fix button upload - due to adding preventDefault on buttons
[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                 "Roo.bootstrap",
705                 "Roo.bootstrap.dash");
706 /*
707  * Based on:
708  * Ext JS Library 1.1.1
709  * Copyright(c) 2006-2007, Ext JS, LLC.
710  *
711  * Originally Released Under LGPL - original licence link has changed is not relivant.
712  *
713  * Fork - LGPL
714  * <script type="text/javascript">
715  */
716
717 (function() {    
718     // wrappedn so fnCleanup is not in global scope...
719     if(Roo.isIE) {
720         function fnCleanUp() {
721             var p = Function.prototype;
722             delete p.createSequence;
723             delete p.defer;
724             delete p.createDelegate;
725             delete p.createCallback;
726             delete p.createInterceptor;
727
728             window.detachEvent("onunload", fnCleanUp);
729         }
730         window.attachEvent("onunload", fnCleanUp);
731     }
732 })();
733
734
735 /**
736  * @class Function
737  * These functions are available on every Function object (any JavaScript function).
738  */
739 Roo.apply(Function.prototype, {
740      /**
741      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
742      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
743      * Will create a function that is bound to those 2 args.
744      * @return {Function} The new function
745     */
746     createCallback : function(/*args...*/){
747         // make args available, in function below
748         var args = arguments;
749         var method = this;
750         return function() {
751             return method.apply(window, args);
752         };
753     },
754
755     /**
756      * Creates a delegate (callback) that sets the scope to obj.
757      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
758      * Will create a function that is automatically scoped to this.
759      * @param {Object} obj (optional) The object for which the scope is set
760      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762      *                                             if a number the args are inserted at the specified position
763      * @return {Function} The new function
764      */
765     createDelegate : function(obj, args, appendArgs){
766         var method = this;
767         return function() {
768             var callArgs = args || arguments;
769             if(appendArgs === true){
770                 callArgs = Array.prototype.slice.call(arguments, 0);
771                 callArgs = callArgs.concat(args);
772             }else if(typeof appendArgs == "number"){
773                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
774                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
775                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
776             }
777             return method.apply(obj || window, callArgs);
778         };
779     },
780
781     /**
782      * Calls this function after the number of millseconds specified.
783      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
784      * @param {Object} obj (optional) The object for which the scope is set
785      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
786      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
787      *                                             if a number the args are inserted at the specified position
788      * @return {Number} The timeout id that can be used with clearTimeout
789      */
790     defer : function(millis, obj, args, appendArgs){
791         var fn = this.createDelegate(obj, args, appendArgs);
792         if(millis){
793             return setTimeout(fn, millis);
794         }
795         fn();
796         return 0;
797     },
798     /**
799      * Create a combined function call sequence of the original function + the passed function.
800      * The resulting function returns the results of the original function.
801      * The passed fcn is called with the parameters of the original function
802      * @param {Function} fcn The function to sequence
803      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
804      * @return {Function} The new function
805      */
806     createSequence : function(fcn, scope){
807         if(typeof fcn != "function"){
808             return this;
809         }
810         var method = this;
811         return function() {
812             var retval = method.apply(this || window, arguments);
813             fcn.apply(scope || this || window, arguments);
814             return retval;
815         };
816     },
817
818     /**
819      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
820      * The resulting function returns the results of the original function.
821      * The passed fcn is called with the parameters of the original function.
822      * @addon
823      * @param {Function} fcn The function to call before the original
824      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
825      * @return {Function} The new function
826      */
827     createInterceptor : function(fcn, scope){
828         if(typeof fcn != "function"){
829             return this;
830         }
831         var method = this;
832         return function() {
833             fcn.target = this;
834             fcn.method = method;
835             if(fcn.apply(scope || this || window, arguments) === false){
836                 return;
837             }
838             return method.apply(this || window, arguments);
839         };
840     }
841 });
842 /*
843  * Based on:
844  * Ext JS Library 1.1.1
845  * Copyright(c) 2006-2007, Ext JS, LLC.
846  *
847  * Originally Released Under LGPL - original licence link has changed is not relivant.
848  *
849  * Fork - LGPL
850  * <script type="text/javascript">
851  */
852
853 Roo.applyIf(String, {
854     
855     /** @scope String */
856     
857     /**
858      * Escapes the passed string for ' and \
859      * @param {String} string The string to escape
860      * @return {String} The escaped string
861      * @static
862      */
863     escape : function(string) {
864         return string.replace(/('|\\)/g, "\\$1");
865     },
866
867     /**
868      * Pads the left side of a string with a specified character.  This is especially useful
869      * for normalizing number and date strings.  Example usage:
870      * <pre><code>
871 var s = String.leftPad('123', 5, '0');
872 // s now contains the string: '00123'
873 </code></pre>
874      * @param {String} string The original string
875      * @param {Number} size The total length of the output string
876      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
877      * @return {String} The padded string
878      * @static
879      */
880     leftPad : function (val, size, ch) {
881         var result = new String(val);
882         if(ch === null || ch === undefined || ch === '') {
883             ch = " ";
884         }
885         while (result.length < size) {
886             result = ch + result;
887         }
888         return result;
889     },
890
891     /**
892      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
893      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
894      * <pre><code>
895 var cls = 'my-class', text = 'Some text';
896 var s = String.format('<div class="{0}">{1}</div>', cls, text);
897 // s now contains the string: '<div class="my-class">Some text</div>'
898 </code></pre>
899      * @param {String} string The tokenized string to be formatted
900      * @param {String} value1 The value to replace token {0}
901      * @param {String} value2 Etc...
902      * @return {String} The formatted string
903      * @static
904      */
905     format : function(format){
906         var args = Array.prototype.slice.call(arguments, 1);
907         return format.replace(/\{(\d+)\}/g, function(m, i){
908             return Roo.util.Format.htmlEncode(args[i]);
909         });
910     }
911   
912     
913 });
914
915 /**
916  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
917  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
918  * they are already different, the first value passed in is returned.  Note that this method returns the new value
919  * but does not change the current string.
920  * <pre><code>
921 // alternate sort directions
922 sort = sort.toggle('ASC', 'DESC');
923
924 // instead of conditional logic:
925 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
926 </code></pre>
927  * @param {String} value The value to compare to the current string
928  * @param {String} other The new value to use if the string already equals the first value passed in
929  * @return {String} The new value
930  */
931  
932 String.prototype.toggle = function(value, other){
933     return this == value ? other : value;
934 };
935
936
937 /**
938   * Remove invalid unicode characters from a string 
939   *
940   * @return {String} The clean string
941   */
942 String.prototype.unicodeClean = function () {
943     return this.replace(/[\s\S]/g,
944         function(character) {
945             if (character.charCodeAt()< 256) {
946               return character;
947            }
948            try {
949                 encodeURIComponent(character);
950            } catch(e) { 
951               return '';
952            }
953            return character;
954         }
955     );
956 };
957   
958 /*
959  * Based on:
960  * Ext JS Library 1.1.1
961  * Copyright(c) 2006-2007, Ext JS, LLC.
962  *
963  * Originally Released Under LGPL - original licence link has changed is not relivant.
964  *
965  * Fork - LGPL
966  * <script type="text/javascript">
967  */
968
969  /**
970  * @class Number
971  */
972 Roo.applyIf(Number.prototype, {
973     /**
974      * Checks whether or not the current number is within a desired range.  If the number is already within the
975      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
976      * exceeded.  Note that this method returns the constrained value but does not change the current number.
977      * @param {Number} min The minimum number in the range
978      * @param {Number} max The maximum number in the range
979      * @return {Number} The constrained value if outside the range, otherwise the current value
980      */
981     constrain : function(min, max){
982         return Math.min(Math.max(this, min), max);
983     }
984 });/*
985  * Based on:
986  * Ext JS Library 1.1.1
987  * Copyright(c) 2006-2007, Ext JS, LLC.
988  *
989  * Originally Released Under LGPL - original licence link has changed is not relivant.
990  *
991  * Fork - LGPL
992  * <script type="text/javascript">
993  */
994  /**
995  * @class Array
996  */
997 Roo.applyIf(Array.prototype, {
998     /**
999      * 
1000      * Checks whether or not the specified object exists in the array.
1001      * @param {Object} o The object to check for
1002      * @return {Number} The index of o in the array (or -1 if it is not found)
1003      */
1004     indexOf : function(o){
1005        for (var i = 0, len = this.length; i < len; i++){
1006               if(this[i] == o) { return i; }
1007        }
1008            return -1;
1009     },
1010
1011     /**
1012      * Removes the specified object from the array.  If the object is not found nothing happens.
1013      * @param {Object} o The object to remove
1014      */
1015     remove : function(o){
1016        var index = this.indexOf(o);
1017        if(index != -1){
1018            this.splice(index, 1);
1019        }
1020     },
1021     /**
1022      * Map (JS 1.6 compatibility)
1023      * @param {Function} function  to call
1024      */
1025     map : function(fun )
1026     {
1027         var len = this.length >>> 0;
1028         if (typeof fun != "function") {
1029             throw new TypeError();
1030         }
1031         var res = new Array(len);
1032         var thisp = arguments[1];
1033         for (var i = 0; i < len; i++)
1034         {
1035             if (i in this) {
1036                 res[i] = fun.call(thisp, this[i], i, this);
1037             }
1038         }
1039
1040         return res;
1041     },
1042     /**
1043      * equals
1044      * @param {Array} o The array to compare to
1045      * @returns {Boolean} true if the same
1046      */
1047     equals : function(b)
1048     {
1049         // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1050         if (this === b) {
1051             return true;
1052          }
1053         if (b == null) {
1054             return false;
1055         }
1056         if (this.length !== b.length) {
1057             return false;
1058         }
1059       
1060         // sort?? a.sort().equals(b.sort());
1061       
1062         for (var i = 0; i < this.length; ++i) {
1063             if (this[i] !== b[i]) {
1064                 return false;
1065             }
1066         }
1067         return true;
1068     }
1069 });
1070
1071
1072  
1073 /*
1074  * Based on:
1075  * Ext JS Library 1.1.1
1076  * Copyright(c) 2006-2007, Ext JS, LLC.
1077  *
1078  * Originally Released Under LGPL - original licence link has changed is not relivant.
1079  *
1080  * Fork - LGPL
1081  * <script type="text/javascript">
1082  */
1083
1084 /**
1085  * @class Date
1086  *
1087  * The date parsing and format syntax is a subset of
1088  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1089  * supported will provide results equivalent to their PHP versions.
1090  *
1091  * Following is the list of all currently supported formats:
1092  *<pre>
1093 Sample date:
1094 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1095
1096 Format  Output      Description
1097 ------  ----------  --------------------------------------------------------------
1098   d      10         Day of the month, 2 digits with leading zeros
1099   D      Wed        A textual representation of a day, three letters
1100   j      10         Day of the month without leading zeros
1101   l      Wednesday  A full textual representation of the day of the week
1102   S      th         English ordinal day of month suffix, 2 chars (use with j)
1103   w      3          Numeric representation of the day of the week
1104   z      9          The julian date, or day of the year (0-365)
1105   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1106   F      January    A full textual representation of the month
1107   m      01         Numeric representation of a month, with leading zeros
1108   M      Jan        Month name abbreviation, three letters
1109   n      1          Numeric representation of a month, without leading zeros
1110   t      31         Number of days in the given month
1111   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1112   Y      2007       A full numeric representation of a year, 4 digits
1113   y      07         A two digit representation of a year
1114   a      pm         Lowercase Ante meridiem and Post meridiem
1115   A      PM         Uppercase Ante meridiem and Post meridiem
1116   g      3          12-hour format of an hour without leading zeros
1117   G      15         24-hour format of an hour without leading zeros
1118   h      03         12-hour format of an hour with leading zeros
1119   H      15         24-hour format of an hour with leading zeros
1120   i      05         Minutes with leading zeros
1121   s      01         Seconds, with leading zeros
1122   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1123   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1124   T      CST        Timezone setting of the machine running the code
1125   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1126 </pre>
1127  *
1128  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1129  * <pre><code>
1130 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1131 document.write(dt.format('Y-m-d'));                         //2007-01-10
1132 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1133 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
1134  </code></pre>
1135  *
1136  * Here are some standard date/time patterns that you might find helpful.  They
1137  * are not part of the source of Date.js, but to use them you can simply copy this
1138  * block of code into any script that is included after Date.js and they will also become
1139  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1140  * <pre><code>
1141 Date.patterns = {
1142     ISO8601Long:"Y-m-d H:i:s",
1143     ISO8601Short:"Y-m-d",
1144     ShortDate: "n/j/Y",
1145     LongDate: "l, F d, Y",
1146     FullDateTime: "l, F d, Y g:i:s A",
1147     MonthDay: "F d",
1148     ShortTime: "g:i A",
1149     LongTime: "g:i:s A",
1150     SortableDateTime: "Y-m-d\\TH:i:s",
1151     UniversalSortableDateTime: "Y-m-d H:i:sO",
1152     YearMonth: "F, Y"
1153 };
1154 </code></pre>
1155  *
1156  * Example usage:
1157  * <pre><code>
1158 var dt = new Date();
1159 document.write(dt.format(Date.patterns.ShortDate));
1160  </code></pre>
1161  */
1162
1163 /*
1164  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1165  * They generate precompiled functions from date formats instead of parsing and
1166  * processing the pattern every time you format a date.  These functions are available
1167  * on every Date object (any javascript function).
1168  *
1169  * The original article and download are here:
1170  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1171  *
1172  */
1173  
1174  
1175  // was in core
1176 /**
1177  Returns the number of milliseconds between this date and date
1178  @param {Date} date (optional) Defaults to now
1179  @return {Number} The diff in milliseconds
1180  @member Date getElapsed
1181  */
1182 Date.prototype.getElapsed = function(date) {
1183         return Math.abs((date || new Date()).getTime()-this.getTime());
1184 };
1185 // was in date file..
1186
1187
1188 // private
1189 Date.parseFunctions = {count:0};
1190 // private
1191 Date.parseRegexes = [];
1192 // private
1193 Date.formatFunctions = {count:0};
1194
1195 // private
1196 Date.prototype.dateFormat = function(format) {
1197     if (Date.formatFunctions[format] == null) {
1198         Date.createNewFormat(format);
1199     }
1200     var func = Date.formatFunctions[format];
1201     return this[func]();
1202 };
1203
1204
1205 /**
1206  * Formats a date given the supplied format string
1207  * @param {String} format The format string
1208  * @return {String} The formatted date
1209  * @method
1210  */
1211 Date.prototype.format = Date.prototype.dateFormat;
1212
1213 // private
1214 Date.createNewFormat = function(format) {
1215     var funcName = "format" + Date.formatFunctions.count++;
1216     Date.formatFunctions[format] = funcName;
1217     var code = "Date.prototype." + funcName + " = function(){return ";
1218     var special = false;
1219     var ch = '';
1220     for (var i = 0; i < format.length; ++i) {
1221         ch = format.charAt(i);
1222         if (!special && ch == "\\") {
1223             special = true;
1224         }
1225         else if (special) {
1226             special = false;
1227             code += "'" + String.escape(ch) + "' + ";
1228         }
1229         else {
1230             code += Date.getFormatCode(ch);
1231         }
1232     }
1233     /** eval:var:zzzzzzzzzzzzz */
1234     eval(code.substring(0, code.length - 3) + ";}");
1235 };
1236
1237 // private
1238 Date.getFormatCode = function(character) {
1239     switch (character) {
1240     case "d":
1241         return "String.leftPad(this.getDate(), 2, '0') + ";
1242     case "D":
1243         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1244     case "j":
1245         return "this.getDate() + ";
1246     case "l":
1247         return "Date.dayNames[this.getDay()] + ";
1248     case "S":
1249         return "this.getSuffix() + ";
1250     case "w":
1251         return "this.getDay() + ";
1252     case "z":
1253         return "this.getDayOfYear() + ";
1254     case "W":
1255         return "this.getWeekOfYear() + ";
1256     case "F":
1257         return "Date.monthNames[this.getMonth()] + ";
1258     case "m":
1259         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1260     case "M":
1261         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1262     case "n":
1263         return "(this.getMonth() + 1) + ";
1264     case "t":
1265         return "this.getDaysInMonth() + ";
1266     case "L":
1267         return "(this.isLeapYear() ? 1 : 0) + ";
1268     case "Y":
1269         return "this.getFullYear() + ";
1270     case "y":
1271         return "('' + this.getFullYear()).substring(2, 4) + ";
1272     case "a":
1273         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1274     case "A":
1275         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1276     case "g":
1277         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1278     case "G":
1279         return "this.getHours() + ";
1280     case "h":
1281         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1282     case "H":
1283         return "String.leftPad(this.getHours(), 2, '0') + ";
1284     case "i":
1285         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1286     case "s":
1287         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1288     case "O":
1289         return "this.getGMTOffset() + ";
1290     case "P":
1291         return "this.getGMTColonOffset() + ";
1292     case "T":
1293         return "this.getTimezone() + ";
1294     case "Z":
1295         return "(this.getTimezoneOffset() * -60) + ";
1296     default:
1297         return "'" + String.escape(character) + "' + ";
1298     }
1299 };
1300
1301 /**
1302  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1303  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1304  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1305  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1306  * string or the parse operation will fail.
1307  * Example Usage:
1308 <pre><code>
1309 //dt = Fri May 25 2007 (current date)
1310 var dt = new Date();
1311
1312 //dt = Thu May 25 2006 (today's month/day in 2006)
1313 dt = Date.parseDate("2006", "Y");
1314
1315 //dt = Sun Jan 15 2006 (all date parts specified)
1316 dt = Date.parseDate("2006-1-15", "Y-m-d");
1317
1318 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1319 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1320 </code></pre>
1321  * @param {String} input The unparsed date as a string
1322  * @param {String} format The format the date is in
1323  * @return {Date} The parsed date
1324  * @static
1325  */
1326 Date.parseDate = function(input, format) {
1327     if (Date.parseFunctions[format] == null) {
1328         Date.createParser(format);
1329     }
1330     var func = Date.parseFunctions[format];
1331     return Date[func](input);
1332 };
1333 /**
1334  * @private
1335  */
1336
1337 Date.createParser = function(format) {
1338     var funcName = "parse" + Date.parseFunctions.count++;
1339     var regexNum = Date.parseRegexes.length;
1340     var currentGroup = 1;
1341     Date.parseFunctions[format] = funcName;
1342
1343     var code = "Date." + funcName + " = function(input){\n"
1344         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1345         + "var d = new Date();\n"
1346         + "y = d.getFullYear();\n"
1347         + "m = d.getMonth();\n"
1348         + "d = d.getDate();\n"
1349         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1350         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1351         + "if (results && results.length > 0) {";
1352     var regex = "";
1353
1354     var special = false;
1355     var ch = '';
1356     for (var i = 0; i < format.length; ++i) {
1357         ch = format.charAt(i);
1358         if (!special && ch == "\\") {
1359             special = true;
1360         }
1361         else if (special) {
1362             special = false;
1363             regex += String.escape(ch);
1364         }
1365         else {
1366             var obj = Date.formatCodeToRegex(ch, currentGroup);
1367             currentGroup += obj.g;
1368             regex += obj.s;
1369             if (obj.g && obj.c) {
1370                 code += obj.c;
1371             }
1372         }
1373     }
1374
1375     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1376         + "{v = new Date(y, m, d, h, i, s);}\n"
1377         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1378         + "{v = new Date(y, m, d, h, i);}\n"
1379         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1380         + "{v = new Date(y, m, d, h);}\n"
1381         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1382         + "{v = new Date(y, m, d);}\n"
1383         + "else if (y >= 0 && m >= 0)\n"
1384         + "{v = new Date(y, m);}\n"
1385         + "else if (y >= 0)\n"
1386         + "{v = new Date(y);}\n"
1387         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1388         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1389         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1390         + ";}";
1391
1392     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1393     /** eval:var:zzzzzzzzzzzzz */
1394     eval(code);
1395 };
1396
1397 // private
1398 Date.formatCodeToRegex = function(character, currentGroup) {
1399     switch (character) {
1400     case "D":
1401         return {g:0,
1402         c:null,
1403         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1404     case "j":
1405         return {g:1,
1406             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1407             s:"(\\d{1,2})"}; // day of month without leading zeroes
1408     case "d":
1409         return {g:1,
1410             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1411             s:"(\\d{2})"}; // day of month with leading zeroes
1412     case "l":
1413         return {g:0,
1414             c:null,
1415             s:"(?:" + Date.dayNames.join("|") + ")"};
1416     case "S":
1417         return {g:0,
1418             c:null,
1419             s:"(?:st|nd|rd|th)"};
1420     case "w":
1421         return {g:0,
1422             c:null,
1423             s:"\\d"};
1424     case "z":
1425         return {g:0,
1426             c:null,
1427             s:"(?:\\d{1,3})"};
1428     case "W":
1429         return {g:0,
1430             c:null,
1431             s:"(?:\\d{2})"};
1432     case "F":
1433         return {g:1,
1434             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1435             s:"(" + Date.monthNames.join("|") + ")"};
1436     case "M":
1437         return {g:1,
1438             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1439             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1440     case "n":
1441         return {g:1,
1442             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1443             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1444     case "m":
1445         return {g:1,
1446             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1447             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1448     case "t":
1449         return {g:0,
1450             c:null,
1451             s:"\\d{1,2}"};
1452     case "L":
1453         return {g:0,
1454             c:null,
1455             s:"(?:1|0)"};
1456     case "Y":
1457         return {g:1,
1458             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1459             s:"(\\d{4})"};
1460     case "y":
1461         return {g:1,
1462             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1463                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1464             s:"(\\d{1,2})"};
1465     case "a":
1466         return {g:1,
1467             c:"if (results[" + currentGroup + "] == 'am') {\n"
1468                 + "if (h == 12) { h = 0; }\n"
1469                 + "} else { if (h < 12) { h += 12; }}",
1470             s:"(am|pm)"};
1471     case "A":
1472         return {g:1,
1473             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1474                 + "if (h == 12) { h = 0; }\n"
1475                 + "} else { if (h < 12) { h += 12; }}",
1476             s:"(AM|PM)"};
1477     case "g":
1478     case "G":
1479         return {g:1,
1480             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1481             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1482     case "h":
1483     case "H":
1484         return {g:1,
1485             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1486             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1487     case "i":
1488         return {g:1,
1489             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1490             s:"(\\d{2})"};
1491     case "s":
1492         return {g:1,
1493             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1494             s:"(\\d{2})"};
1495     case "O":
1496         return {g:1,
1497             c:[
1498                 "o = results[", currentGroup, "];\n",
1499                 "var sn = o.substring(0,1);\n", // get + / - sign
1500                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1501                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1502                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1503                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1504             ].join(""),
1505             s:"([+\-]\\d{2,4})"};
1506     
1507     
1508     case "P":
1509         return {g:1,
1510                 c:[
1511                    "o = results[", currentGroup, "];\n",
1512                    "var sn = o.substring(0,1);\n",
1513                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1514                    "var mn = o.substring(4,6) % 60;\n",
1515                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1516                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1517             ].join(""),
1518             s:"([+\-]\\d{4})"};
1519     case "T":
1520         return {g:0,
1521             c:null,
1522             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1523     case "Z":
1524         return {g:1,
1525             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1526                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1527             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1528     default:
1529         return {g:0,
1530             c:null,
1531             s:String.escape(character)};
1532     }
1533 };
1534
1535 /**
1536  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1537  * @return {String} The abbreviated timezone name (e.g. 'CST')
1538  */
1539 Date.prototype.getTimezone = function() {
1540     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1541 };
1542
1543 /**
1544  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1545  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1546  */
1547 Date.prototype.getGMTOffset = function() {
1548     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1549         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1550         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1551 };
1552
1553 /**
1554  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1555  * @return {String} 2-characters representing hours and 2-characters representing minutes
1556  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1557  */
1558 Date.prototype.getGMTColonOffset = function() {
1559         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1560                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1561                 + ":"
1562                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1563 }
1564
1565 /**
1566  * Get the numeric day number of the year, adjusted for leap year.
1567  * @return {Number} 0 through 364 (365 in leap years)
1568  */
1569 Date.prototype.getDayOfYear = function() {
1570     var num = 0;
1571     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1572     for (var i = 0; i < this.getMonth(); ++i) {
1573         num += Date.daysInMonth[i];
1574     }
1575     return num + this.getDate() - 1;
1576 };
1577
1578 /**
1579  * Get the string representation of the numeric week number of the year
1580  * (equivalent to the format specifier 'W').
1581  * @return {String} '00' through '52'
1582  */
1583 Date.prototype.getWeekOfYear = function() {
1584     // Skip to Thursday of this week
1585     var now = this.getDayOfYear() + (4 - this.getDay());
1586     // Find the first Thursday of the year
1587     var jan1 = new Date(this.getFullYear(), 0, 1);
1588     var then = (7 - jan1.getDay() + 4);
1589     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1590 };
1591
1592 /**
1593  * Whether or not the current date is in a leap year.
1594  * @return {Boolean} True if the current date is in a leap year, else false
1595  */
1596 Date.prototype.isLeapYear = function() {
1597     var year = this.getFullYear();
1598     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1599 };
1600
1601 /**
1602  * Get the first day of the current month, adjusted for leap year.  The returned value
1603  * is the numeric day index within the week (0-6) which can be used in conjunction with
1604  * the {@link #monthNames} array to retrieve the textual day name.
1605  * Example:
1606  *<pre><code>
1607 var dt = new Date('1/10/2007');
1608 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1609 </code></pre>
1610  * @return {Number} The day number (0-6)
1611  */
1612 Date.prototype.getFirstDayOfMonth = function() {
1613     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1614     return (day < 0) ? (day + 7) : day;
1615 };
1616
1617 /**
1618  * Get the last day of the current month, adjusted for leap year.  The returned value
1619  * is the numeric day index within the week (0-6) which can be used in conjunction with
1620  * the {@link #monthNames} array to retrieve the textual day name.
1621  * Example:
1622  *<pre><code>
1623 var dt = new Date('1/10/2007');
1624 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1625 </code></pre>
1626  * @return {Number} The day number (0-6)
1627  */
1628 Date.prototype.getLastDayOfMonth = function() {
1629     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1630     return (day < 0) ? (day + 7) : day;
1631 };
1632
1633
1634 /**
1635  * Get the first date of this date's month
1636  * @return {Date}
1637  */
1638 Date.prototype.getFirstDateOfMonth = function() {
1639     return new Date(this.getFullYear(), this.getMonth(), 1);
1640 };
1641
1642 /**
1643  * Get the last date of this date's month
1644  * @return {Date}
1645  */
1646 Date.prototype.getLastDateOfMonth = function() {
1647     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1648 };
1649 /**
1650  * Get the number of days in the current month, adjusted for leap year.
1651  * @return {Number} The number of days in the month
1652  */
1653 Date.prototype.getDaysInMonth = function() {
1654     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1655     return Date.daysInMonth[this.getMonth()];
1656 };
1657
1658 /**
1659  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1660  * @return {String} 'st, 'nd', 'rd' or 'th'
1661  */
1662 Date.prototype.getSuffix = function() {
1663     switch (this.getDate()) {
1664         case 1:
1665         case 21:
1666         case 31:
1667             return "st";
1668         case 2:
1669         case 22:
1670             return "nd";
1671         case 3:
1672         case 23:
1673             return "rd";
1674         default:
1675             return "th";
1676     }
1677 };
1678
1679 // private
1680 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1681
1682 /**
1683  * An array of textual month names.
1684  * Override these values for international dates, for example...
1685  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1686  * @type Array
1687  * @static
1688  */
1689 Date.monthNames =
1690    ["January",
1691     "February",
1692     "March",
1693     "April",
1694     "May",
1695     "June",
1696     "July",
1697     "August",
1698     "September",
1699     "October",
1700     "November",
1701     "December"];
1702
1703 /**
1704  * An array of textual day names.
1705  * Override these values for international dates, for example...
1706  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1707  * @type Array
1708  * @static
1709  */
1710 Date.dayNames =
1711    ["Sunday",
1712     "Monday",
1713     "Tuesday",
1714     "Wednesday",
1715     "Thursday",
1716     "Friday",
1717     "Saturday"];
1718
1719 // private
1720 Date.y2kYear = 50;
1721 // private
1722 Date.monthNumbers = {
1723     Jan:0,
1724     Feb:1,
1725     Mar:2,
1726     Apr:3,
1727     May:4,
1728     Jun:5,
1729     Jul:6,
1730     Aug:7,
1731     Sep:8,
1732     Oct:9,
1733     Nov:10,
1734     Dec:11};
1735
1736 /**
1737  * Creates and returns a new Date instance with the exact same date value as the called instance.
1738  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1739  * variable will also be changed.  When the intention is to create a new variable that will not
1740  * modify the original instance, you should create a clone.
1741  *
1742  * Example of correctly cloning a date:
1743  * <pre><code>
1744 //wrong way:
1745 var orig = new Date('10/1/2006');
1746 var copy = orig;
1747 copy.setDate(5);
1748 document.write(orig);  //returns 'Thu Oct 05 2006'!
1749
1750 //correct way:
1751 var orig = new Date('10/1/2006');
1752 var copy = orig.clone();
1753 copy.setDate(5);
1754 document.write(orig);  //returns 'Thu Oct 01 2006'
1755 </code></pre>
1756  * @return {Date} The new Date instance
1757  */
1758 Date.prototype.clone = function() {
1759         return new Date(this.getTime());
1760 };
1761
1762 /**
1763  * Clears any time information from this date
1764  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1765  @return {Date} this or the clone
1766  */
1767 Date.prototype.clearTime = function(clone){
1768     if(clone){
1769         return this.clone().clearTime();
1770     }
1771     this.setHours(0);
1772     this.setMinutes(0);
1773     this.setSeconds(0);
1774     this.setMilliseconds(0);
1775     return this;
1776 };
1777
1778 // private
1779 // safari setMonth is broken -- check that this is only donw once...
1780 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1781     Date.brokenSetMonth = Date.prototype.setMonth;
1782         Date.prototype.setMonth = function(num){
1783                 if(num <= -1){
1784                         var n = Math.ceil(-num);
1785                         var back_year = Math.ceil(n/12);
1786                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1787                         this.setFullYear(this.getFullYear() - back_year);
1788                         return Date.brokenSetMonth.call(this, month);
1789                 } else {
1790                         return Date.brokenSetMonth.apply(this, arguments);
1791                 }
1792         };
1793 }
1794
1795 /** Date interval constant 
1796 * @static 
1797 * @type String */
1798 Date.MILLI = "ms";
1799 /** Date interval constant 
1800 * @static 
1801 * @type String */
1802 Date.SECOND = "s";
1803 /** Date interval constant 
1804 * @static 
1805 * @type String */
1806 Date.MINUTE = "mi";
1807 /** Date interval constant 
1808 * @static 
1809 * @type String */
1810 Date.HOUR = "h";
1811 /** Date interval constant 
1812 * @static 
1813 * @type String */
1814 Date.DAY = "d";
1815 /** Date interval constant 
1816 * @static 
1817 * @type String */
1818 Date.MONTH = "mo";
1819 /** Date interval constant 
1820 * @static 
1821 * @type String */
1822 Date.YEAR = "y";
1823
1824 /**
1825  * Provides a convenient method of performing basic date arithmetic.  This method
1826  * does not modify the Date instance being called - it creates and returns
1827  * a new Date instance containing the resulting date value.
1828  *
1829  * Examples:
1830  * <pre><code>
1831 //Basic usage:
1832 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1833 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1834
1835 //Negative values will subtract correctly:
1836 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1837 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1838
1839 //You can even chain several calls together in one line!
1840 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1841 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1842  </code></pre>
1843  *
1844  * @param {String} interval   A valid date interval enum value
1845  * @param {Number} value      The amount to add to the current date
1846  * @return {Date} The new Date instance
1847  */
1848 Date.prototype.add = function(interval, value){
1849   var d = this.clone();
1850   if (!interval || value === 0) { return d; }
1851   switch(interval.toLowerCase()){
1852     case Date.MILLI:
1853       d.setMilliseconds(this.getMilliseconds() + value);
1854       break;
1855     case Date.SECOND:
1856       d.setSeconds(this.getSeconds() + value);
1857       break;
1858     case Date.MINUTE:
1859       d.setMinutes(this.getMinutes() + value);
1860       break;
1861     case Date.HOUR:
1862       d.setHours(this.getHours() + value);
1863       break;
1864     case Date.DAY:
1865       d.setDate(this.getDate() + value);
1866       break;
1867     case Date.MONTH:
1868       var day = this.getDate();
1869       if(day > 28){
1870           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1871       }
1872       d.setDate(day);
1873       d.setMonth(this.getMonth() + value);
1874       break;
1875     case Date.YEAR:
1876       d.setFullYear(this.getFullYear() + value);
1877       break;
1878   }
1879   return d;
1880 };
1881 /**
1882  * @class Roo.lib.Dom
1883  * @licence LGPL
1884  * @static
1885  * 
1886  * Dom utils (from YIU afaik)
1887  *
1888  * 
1889  **/
1890 Roo.lib.Dom = {
1891     /**
1892      * Get the view width
1893      * @param {Boolean} full True will get the full document, otherwise it's the view width
1894      * @return {Number} The width
1895      */
1896      
1897     getViewWidth : function(full) {
1898         return full ? this.getDocumentWidth() : this.getViewportWidth();
1899     },
1900     /**
1901      * Get the view height
1902      * @param {Boolean} full True will get the full document, otherwise it's the view height
1903      * @return {Number} The height
1904      */
1905     getViewHeight : function(full) {
1906         return full ? this.getDocumentHeight() : this.getViewportHeight();
1907     },
1908     /**
1909      * Get the Full Document height 
1910      * @return {Number} The height
1911      */
1912     getDocumentHeight: function() {
1913         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1914         return Math.max(scrollHeight, this.getViewportHeight());
1915     },
1916     /**
1917      * Get the Full Document width
1918      * @return {Number} The width
1919      */
1920     getDocumentWidth: function() {
1921         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1922         return Math.max(scrollWidth, this.getViewportWidth());
1923     },
1924     /**
1925      * Get the Window Viewport height
1926      * @return {Number} The height
1927      */
1928     getViewportHeight: function() {
1929         var height = self.innerHeight;
1930         var mode = document.compatMode;
1931
1932         if ((mode || Roo.isIE) && !Roo.isOpera) {
1933             height = (mode == "CSS1Compat") ?
1934                      document.documentElement.clientHeight :
1935                      document.body.clientHeight;
1936         }
1937
1938         return height;
1939     },
1940     /**
1941      * Get the Window Viewport width
1942      * @return {Number} The width
1943      */
1944     getViewportWidth: function() {
1945         var width = self.innerWidth;
1946         var mode = document.compatMode;
1947
1948         if (mode || Roo.isIE) {
1949             width = (mode == "CSS1Compat") ?
1950                     document.documentElement.clientWidth :
1951                     document.body.clientWidth;
1952         }
1953         return width;
1954     },
1955
1956     isAncestor : function(p, c) {
1957         p = Roo.getDom(p);
1958         c = Roo.getDom(c);
1959         if (!p || !c) {
1960             return false;
1961         }
1962
1963         if (p.contains && !Roo.isSafari) {
1964             return p.contains(c);
1965         } else if (p.compareDocumentPosition) {
1966             return !!(p.compareDocumentPosition(c) & 16);
1967         } else {
1968             var parent = c.parentNode;
1969             while (parent) {
1970                 if (parent == p) {
1971                     return true;
1972                 }
1973                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1974                     return false;
1975                 }
1976                 parent = parent.parentNode;
1977             }
1978             return false;
1979         }
1980     },
1981
1982     getRegion : function(el) {
1983         return Roo.lib.Region.getRegion(el);
1984     },
1985
1986     getY : function(el) {
1987         return this.getXY(el)[1];
1988     },
1989
1990     getX : function(el) {
1991         return this.getXY(el)[0];
1992     },
1993
1994     getXY : function(el) {
1995         var p, pe, b, scroll, bd = document.body;
1996         el = Roo.getDom(el);
1997         var fly = Roo.lib.AnimBase.fly;
1998         if (el.getBoundingClientRect) {
1999             b = el.getBoundingClientRect();
2000             scroll = fly(document).getScroll();
2001             return [b.left + scroll.left, b.top + scroll.top];
2002         }
2003         var x = 0, y = 0;
2004
2005         p = el;
2006
2007         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2008
2009         while (p) {
2010
2011             x += p.offsetLeft;
2012             y += p.offsetTop;
2013
2014             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2015                 hasAbsolute = true;
2016             }
2017
2018             if (Roo.isGecko) {
2019                 pe = fly(p);
2020
2021                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2022                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2023
2024
2025                 x += bl;
2026                 y += bt;
2027
2028
2029                 if (p != el && pe.getStyle('overflow') != 'visible') {
2030                     x += bl;
2031                     y += bt;
2032                 }
2033             }
2034             p = p.offsetParent;
2035         }
2036
2037         if (Roo.isSafari && hasAbsolute) {
2038             x -= bd.offsetLeft;
2039             y -= bd.offsetTop;
2040         }
2041
2042         if (Roo.isGecko && !hasAbsolute) {
2043             var dbd = fly(bd);
2044             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2045             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2046         }
2047
2048         p = el.parentNode;
2049         while (p && p != bd) {
2050             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2051                 x -= p.scrollLeft;
2052                 y -= p.scrollTop;
2053             }
2054             p = p.parentNode;
2055         }
2056         return [x, y];
2057     },
2058  
2059   
2060
2061
2062     setXY : function(el, xy) {
2063         el = Roo.fly(el, '_setXY');
2064         el.position();
2065         var pts = el.translatePoints(xy);
2066         if (xy[0] !== false) {
2067             el.dom.style.left = pts.left + "px";
2068         }
2069         if (xy[1] !== false) {
2070             el.dom.style.top = pts.top + "px";
2071         }
2072     },
2073
2074     setX : function(el, x) {
2075         this.setXY(el, [x, false]);
2076     },
2077
2078     setY : function(el, y) {
2079         this.setXY(el, [false, y]);
2080     }
2081 };
2082 /*
2083  * Portions of this file are based on pieces of Yahoo User Interface Library
2084  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2085  * YUI licensed under the BSD License:
2086  * http://developer.yahoo.net/yui/license.txt
2087  * <script type="text/javascript">
2088  *
2089  */
2090
2091 Roo.lib.Event = function() {
2092     var loadComplete = false;
2093     var listeners = [];
2094     var unloadListeners = [];
2095     var retryCount = 0;
2096     var onAvailStack = [];
2097     var counter = 0;
2098     var lastError = null;
2099
2100     return {
2101         POLL_RETRYS: 200,
2102         POLL_INTERVAL: 20,
2103         EL: 0,
2104         TYPE: 1,
2105         FN: 2,
2106         WFN: 3,
2107         OBJ: 3,
2108         ADJ_SCOPE: 4,
2109         _interval: null,
2110
2111         startInterval: function() {
2112             if (!this._interval) {
2113                 var self = this;
2114                 var callback = function() {
2115                     self._tryPreloadAttach();
2116                 };
2117                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2118
2119             }
2120         },
2121
2122         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2123             onAvailStack.push({ id:         p_id,
2124                 fn:         p_fn,
2125                 obj:        p_obj,
2126                 override:   p_override,
2127                 checkReady: false    });
2128
2129             retryCount = this.POLL_RETRYS;
2130             this.startInterval();
2131         },
2132
2133
2134         addListener: function(el, eventName, fn) {
2135             el = Roo.getDom(el);
2136             if (!el || !fn) {
2137                 return false;
2138             }
2139
2140             if ("unload" == eventName) {
2141                 unloadListeners[unloadListeners.length] =
2142                 [el, eventName, fn];
2143                 return true;
2144             }
2145
2146             var wrappedFn = function(e) {
2147                 return fn(Roo.lib.Event.getEvent(e));
2148             };
2149
2150             var li = [el, eventName, fn, wrappedFn];
2151
2152             var index = listeners.length;
2153             listeners[index] = li;
2154
2155             this.doAdd(el, eventName, wrappedFn, false);
2156             return true;
2157
2158         },
2159
2160
2161         removeListener: function(el, eventName, fn) {
2162             var i, len;
2163
2164             el = Roo.getDom(el);
2165
2166             if(!fn) {
2167                 return this.purgeElement(el, false, eventName);
2168             }
2169
2170
2171             if ("unload" == eventName) {
2172
2173                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2174                     var li = unloadListeners[i];
2175                     if (li &&
2176                         li[0] == el &&
2177                         li[1] == eventName &&
2178                         li[2] == fn) {
2179                         unloadListeners.splice(i, 1);
2180                         return true;
2181                     }
2182                 }
2183
2184                 return false;
2185             }
2186
2187             var cacheItem = null;
2188
2189
2190             var index = arguments[3];
2191
2192             if ("undefined" == typeof index) {
2193                 index = this._getCacheIndex(el, eventName, fn);
2194             }
2195
2196             if (index >= 0) {
2197                 cacheItem = listeners[index];
2198             }
2199
2200             if (!el || !cacheItem) {
2201                 return false;
2202             }
2203
2204             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2205
2206             delete listeners[index][this.WFN];
2207             delete listeners[index][this.FN];
2208             listeners.splice(index, 1);
2209
2210             return true;
2211
2212         },
2213
2214
2215         getTarget: function(ev, resolveTextNode) {
2216             ev = ev.browserEvent || ev;
2217             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2218             var t = ev.target || ev.srcElement;
2219             return this.resolveTextNode(t);
2220         },
2221
2222
2223         resolveTextNode: function(node) {
2224             if (Roo.isSafari && node && 3 == node.nodeType) {
2225                 return node.parentNode;
2226             } else {
2227                 return node;
2228             }
2229         },
2230
2231
2232         getPageX: function(ev) {
2233             ev = ev.browserEvent || ev;
2234             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2235             var x = ev.pageX;
2236             if (!x && 0 !== x) {
2237                 x = ev.clientX || 0;
2238
2239                 if (Roo.isIE) {
2240                     x += this.getScroll()[1];
2241                 }
2242             }
2243
2244             return x;
2245         },
2246
2247
2248         getPageY: function(ev) {
2249             ev = ev.browserEvent || ev;
2250             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2251             var y = ev.pageY;
2252             if (!y && 0 !== y) {
2253                 y = ev.clientY || 0;
2254
2255                 if (Roo.isIE) {
2256                     y += this.getScroll()[0];
2257                 }
2258             }
2259
2260
2261             return y;
2262         },
2263
2264
2265         getXY: function(ev) {
2266             ev = ev.browserEvent || ev;
2267             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2268             return [this.getPageX(ev), this.getPageY(ev)];
2269         },
2270
2271
2272         getRelatedTarget: function(ev) {
2273             ev = ev.browserEvent || ev;
2274             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2275             var t = ev.relatedTarget;
2276             if (!t) {
2277                 if (ev.type == "mouseout") {
2278                     t = ev.toElement;
2279                 } else if (ev.type == "mouseover") {
2280                     t = ev.fromElement;
2281                 }
2282             }
2283
2284             return this.resolveTextNode(t);
2285         },
2286
2287
2288         getTime: function(ev) {
2289             ev = ev.browserEvent || ev;
2290             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2291             if (!ev.time) {
2292                 var t = new Date().getTime();
2293                 try {
2294                     ev.time = t;
2295                 } catch(ex) {
2296                     this.lastError = ex;
2297                     return t;
2298                 }
2299             }
2300
2301             return ev.time;
2302         },
2303
2304
2305         stopEvent: function(ev) {
2306             this.stopPropagation(ev);
2307             this.preventDefault(ev);
2308         },
2309
2310
2311         stopPropagation: function(ev) {
2312             ev = ev.browserEvent || ev;
2313             if (ev.stopPropagation) {
2314                 ev.stopPropagation();
2315             } else {
2316                 ev.cancelBubble = true;
2317             }
2318         },
2319
2320
2321         preventDefault: function(ev) {
2322             ev = ev.browserEvent || ev;
2323             if(ev.preventDefault) {
2324                 ev.preventDefault();
2325             } else {
2326                 ev.returnValue = false;
2327             }
2328         },
2329
2330
2331         getEvent: function(e) {
2332             var ev = e || window.event;
2333             if (!ev) {
2334                 var c = this.getEvent.caller;
2335                 while (c) {
2336                     ev = c.arguments[0];
2337                     if (ev && Event == ev.constructor) {
2338                         break;
2339                     }
2340                     c = c.caller;
2341                 }
2342             }
2343             return ev;
2344         },
2345
2346
2347         getCharCode: function(ev) {
2348             ev = ev.browserEvent || ev;
2349             return ev.charCode || ev.keyCode || 0;
2350         },
2351
2352
2353         _getCacheIndex: function(el, eventName, fn) {
2354             for (var i = 0,len = listeners.length; i < len; ++i) {
2355                 var li = listeners[i];
2356                 if (li &&
2357                     li[this.FN] == fn &&
2358                     li[this.EL] == el &&
2359                     li[this.TYPE] == eventName) {
2360                     return i;
2361                 }
2362             }
2363
2364             return -1;
2365         },
2366
2367
2368         elCache: {},
2369
2370
2371         getEl: function(id) {
2372             return document.getElementById(id);
2373         },
2374
2375
2376         clearCache: function() {
2377         },
2378
2379
2380         _load: function(e) {
2381             loadComplete = true;
2382             var EU = Roo.lib.Event;
2383
2384
2385             if (Roo.isIE) {
2386                 EU.doRemove(window, "load", EU._load);
2387             }
2388         },
2389
2390
2391         _tryPreloadAttach: function() {
2392
2393             if (this.locked) {
2394                 return false;
2395             }
2396
2397             this.locked = true;
2398
2399
2400             var tryAgain = !loadComplete;
2401             if (!tryAgain) {
2402                 tryAgain = (retryCount > 0);
2403             }
2404
2405
2406             var notAvail = [];
2407             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2408                 var item = onAvailStack[i];
2409                 if (item) {
2410                     var el = this.getEl(item.id);
2411
2412                     if (el) {
2413                         if (!item.checkReady ||
2414                             loadComplete ||
2415                             el.nextSibling ||
2416                             (document && document.body)) {
2417
2418                             var scope = el;
2419                             if (item.override) {
2420                                 if (item.override === true) {
2421                                     scope = item.obj;
2422                                 } else {
2423                                     scope = item.override;
2424                                 }
2425                             }
2426                             item.fn.call(scope, item.obj);
2427                             onAvailStack[i] = null;
2428                         }
2429                     } else {
2430                         notAvail.push(item);
2431                     }
2432                 }
2433             }
2434
2435             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2436
2437             if (tryAgain) {
2438
2439                 this.startInterval();
2440             } else {
2441                 clearInterval(this._interval);
2442                 this._interval = null;
2443             }
2444
2445             this.locked = false;
2446
2447             return true;
2448
2449         },
2450
2451
2452         purgeElement: function(el, recurse, eventName) {
2453             var elListeners = this.getListeners(el, eventName);
2454             if (elListeners) {
2455                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2456                     var l = elListeners[i];
2457                     this.removeListener(el, l.type, l.fn);
2458                 }
2459             }
2460
2461             if (recurse && el && el.childNodes) {
2462                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2463                     this.purgeElement(el.childNodes[i], recurse, eventName);
2464                 }
2465             }
2466         },
2467
2468
2469         getListeners: function(el, eventName) {
2470             var results = [], searchLists;
2471             if (!eventName) {
2472                 searchLists = [listeners, unloadListeners];
2473             } else if (eventName == "unload") {
2474                 searchLists = [unloadListeners];
2475             } else {
2476                 searchLists = [listeners];
2477             }
2478
2479             for (var j = 0; j < searchLists.length; ++j) {
2480                 var searchList = searchLists[j];
2481                 if (searchList && searchList.length > 0) {
2482                     for (var i = 0,len = searchList.length; i < len; ++i) {
2483                         var l = searchList[i];
2484                         if (l && l[this.EL] === el &&
2485                             (!eventName || eventName === l[this.TYPE])) {
2486                             results.push({
2487                                 type:   l[this.TYPE],
2488                                 fn:     l[this.FN],
2489                                 obj:    l[this.OBJ],
2490                                 adjust: l[this.ADJ_SCOPE],
2491                                 index:  i
2492                             });
2493                         }
2494                     }
2495                 }
2496             }
2497
2498             return (results.length) ? results : null;
2499         },
2500
2501
2502         _unload: function(e) {
2503
2504             var EU = Roo.lib.Event, i, j, l, len, index;
2505
2506             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2507                 l = unloadListeners[i];
2508                 if (l) {
2509                     var scope = window;
2510                     if (l[EU.ADJ_SCOPE]) {
2511                         if (l[EU.ADJ_SCOPE] === true) {
2512                             scope = l[EU.OBJ];
2513                         } else {
2514                             scope = l[EU.ADJ_SCOPE];
2515                         }
2516                     }
2517                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2518                     unloadListeners[i] = null;
2519                     l = null;
2520                     scope = null;
2521                 }
2522             }
2523
2524             unloadListeners = null;
2525
2526             if (listeners && listeners.length > 0) {
2527                 j = listeners.length;
2528                 while (j) {
2529                     index = j - 1;
2530                     l = listeners[index];
2531                     if (l) {
2532                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2533                                 l[EU.FN], index);
2534                     }
2535                     j = j - 1;
2536                 }
2537                 l = null;
2538
2539                 EU.clearCache();
2540             }
2541
2542             EU.doRemove(window, "unload", EU._unload);
2543
2544         },
2545
2546
2547         getScroll: function() {
2548             var dd = document.documentElement, db = document.body;
2549             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2550                 return [dd.scrollTop, dd.scrollLeft];
2551             } else if (db) {
2552                 return [db.scrollTop, db.scrollLeft];
2553             } else {
2554                 return [0, 0];
2555             }
2556         },
2557
2558
2559         doAdd: function () {
2560             if (window.addEventListener) {
2561                 return function(el, eventName, fn, capture) {
2562                     el.addEventListener(eventName, fn, (capture));
2563                 };
2564             } else if (window.attachEvent) {
2565                 return function(el, eventName, fn, capture) {
2566                     el.attachEvent("on" + eventName, fn);
2567                 };
2568             } else {
2569                 return function() {
2570                 };
2571             }
2572         }(),
2573
2574
2575         doRemove: function() {
2576             if (window.removeEventListener) {
2577                 return function (el, eventName, fn, capture) {
2578                     el.removeEventListener(eventName, fn, (capture));
2579                 };
2580             } else if (window.detachEvent) {
2581                 return function (el, eventName, fn) {
2582                     el.detachEvent("on" + eventName, fn);
2583                 };
2584             } else {
2585                 return function() {
2586                 };
2587             }
2588         }()
2589     };
2590     
2591 }();
2592 (function() {     
2593    
2594     var E = Roo.lib.Event;
2595     E.on = E.addListener;
2596     E.un = E.removeListener;
2597
2598     if (document && document.body) {
2599         E._load();
2600     } else {
2601         E.doAdd(window, "load", E._load);
2602     }
2603     E.doAdd(window, "unload", E._unload);
2604     E._tryPreloadAttach();
2605 })();
2606
2607  
2608
2609 (function() {
2610     /**
2611      * @class Roo.lib.Ajax
2612      *
2613      * provide a simple Ajax request utility functions
2614      * 
2615      * Portions of this file are based on pieces of Yahoo User Interface Library
2616     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2617     * YUI licensed under the BSD License:
2618     * http://developer.yahoo.net/yui/license.txt
2619     * <script type="text/javascript">
2620     *
2621      *
2622      */
2623     Roo.lib.Ajax = {
2624         /**
2625          * @static 
2626          */
2627         request : function(method, uri, cb, data, options) {
2628             if(options){
2629                 var hs = options.headers;
2630                 if(hs){
2631                     for(var h in hs){
2632                         if(hs.hasOwnProperty(h)){
2633                             this.initHeader(h, hs[h], false);
2634                         }
2635                     }
2636                 }
2637                 if(options.xmlData){
2638                     this.initHeader('Content-Type', 'text/xml', false);
2639                     method = 'POST';
2640                     data = options.xmlData;
2641                 }
2642             }
2643
2644             return this.asyncRequest(method, uri, cb, data);
2645         },
2646         /**
2647          * serialize a form
2648          *
2649          * @static
2650          * @param {DomForm} form element
2651          * @return {String} urlencode form output.
2652          */
2653         serializeForm : function(form) {
2654             if(typeof form == 'string') {
2655                 form = (document.getElementById(form) || document.forms[form]);
2656             }
2657
2658             var el, name, val, disabled, data = '', hasSubmit = false;
2659             for (var i = 0; i < form.elements.length; i++) {
2660                 el = form.elements[i];
2661                 disabled = form.elements[i].disabled;
2662                 name = form.elements[i].name;
2663                 val = form.elements[i].value;
2664
2665                 if (!disabled && name){
2666                     switch (el.type)
2667                             {
2668                         case 'select-one':
2669                         case 'select-multiple':
2670                             for (var j = 0; j < el.options.length; j++) {
2671                                 if (el.options[j].selected) {
2672                                     if (Roo.isIE) {
2673                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2674                                     }
2675                                     else {
2676                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2677                                     }
2678                                 }
2679                             }
2680                             break;
2681                         case 'radio':
2682                         case 'checkbox':
2683                             if (el.checked) {
2684                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2685                             }
2686                             break;
2687                         case 'file':
2688
2689                         case undefined:
2690
2691                         case 'reset':
2692
2693                         case 'button':
2694
2695                             break;
2696                         case 'submit':
2697                             if(hasSubmit == false) {
2698                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2699                                 hasSubmit = true;
2700                             }
2701                             break;
2702                         default:
2703                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2704                             break;
2705                     }
2706                 }
2707             }
2708             data = data.substr(0, data.length - 1);
2709             return data;
2710         },
2711
2712         headers:{},
2713
2714         hasHeaders:false,
2715
2716         useDefaultHeader:true,
2717
2718         defaultPostHeader:'application/x-www-form-urlencoded',
2719
2720         useDefaultXhrHeader:true,
2721
2722         defaultXhrHeader:'XMLHttpRequest',
2723
2724         hasDefaultHeaders:true,
2725
2726         defaultHeaders:{},
2727
2728         poll:{},
2729
2730         timeout:{},
2731
2732         pollInterval:50,
2733
2734         transactionId:0,
2735
2736         setProgId:function(id)
2737         {
2738             this.activeX.unshift(id);
2739         },
2740
2741         setDefaultPostHeader:function(b)
2742         {
2743             this.useDefaultHeader = b;
2744         },
2745
2746         setDefaultXhrHeader:function(b)
2747         {
2748             this.useDefaultXhrHeader = b;
2749         },
2750
2751         setPollingInterval:function(i)
2752         {
2753             if (typeof i == 'number' && isFinite(i)) {
2754                 this.pollInterval = i;
2755             }
2756         },
2757
2758         createXhrObject:function(transactionId)
2759         {
2760             var obj,http;
2761             try
2762             {
2763
2764                 http = new XMLHttpRequest();
2765
2766                 obj = { conn:http, tId:transactionId };
2767             }
2768             catch(e)
2769             {
2770                 for (var i = 0; i < this.activeX.length; ++i) {
2771                     try
2772                     {
2773
2774                         http = new ActiveXObject(this.activeX[i]);
2775
2776                         obj = { conn:http, tId:transactionId };
2777                         break;
2778                     }
2779                     catch(e) {
2780                     }
2781                 }
2782             }
2783             finally
2784             {
2785                 return obj;
2786             }
2787         },
2788
2789         getConnectionObject:function()
2790         {
2791             var o;
2792             var tId = this.transactionId;
2793
2794             try
2795             {
2796                 o = this.createXhrObject(tId);
2797                 if (o) {
2798                     this.transactionId++;
2799                 }
2800             }
2801             catch(e) {
2802             }
2803             finally
2804             {
2805                 return o;
2806             }
2807         },
2808
2809         asyncRequest:function(method, uri, callback, postData)
2810         {
2811             var o = this.getConnectionObject();
2812
2813             if (!o) {
2814                 return null;
2815             }
2816             else {
2817                 o.conn.open(method, uri, true);
2818
2819                 if (this.useDefaultXhrHeader) {
2820                     if (!this.defaultHeaders['X-Requested-With']) {
2821                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2822                     }
2823                 }
2824
2825                 if(postData && this.useDefaultHeader){
2826                     this.initHeader('Content-Type', this.defaultPostHeader);
2827                 }
2828
2829                  if (this.hasDefaultHeaders || this.hasHeaders) {
2830                     this.setHeader(o);
2831                 }
2832
2833                 this.handleReadyState(o, callback);
2834                 o.conn.send(postData || null);
2835
2836                 return o;
2837             }
2838         },
2839
2840         handleReadyState:function(o, callback)
2841         {
2842             var oConn = this;
2843
2844             if (callback && callback.timeout) {
2845                 
2846                 this.timeout[o.tId] = window.setTimeout(function() {
2847                     oConn.abort(o, callback, true);
2848                 }, callback.timeout);
2849             }
2850
2851             this.poll[o.tId] = window.setInterval(
2852                     function() {
2853                         if (o.conn && o.conn.readyState == 4) {
2854                             window.clearInterval(oConn.poll[o.tId]);
2855                             delete oConn.poll[o.tId];
2856
2857                             if(callback && callback.timeout) {
2858                                 window.clearTimeout(oConn.timeout[o.tId]);
2859                                 delete oConn.timeout[o.tId];
2860                             }
2861
2862                             oConn.handleTransactionResponse(o, callback);
2863                         }
2864                     }
2865                     , this.pollInterval);
2866         },
2867
2868         handleTransactionResponse:function(o, callback, isAbort)
2869         {
2870
2871             if (!callback) {
2872                 this.releaseObject(o);
2873                 return;
2874             }
2875
2876             var httpStatus, responseObject;
2877
2878             try
2879             {
2880                 if (o.conn.status !== undefined && o.conn.status != 0) {
2881                     httpStatus = o.conn.status;
2882                 }
2883                 else {
2884                     httpStatus = 13030;
2885                 }
2886             }
2887             catch(e) {
2888
2889
2890                 httpStatus = 13030;
2891             }
2892
2893             if (httpStatus >= 200 && httpStatus < 300) {
2894                 responseObject = this.createResponseObject(o, callback.argument);
2895                 if (callback.success) {
2896                     if (!callback.scope) {
2897                         callback.success(responseObject);
2898                     }
2899                     else {
2900
2901
2902                         callback.success.apply(callback.scope, [responseObject]);
2903                     }
2904                 }
2905             }
2906             else {
2907                 switch (httpStatus) {
2908
2909                     case 12002:
2910                     case 12029:
2911                     case 12030:
2912                     case 12031:
2913                     case 12152:
2914                     case 13030:
2915                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2916                         if (callback.failure) {
2917                             if (!callback.scope) {
2918                                 callback.failure(responseObject);
2919                             }
2920                             else {
2921                                 callback.failure.apply(callback.scope, [responseObject]);
2922                             }
2923                         }
2924                         break;
2925                     default:
2926                         responseObject = this.createResponseObject(o, callback.argument);
2927                         if (callback.failure) {
2928                             if (!callback.scope) {
2929                                 callback.failure(responseObject);
2930                             }
2931                             else {
2932                                 callback.failure.apply(callback.scope, [responseObject]);
2933                             }
2934                         }
2935                 }
2936             }
2937
2938             this.releaseObject(o);
2939             responseObject = null;
2940         },
2941
2942         createResponseObject:function(o, callbackArg)
2943         {
2944             var obj = {};
2945             var headerObj = {};
2946
2947             try
2948             {
2949                 var headerStr = o.conn.getAllResponseHeaders();
2950                 var header = headerStr.split('\n');
2951                 for (var i = 0; i < header.length; i++) {
2952                     var delimitPos = header[i].indexOf(':');
2953                     if (delimitPos != -1) {
2954                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2955                     }
2956                 }
2957             }
2958             catch(e) {
2959             }
2960
2961             obj.tId = o.tId;
2962             obj.status = o.conn.status;
2963             obj.statusText = o.conn.statusText;
2964             obj.getResponseHeader = headerObj;
2965             obj.getAllResponseHeaders = headerStr;
2966             obj.responseText = o.conn.responseText;
2967             obj.responseXML = o.conn.responseXML;
2968
2969             if (typeof callbackArg !== undefined) {
2970                 obj.argument = callbackArg;
2971             }
2972
2973             return obj;
2974         },
2975
2976         createExceptionObject:function(tId, callbackArg, isAbort)
2977         {
2978             var COMM_CODE = 0;
2979             var COMM_ERROR = 'communication failure';
2980             var ABORT_CODE = -1;
2981             var ABORT_ERROR = 'transaction aborted';
2982
2983             var obj = {};
2984
2985             obj.tId = tId;
2986             if (isAbort) {
2987                 obj.status = ABORT_CODE;
2988                 obj.statusText = ABORT_ERROR;
2989             }
2990             else {
2991                 obj.status = COMM_CODE;
2992                 obj.statusText = COMM_ERROR;
2993             }
2994
2995             if (callbackArg) {
2996                 obj.argument = callbackArg;
2997             }
2998
2999             return obj;
3000         },
3001
3002         initHeader:function(label, value, isDefault)
3003         {
3004             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3005
3006             if (headerObj[label] === undefined) {
3007                 headerObj[label] = value;
3008             }
3009             else {
3010
3011
3012                 headerObj[label] = value + "," + headerObj[label];
3013             }
3014
3015             if (isDefault) {
3016                 this.hasDefaultHeaders = true;
3017             }
3018             else {
3019                 this.hasHeaders = true;
3020             }
3021         },
3022
3023
3024         setHeader:function(o)
3025         {
3026             if (this.hasDefaultHeaders) {
3027                 for (var prop in this.defaultHeaders) {
3028                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3029                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3030                     }
3031                 }
3032             }
3033
3034             if (this.hasHeaders) {
3035                 for (var prop in this.headers) {
3036                     if (this.headers.hasOwnProperty(prop)) {
3037                         o.conn.setRequestHeader(prop, this.headers[prop]);
3038                     }
3039                 }
3040                 this.headers = {};
3041                 this.hasHeaders = false;
3042             }
3043         },
3044
3045         resetDefaultHeaders:function() {
3046             delete this.defaultHeaders;
3047             this.defaultHeaders = {};
3048             this.hasDefaultHeaders = false;
3049         },
3050
3051         abort:function(o, callback, isTimeout)
3052         {
3053             if(this.isCallInProgress(o)) {
3054                 o.conn.abort();
3055                 window.clearInterval(this.poll[o.tId]);
3056                 delete this.poll[o.tId];
3057                 if (isTimeout) {
3058                     delete this.timeout[o.tId];
3059                 }
3060
3061                 this.handleTransactionResponse(o, callback, true);
3062
3063                 return true;
3064             }
3065             else {
3066                 return false;
3067             }
3068         },
3069
3070
3071         isCallInProgress:function(o)
3072         {
3073             if (o && o.conn) {
3074                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3075             }
3076             else {
3077
3078                 return false;
3079             }
3080         },
3081
3082
3083         releaseObject:function(o)
3084         {
3085
3086             o.conn = null;
3087
3088             o = null;
3089         },
3090
3091         activeX:[
3092         'MSXML2.XMLHTTP.3.0',
3093         'MSXML2.XMLHTTP',
3094         'Microsoft.XMLHTTP'
3095         ]
3096
3097
3098     };
3099 })();/*
3100  * Portions of this file are based on pieces of Yahoo User Interface Library
3101  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3102  * YUI licensed under the BSD License:
3103  * http://developer.yahoo.net/yui/license.txt
3104  * <script type="text/javascript">
3105  *
3106  */
3107
3108 Roo.lib.Region = function(t, r, b, l) {
3109     this.top = t;
3110     this[1] = t;
3111     this.right = r;
3112     this.bottom = b;
3113     this.left = l;
3114     this[0] = l;
3115 };
3116
3117
3118 Roo.lib.Region.prototype = {
3119     contains : function(region) {
3120         return ( region.left >= this.left &&
3121                  region.right <= this.right &&
3122                  region.top >= this.top &&
3123                  region.bottom <= this.bottom    );
3124
3125     },
3126
3127     getArea : function() {
3128         return ( (this.bottom - this.top) * (this.right - this.left) );
3129     },
3130
3131     intersect : function(region) {
3132         var t = Math.max(this.top, region.top);
3133         var r = Math.min(this.right, region.right);
3134         var b = Math.min(this.bottom, region.bottom);
3135         var l = Math.max(this.left, region.left);
3136
3137         if (b >= t && r >= l) {
3138             return new Roo.lib.Region(t, r, b, l);
3139         } else {
3140             return null;
3141         }
3142     },
3143     union : function(region) {
3144         var t = Math.min(this.top, region.top);
3145         var r = Math.max(this.right, region.right);
3146         var b = Math.max(this.bottom, region.bottom);
3147         var l = Math.min(this.left, region.left);
3148
3149         return new Roo.lib.Region(t, r, b, l);
3150     },
3151
3152     adjust : function(t, l, b, r) {
3153         this.top += t;
3154         this.left += l;
3155         this.right += r;
3156         this.bottom += b;
3157         return this;
3158     }
3159 };
3160
3161 Roo.lib.Region.getRegion = function(el) {
3162     var p = Roo.lib.Dom.getXY(el);
3163
3164     var t = p[1];
3165     var r = p[0] + el.offsetWidth;
3166     var b = p[1] + el.offsetHeight;
3167     var l = p[0];
3168
3169     return new Roo.lib.Region(t, r, b, l);
3170 };
3171 /*
3172  * Portions of this file are based on pieces of Yahoo User Interface Library
3173  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3174  * YUI licensed under the BSD License:
3175  * http://developer.yahoo.net/yui/license.txt
3176  * <script type="text/javascript">
3177  *
3178  */
3179 //@@dep Roo.lib.Region
3180
3181
3182 Roo.lib.Point = function(x, y) {
3183     if (x instanceof Array) {
3184         y = x[1];
3185         x = x[0];
3186     }
3187     this.x = this.right = this.left = this[0] = x;
3188     this.y = this.top = this.bottom = this[1] = y;
3189 };
3190
3191 Roo.lib.Point.prototype = new Roo.lib.Region();
3192 /*
3193  * Portions of this file are based on pieces of Yahoo User Interface Library
3194  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3195  * YUI licensed under the BSD License:
3196  * http://developer.yahoo.net/yui/license.txt
3197  * <script type="text/javascript">
3198  *
3199  */
3200  
3201 (function() {   
3202
3203     Roo.lib.Anim = {
3204         scroll : function(el, args, duration, easing, cb, scope) {
3205             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3206         },
3207
3208         motion : function(el, args, duration, easing, cb, scope) {
3209             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3210         },
3211
3212         color : function(el, args, duration, easing, cb, scope) {
3213             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3214         },
3215
3216         run : function(el, args, duration, easing, cb, scope, type) {
3217             type = type || Roo.lib.AnimBase;
3218             if (typeof easing == "string") {
3219                 easing = Roo.lib.Easing[easing];
3220             }
3221             var anim = new type(el, args, duration, easing);
3222             anim.animateX(function() {
3223                 Roo.callback(cb, scope);
3224             });
3225             return anim;
3226         }
3227     };
3228 })();/*
3229  * Portions of this file are based on pieces of Yahoo User Interface Library
3230  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3231  * YUI licensed under the BSD License:
3232  * http://developer.yahoo.net/yui/license.txt
3233  * <script type="text/javascript">
3234  *
3235  */
3236
3237 (function() {    
3238     var libFlyweight;
3239     
3240     function fly(el) {
3241         if (!libFlyweight) {
3242             libFlyweight = new Roo.Element.Flyweight();
3243         }
3244         libFlyweight.dom = el;
3245         return libFlyweight;
3246     }
3247
3248     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3249     
3250    
3251     
3252     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3253         if (el) {
3254             this.init(el, attributes, duration, method);
3255         }
3256     };
3257
3258     Roo.lib.AnimBase.fly = fly;
3259     
3260     
3261     
3262     Roo.lib.AnimBase.prototype = {
3263
3264         toString: function() {
3265             var el = this.getEl();
3266             var id = el.id || el.tagName;
3267             return ("Anim " + id);
3268         },
3269
3270         patterns: {
3271             noNegatives:        /width|height|opacity|padding/i,
3272             offsetAttribute:  /^((width|height)|(top|left))$/,
3273             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3274             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3275         },
3276
3277
3278         doMethod: function(attr, start, end) {
3279             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3280         },
3281
3282
3283         setAttribute: function(attr, val, unit) {
3284             if (this.patterns.noNegatives.test(attr)) {
3285                 val = (val > 0) ? val : 0;
3286             }
3287
3288             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3289         },
3290
3291
3292         getAttribute: function(attr) {
3293             var el = this.getEl();
3294             var val = fly(el).getStyle(attr);
3295
3296             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3297                 return parseFloat(val);
3298             }
3299
3300             var a = this.patterns.offsetAttribute.exec(attr) || [];
3301             var pos = !!( a[3] );
3302             var box = !!( a[2] );
3303
3304
3305             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3306                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3307             } else {
3308                 val = 0;
3309             }
3310
3311             return val;
3312         },
3313
3314
3315         getDefaultUnit: function(attr) {
3316             if (this.patterns.defaultUnit.test(attr)) {
3317                 return 'px';
3318             }
3319
3320             return '';
3321         },
3322
3323         animateX : function(callback, scope) {
3324             var f = function() {
3325                 this.onComplete.removeListener(f);
3326                 if (typeof callback == "function") {
3327                     callback.call(scope || this, this);
3328                 }
3329             };
3330             this.onComplete.addListener(f, this);
3331             this.animate();
3332         },
3333
3334
3335         setRuntimeAttribute: function(attr) {
3336             var start;
3337             var end;
3338             var attributes = this.attributes;
3339
3340             this.runtimeAttributes[attr] = {};
3341
3342             var isset = function(prop) {
3343                 return (typeof prop !== 'undefined');
3344             };
3345
3346             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3347                 return false;
3348             }
3349
3350             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3351
3352
3353             if (isset(attributes[attr]['to'])) {
3354                 end = attributes[attr]['to'];
3355             } else if (isset(attributes[attr]['by'])) {
3356                 if (start.constructor == Array) {
3357                     end = [];
3358                     for (var i = 0, len = start.length; i < len; ++i) {
3359                         end[i] = start[i] + attributes[attr]['by'][i];
3360                     }
3361                 } else {
3362                     end = start + attributes[attr]['by'];
3363                 }
3364             }
3365
3366             this.runtimeAttributes[attr].start = start;
3367             this.runtimeAttributes[attr].end = end;
3368
3369
3370             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3371         },
3372
3373
3374         init: function(el, attributes, duration, method) {
3375
3376             var isAnimated = false;
3377
3378
3379             var startTime = null;
3380
3381
3382             var actualFrames = 0;
3383
3384
3385             el = Roo.getDom(el);
3386
3387
3388             this.attributes = attributes || {};
3389
3390
3391             this.duration = duration || 1;
3392
3393
3394             this.method = method || Roo.lib.Easing.easeNone;
3395
3396
3397             this.useSeconds = true;
3398
3399
3400             this.currentFrame = 0;
3401
3402
3403             this.totalFrames = Roo.lib.AnimMgr.fps;
3404
3405
3406             this.getEl = function() {
3407                 return el;
3408             };
3409
3410
3411             this.isAnimated = function() {
3412                 return isAnimated;
3413             };
3414
3415
3416             this.getStartTime = function() {
3417                 return startTime;
3418             };
3419
3420             this.runtimeAttributes = {};
3421
3422
3423             this.animate = function() {
3424                 if (this.isAnimated()) {
3425                     return false;
3426                 }
3427
3428                 this.currentFrame = 0;
3429
3430                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3431
3432                 Roo.lib.AnimMgr.registerElement(this);
3433             };
3434
3435
3436             this.stop = function(finish) {
3437                 if (finish) {
3438                     this.currentFrame = this.totalFrames;
3439                     this._onTween.fire();
3440                 }
3441                 Roo.lib.AnimMgr.stop(this);
3442             };
3443
3444             var onStart = function() {
3445                 this.onStart.fire();
3446
3447                 this.runtimeAttributes = {};
3448                 for (var attr in this.attributes) {
3449                     this.setRuntimeAttribute(attr);
3450                 }
3451
3452                 isAnimated = true;
3453                 actualFrames = 0;
3454                 startTime = new Date();
3455             };
3456
3457
3458             var onTween = function() {
3459                 var data = {
3460                     duration: new Date() - this.getStartTime(),
3461                     currentFrame: this.currentFrame
3462                 };
3463
3464                 data.toString = function() {
3465                     return (
3466                             'duration: ' + data.duration +
3467                             ', currentFrame: ' + data.currentFrame
3468                             );
3469                 };
3470
3471                 this.onTween.fire(data);
3472
3473                 var runtimeAttributes = this.runtimeAttributes;
3474
3475                 for (var attr in runtimeAttributes) {
3476                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3477                 }
3478
3479                 actualFrames += 1;
3480             };
3481
3482             var onComplete = function() {
3483                 var actual_duration = (new Date() - startTime) / 1000 ;
3484
3485                 var data = {
3486                     duration: actual_duration,
3487                     frames: actualFrames,
3488                     fps: actualFrames / actual_duration
3489                 };
3490
3491                 data.toString = function() {
3492                     return (
3493                             'duration: ' + data.duration +
3494                             ', frames: ' + data.frames +
3495                             ', fps: ' + data.fps
3496                             );
3497                 };
3498
3499                 isAnimated = false;
3500                 actualFrames = 0;
3501                 this.onComplete.fire(data);
3502             };
3503
3504
3505             this._onStart = new Roo.util.Event(this);
3506             this.onStart = new Roo.util.Event(this);
3507             this.onTween = new Roo.util.Event(this);
3508             this._onTween = new Roo.util.Event(this);
3509             this.onComplete = new Roo.util.Event(this);
3510             this._onComplete = new Roo.util.Event(this);
3511             this._onStart.addListener(onStart);
3512             this._onTween.addListener(onTween);
3513             this._onComplete.addListener(onComplete);
3514         }
3515     };
3516 })();
3517 /*
3518  * Portions of this file are based on pieces of Yahoo User Interface Library
3519  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3520  * YUI licensed under the BSD License:
3521  * http://developer.yahoo.net/yui/license.txt
3522  * <script type="text/javascript">
3523  *
3524  */
3525
3526 Roo.lib.AnimMgr = new function() {
3527
3528     var thread = null;
3529
3530
3531     var queue = [];
3532
3533
3534     var tweenCount = 0;
3535
3536
3537     this.fps = 1000;
3538
3539
3540     this.delay = 1;
3541
3542
3543     this.registerElement = function(tween) {
3544         queue[queue.length] = tween;
3545         tweenCount += 1;
3546         tween._onStart.fire();
3547         this.start();
3548     };
3549
3550
3551     this.unRegister = function(tween, index) {
3552         tween._onComplete.fire();
3553         index = index || getIndex(tween);
3554         if (index != -1) {
3555             queue.splice(index, 1);
3556         }
3557
3558         tweenCount -= 1;
3559         if (tweenCount <= 0) {
3560             this.stop();
3561         }
3562     };
3563
3564
3565     this.start = function() {
3566         if (thread === null) {
3567             thread = setInterval(this.run, this.delay);
3568         }
3569     };
3570
3571
3572     this.stop = function(tween) {
3573         if (!tween) {
3574             clearInterval(thread);
3575
3576             for (var i = 0, len = queue.length; i < len; ++i) {
3577                 if (queue[0].isAnimated()) {
3578                     this.unRegister(queue[0], 0);
3579                 }
3580             }
3581
3582             queue = [];
3583             thread = null;
3584             tweenCount = 0;
3585         }
3586         else {
3587             this.unRegister(tween);
3588         }
3589     };
3590
3591
3592     this.run = function() {
3593         for (var i = 0, len = queue.length; i < len; ++i) {
3594             var tween = queue[i];
3595             if (!tween || !tween.isAnimated()) {
3596                 continue;
3597             }
3598
3599             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3600             {
3601                 tween.currentFrame += 1;
3602
3603                 if (tween.useSeconds) {
3604                     correctFrame(tween);
3605                 }
3606                 tween._onTween.fire();
3607             }
3608             else {
3609                 Roo.lib.AnimMgr.stop(tween, i);
3610             }
3611         }
3612     };
3613
3614     var getIndex = function(anim) {
3615         for (var i = 0, len = queue.length; i < len; ++i) {
3616             if (queue[i] == anim) {
3617                 return i;
3618             }
3619         }
3620         return -1;
3621     };
3622
3623
3624     var correctFrame = function(tween) {
3625         var frames = tween.totalFrames;
3626         var frame = tween.currentFrame;
3627         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3628         var elapsed = (new Date() - tween.getStartTime());
3629         var tweak = 0;
3630
3631         if (elapsed < tween.duration * 1000) {
3632             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3633         } else {
3634             tweak = frames - (frame + 1);
3635         }
3636         if (tweak > 0 && isFinite(tweak)) {
3637             if (tween.currentFrame + tweak >= frames) {
3638                 tweak = frames - (frame + 1);
3639             }
3640
3641             tween.currentFrame += tweak;
3642         }
3643     };
3644 };
3645
3646     /*
3647  * Portions of this file are based on pieces of Yahoo User Interface Library
3648  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3649  * YUI licensed under the BSD License:
3650  * http://developer.yahoo.net/yui/license.txt
3651  * <script type="text/javascript">
3652  *
3653  */
3654 Roo.lib.Bezier = new function() {
3655
3656         this.getPosition = function(points, t) {
3657             var n = points.length;
3658             var tmp = [];
3659
3660             for (var i = 0; i < n; ++i) {
3661                 tmp[i] = [points[i][0], points[i][1]];
3662             }
3663
3664             for (var j = 1; j < n; ++j) {
3665                 for (i = 0; i < n - j; ++i) {
3666                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3667                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3668                 }
3669             }
3670
3671             return [ tmp[0][0], tmp[0][1] ];
3672
3673         };
3674     }; 
3675
3676 /**
3677  * @class Roo.lib.Color
3678  * @constructor
3679  * An abstract Color implementation. Concrete Color implementations should use
3680  * an instance of this function as their prototype, and implement the getRGB and
3681  * getHSL functions. getRGB should return an object representing the RGB
3682  * components of this Color, with the red, green, and blue components in the
3683  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3684  * return an object representing the HSL components of this Color, with the hue
3685  * component in the range [0,360), the saturation and lightness components in
3686  * the range [0,100], and the alpha component in the range [0,1].
3687  *
3688  *
3689  * Color.js
3690  *
3691  * Functions for Color handling and processing.
3692  *
3693  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3694  *
3695  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3696  * rights to this program, with the intention of it becoming part of the public
3697  * domain. Because this program is released into the public domain, it comes with
3698  * no warranty either expressed or implied, to the extent permitted by law.
3699  * 
3700  * For more free and public domain JavaScript code by the same author, visit:
3701  * http://www.safalra.com/web-design/javascript/
3702  * 
3703  */
3704 Roo.lib.Color = function() { }
3705
3706
3707 Roo.apply(Roo.lib.Color.prototype, {
3708   
3709   rgb : null,
3710   hsv : null,
3711   hsl : null,
3712   
3713   /**
3714    * getIntegerRGB
3715    * @return {Object} an object representing the RGBA components of this Color. The red,
3716    * green, and blue components are converted to integers in the range [0,255].
3717    * The alpha is a value in the range [0,1].
3718    */
3719   getIntegerRGB : function(){
3720
3721     // get the RGB components of this Color
3722     var rgb = this.getRGB();
3723
3724     // return the integer components
3725     return {
3726       'r' : Math.round(rgb.r),
3727       'g' : Math.round(rgb.g),
3728       'b' : Math.round(rgb.b),
3729       'a' : rgb.a
3730     };
3731
3732   },
3733
3734   /**
3735    * getPercentageRGB
3736    * @return {Object} an object representing the RGBA components of this Color. The red,
3737    * green, and blue components are converted to numbers in the range [0,100].
3738    * The alpha is a value in the range [0,1].
3739    */
3740   getPercentageRGB : function(){
3741
3742     // get the RGB components of this Color
3743     var rgb = this.getRGB();
3744
3745     // return the percentage components
3746     return {
3747       'r' : 100 * rgb.r / 255,
3748       'g' : 100 * rgb.g / 255,
3749       'b' : 100 * rgb.b / 255,
3750       'a' : rgb.a
3751     };
3752
3753   },
3754
3755   /**
3756    * getCSSHexadecimalRGB
3757    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3758    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3759    * are two-digit hexadecimal numbers.
3760    */
3761   getCSSHexadecimalRGB : function()
3762   {
3763
3764     // get the integer RGB components
3765     var rgb = this.getIntegerRGB();
3766
3767     // determine the hexadecimal equivalents
3768     var r16 = rgb.r.toString(16);
3769     var g16 = rgb.g.toString(16);
3770     var b16 = rgb.b.toString(16);
3771
3772     // return the CSS RGB Color value
3773     return '#'
3774         + (r16.length == 2 ? r16 : '0' + r16)
3775         + (g16.length == 2 ? g16 : '0' + g16)
3776         + (b16.length == 2 ? b16 : '0' + b16);
3777
3778   },
3779
3780   /**
3781    * getCSSIntegerRGB
3782    * @return {String} a string representing this Color as a CSS integer RGB Color
3783    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3784    * are integers in the range [0,255].
3785    */
3786   getCSSIntegerRGB : function(){
3787
3788     // get the integer RGB components
3789     var rgb = this.getIntegerRGB();
3790
3791     // return the CSS RGB Color value
3792     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3793
3794   },
3795
3796   /**
3797    * getCSSIntegerRGBA
3798    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3799    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3800    * b are integers in the range [0,255] and a is in the range [0,1].
3801    */
3802   getCSSIntegerRGBA : function(){
3803
3804     // get the integer RGB components
3805     var rgb = this.getIntegerRGB();
3806
3807     // return the CSS integer RGBA Color value
3808     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3809
3810   },
3811
3812   /**
3813    * getCSSPercentageRGB
3814    * @return {String} a string representing this Color as a CSS percentage RGB Color
3815    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3816    * b are in the range [0,100].
3817    */
3818   getCSSPercentageRGB : function(){
3819
3820     // get the percentage RGB components
3821     var rgb = this.getPercentageRGB();
3822
3823     // return the CSS RGB Color value
3824     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3825
3826   },
3827
3828   /**
3829    * getCSSPercentageRGBA
3830    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3831    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3832    * and b are in the range [0,100] and a is in the range [0,1].
3833    */
3834   getCSSPercentageRGBA : function(){
3835
3836     // get the percentage RGB components
3837     var rgb = this.getPercentageRGB();
3838
3839     // return the CSS percentage RGBA Color value
3840     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3841
3842   },
3843
3844   /**
3845    * getCSSHSL
3846    * @return {String} a string representing this Color as a CSS HSL Color value - that
3847    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3848    * s and l are in the range [0,100].
3849    */
3850   getCSSHSL : function(){
3851
3852     // get the HSL components
3853     var hsl = this.getHSL();
3854
3855     // return the CSS HSL Color value
3856     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3857
3858   },
3859
3860   /**
3861    * getCSSHSLA
3862    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3863    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3864    * s and l are in the range [0,100], and a is in the range [0,1].
3865    */
3866   getCSSHSLA : function(){
3867
3868     // get the HSL components
3869     var hsl = this.getHSL();
3870
3871     // return the CSS HSL Color value
3872     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3873
3874   },
3875
3876   /**
3877    * Sets the Color of the specified node to this Color. This functions sets
3878    * the CSS 'color' property for the node. The parameter is:
3879    * 
3880    * @param {DomElement} node - the node whose Color should be set
3881    */
3882   setNodeColor : function(node){
3883
3884     // set the Color of the node
3885     node.style.color = this.getCSSHexadecimalRGB();
3886
3887   },
3888
3889   /**
3890    * Sets the background Color of the specified node to this Color. This
3891    * functions sets the CSS 'background-color' property for the node. The
3892    * parameter is:
3893    *
3894    * @param {DomElement} node - the node whose background Color should be set
3895    */
3896   setNodeBackgroundColor : function(node){
3897
3898     // set the background Color of the node
3899     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3900
3901   },
3902   // convert between formats..
3903   toRGB: function()
3904   {
3905     var r = this.getIntegerRGB();
3906     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3907     
3908   },
3909   toHSL : function()
3910   {
3911      var hsl = this.getHSL();
3912   // return the CSS HSL Color value
3913     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3914     
3915   },
3916   
3917   toHSV : function()
3918   {
3919     var rgb = this.toRGB();
3920     var hsv = rgb.getHSV();
3921    // return the CSS HSL Color value
3922     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3923     
3924   },
3925   
3926   // modify  v = 0 ... 1 (eg. 0.5)
3927   saturate : function(v)
3928   {
3929       var rgb = this.toRGB();
3930       var hsv = rgb.getHSV();
3931       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3932       
3933   
3934   },
3935   
3936    
3937   /**
3938    * getRGB
3939    * @return {Object} the RGB and alpha components of this Color as an object with r,
3940    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3941    * the range [0,1].
3942    */
3943   getRGB: function(){
3944    
3945     // return the RGB components
3946     return {
3947       'r' : this.rgb.r,
3948       'g' : this.rgb.g,
3949       'b' : this.rgb.b,
3950       'a' : this.alpha
3951     };
3952
3953   },
3954
3955   /**
3956    * getHSV
3957    * @return {Object} the HSV and alpha components of this Color as an object with h,
3958    * s, v, and a properties. h is in the range [0,360), s and v are in the range
3959    * [0,100], and a is in the range [0,1].
3960    */
3961   getHSV : function()
3962   {
3963     
3964     // calculate the HSV components if necessary
3965     if (this.hsv == null) {
3966       this.calculateHSV();
3967     }
3968
3969     // return the HSV components
3970     return {
3971       'h' : this.hsv.h,
3972       's' : this.hsv.s,
3973       'v' : this.hsv.v,
3974       'a' : this.alpha
3975     };
3976
3977   },
3978
3979   /**
3980    * getHSL
3981    * @return {Object} the HSL and alpha components of this Color as an object with h,
3982    * s, l, and a properties. h is in the range [0,360), s and l are in the range
3983    * [0,100], and a is in the range [0,1].
3984    */
3985   getHSL : function(){
3986     
3987      
3988     // calculate the HSV components if necessary
3989     if (this.hsl == null) { this.calculateHSL(); }
3990
3991     // return the HSL components
3992     return {
3993       'h' : this.hsl.h,
3994       's' : this.hsl.s,
3995       'l' : this.hsl.l,
3996       'a' : this.alpha
3997     };
3998
3999   }
4000   
4001
4002 });
4003
4004
4005 /**
4006  * @class Roo.lib.RGBColor
4007  * @extends Roo.lib.Color
4008  * Creates a Color specified in the RGB Color space, with an optional alpha
4009  * component. The parameters are:
4010  * @constructor
4011  * 
4012
4013  * @param {Number} r - the red component, clipped to the range [0,255]
4014  * @param {Number} g - the green component, clipped to the range [0,255]
4015  * @param {Number} b - the blue component, clipped to the range [0,255]
4016  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4017  *     optional and defaults to 1
4018  */
4019 Roo.lib.RGBColor = function (r, g, b, a){
4020
4021   // store the alpha component after clipping it if necessary
4022   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4023
4024   // store the RGB components after clipping them if necessary
4025   this.rgb =
4026       {
4027         'r' : Math.max(0, Math.min(255, r)),
4028         'g' : Math.max(0, Math.min(255, g)),
4029         'b' : Math.max(0, Math.min(255, b))
4030       };
4031
4032   // initialise the HSV and HSL components to null
4033   
4034
4035   /* 
4036    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4037    * range [0,360). The parameters are:
4038    *
4039    * maximum - the maximum of the RGB component values
4040    * range   - the range of the RGB component values
4041    */
4042    
4043
4044 }
4045 // this does an 'exteds'
4046 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4047
4048   
4049     getHue  : function(maximum, range)
4050     {
4051       var rgb = this.rgb;
4052        
4053       // check whether the range is zero
4054       if (range == 0){
4055   
4056         // set the hue to zero (any hue is acceptable as the Color is grey)
4057         var hue = 0;
4058   
4059       }else{
4060   
4061         // determine which of the components has the highest value and set the hue
4062         switch (maximum){
4063   
4064           // red has the highest value
4065           case rgb.r:
4066             var hue = (rgb.g - rgb.b) / range * 60;
4067             if (hue < 0) { hue += 360; }
4068             break;
4069   
4070           // green has the highest value
4071           case rgb.g:
4072             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4073             break;
4074   
4075           // blue has the highest value
4076           case rgb.b:
4077             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4078             break;
4079   
4080         }
4081   
4082       }
4083   
4084       // return the hue
4085       return hue;
4086   
4087     },
4088
4089   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4090    * be returned be the getHSV function.
4091    */
4092    calculateHSV : function(){
4093     var rgb = this.rgb;
4094     // get the maximum and range of the RGB component values
4095     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4096     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4097
4098     // store the HSV components
4099     this.hsv =
4100         {
4101           'h' : this.getHue(maximum, range),
4102           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4103           'v' : maximum / 2.55
4104         };
4105
4106   },
4107
4108   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4109    * be returned be the getHSL function.
4110    */
4111    calculateHSL : 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     // determine the lightness in the range [0,1]
4118     var l = maximum / 255 - range / 510;
4119
4120     // store the HSL components
4121     this.hsl =
4122         {
4123           'h' : this.getHue(maximum, range),
4124           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4125           'l' : 100 * l
4126         };
4127
4128   }
4129
4130 });
4131
4132 /**
4133  * @class Roo.lib.HSVColor
4134  * @extends Roo.lib.Color
4135  * Creates a Color specified in the HSV Color space, with an optional alpha
4136  * component. The parameters are:
4137  * @constructor
4138  *
4139  * @param {Number} h - the hue component, wrapped to the range [0,360)
4140  * @param {Number} s - the saturation component, clipped to the range [0,100]
4141  * @param {Number} v - the value component, clipped to the range [0,100]
4142  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4143  *     optional and defaults to 1
4144  */
4145 Roo.lib.HSVColor = function (h, s, v, a){
4146
4147   // store the alpha component after clipping it if necessary
4148   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4149
4150   // store the HSV components after clipping or wrapping them if necessary
4151   this.hsv =
4152       {
4153         'h' : (h % 360 + 360) % 360,
4154         's' : Math.max(0, Math.min(100, s)),
4155         'v' : Math.max(0, Math.min(100, v))
4156       };
4157
4158   // initialise the RGB and HSL components to null
4159   this.rgb = null;
4160   this.hsl = null;
4161 }
4162
4163 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4164   /* Calculates and stores the RGB components of this HSVColor so that they can
4165    * be returned be the getRGB function.
4166    */
4167   calculateRGB: function ()
4168   {
4169     var hsv = this.hsv;
4170     // check whether the saturation is zero
4171     if (hsv.s == 0){
4172
4173       // set the Color to the appropriate shade of grey
4174       var r = hsv.v;
4175       var g = hsv.v;
4176       var b = hsv.v;
4177
4178     }else{
4179
4180       // set some temporary values
4181       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4182       var p  = hsv.v * (1 - hsv.s / 100);
4183       var q  = hsv.v * (1 - hsv.s / 100 * f);
4184       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4185
4186       // set the RGB Color components to their temporary values
4187       switch (Math.floor(hsv.h / 60)){
4188         case 0: var r = hsv.v; var g = t; var b = p; break;
4189         case 1: var r = q; var g = hsv.v; var b = p; break;
4190         case 2: var r = p; var g = hsv.v; var b = t; break;
4191         case 3: var r = p; var g = q; var b = hsv.v; break;
4192         case 4: var r = t; var g = p; var b = hsv.v; break;
4193         case 5: var r = hsv.v; var g = p; var b = q; break;
4194       }
4195
4196     }
4197
4198     // store the RGB components
4199     this.rgb =
4200         {
4201           'r' : r * 2.55,
4202           'g' : g * 2.55,
4203           'b' : b * 2.55
4204         };
4205
4206   },
4207
4208   /* Calculates and stores the HSL components of this HSVColor so that they can
4209    * be returned be the getHSL function.
4210    */
4211   calculateHSL : function (){
4212
4213     var hsv = this.hsv;
4214     // determine the lightness in the range [0,100]
4215     var l = (2 - hsv.s / 100) * hsv.v / 2;
4216
4217     // store the HSL components
4218     this.hsl =
4219         {
4220           'h' : hsv.h,
4221           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4222           'l' : l
4223         };
4224
4225     // correct a division-by-zero error
4226     if (isNaN(hsl.s)) { hsl.s = 0; }
4227
4228   } 
4229  
4230
4231 });
4232  
4233
4234 /**
4235  * @class Roo.lib.HSLColor
4236  * @extends Roo.lib.Color
4237  *
4238  * @constructor
4239  * Creates a Color specified in the HSL Color space, with an optional alpha
4240  * component. The parameters are:
4241  *
4242  * @param {Number} h - the hue component, wrapped to the range [0,360)
4243  * @param {Number} s - the saturation component, clipped to the range [0,100]
4244  * @param {Number} l - the lightness component, clipped to the range [0,100]
4245  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4246  *     optional and defaults to 1
4247  */
4248
4249 Roo.lib.HSLColor = function(h, s, l, a){
4250
4251   // store the alpha component after clipping it if necessary
4252   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4253
4254   // store the HSL components after clipping or wrapping them if necessary
4255   this.hsl =
4256       {
4257         'h' : (h % 360 + 360) % 360,
4258         's' : Math.max(0, Math.min(100, s)),
4259         'l' : Math.max(0, Math.min(100, l))
4260       };
4261
4262   // initialise the RGB and HSV components to null
4263 }
4264
4265 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4266
4267   /* Calculates and stores the RGB components of this HSLColor so that they can
4268    * be returned be the getRGB function.
4269    */
4270   calculateRGB: function (){
4271
4272     // check whether the saturation is zero
4273     if (this.hsl.s == 0){
4274
4275       // store the RGB components representing the appropriate shade of grey
4276       this.rgb =
4277           {
4278             'r' : this.hsl.l * 2.55,
4279             'g' : this.hsl.l * 2.55,
4280             'b' : this.hsl.l * 2.55
4281           };
4282
4283     }else{
4284
4285       // set some temporary values
4286       var p = this.hsl.l < 50
4287             ? this.hsl.l * (1 + hsl.s / 100)
4288             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4289       var q = 2 * hsl.l - p;
4290
4291       // initialise the RGB components
4292       this.rgb =
4293           {
4294             'r' : (h + 120) / 60 % 6,
4295             'g' : h / 60,
4296             'b' : (h + 240) / 60 % 6
4297           };
4298
4299       // loop over the RGB components
4300       for (var key in this.rgb){
4301
4302         // ensure that the property is not inherited from the root object
4303         if (this.rgb.hasOwnProperty(key)){
4304
4305           // set the component to its value in the range [0,100]
4306           if (this.rgb[key] < 1){
4307             this.rgb[key] = q + (p - q) * this.rgb[key];
4308           }else if (this.rgb[key] < 3){
4309             this.rgb[key] = p;
4310           }else if (this.rgb[key] < 4){
4311             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4312           }else{
4313             this.rgb[key] = q;
4314           }
4315
4316           // set the component to its value in the range [0,255]
4317           this.rgb[key] *= 2.55;
4318
4319         }
4320
4321       }
4322
4323     }
4324
4325   },
4326
4327   /* Calculates and stores the HSV components of this HSLColor so that they can
4328    * be returned be the getHSL function.
4329    */
4330    calculateHSV : function(){
4331
4332     // set a temporary value
4333     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4334
4335     // store the HSV components
4336     this.hsv =
4337         {
4338           'h' : this.hsl.h,
4339           's' : 200 * t / (this.hsl.l + t),
4340           'v' : t + this.hsl.l
4341         };
4342
4343     // correct a division-by-zero error
4344     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4345
4346   }
4347  
4348
4349 });
4350 /*
4351  * Portions of this file are based on pieces of Yahoo User Interface Library
4352  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4353  * YUI licensed under the BSD License:
4354  * http://developer.yahoo.net/yui/license.txt
4355  * <script type="text/javascript">
4356  *
4357  */
4358 (function() {
4359
4360     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4361         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4362     };
4363
4364     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4365
4366     var fly = Roo.lib.AnimBase.fly;
4367     var Y = Roo.lib;
4368     var superclass = Y.ColorAnim.superclass;
4369     var proto = Y.ColorAnim.prototype;
4370
4371     proto.toString = function() {
4372         var el = this.getEl();
4373         var id = el.id || el.tagName;
4374         return ("ColorAnim " + id);
4375     };
4376
4377     proto.patterns.color = /color$/i;
4378     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4379     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4380     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4381     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4382
4383
4384     proto.parseColor = function(s) {
4385         if (s.length == 3) {
4386             return s;
4387         }
4388
4389         var c = this.patterns.hex.exec(s);
4390         if (c && c.length == 4) {
4391             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4392         }
4393
4394         c = this.patterns.rgb.exec(s);
4395         if (c && c.length == 4) {
4396             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4397         }
4398
4399         c = this.patterns.hex3.exec(s);
4400         if (c && c.length == 4) {
4401             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4402         }
4403
4404         return null;
4405     };
4406     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4407     proto.getAttribute = function(attr) {
4408         var el = this.getEl();
4409         if (this.patterns.color.test(attr)) {
4410             var val = fly(el).getStyle(attr);
4411
4412             if (this.patterns.transparent.test(val)) {
4413                 var parent = el.parentNode;
4414                 val = fly(parent).getStyle(attr);
4415
4416                 while (parent && this.patterns.transparent.test(val)) {
4417                     parent = parent.parentNode;
4418                     val = fly(parent).getStyle(attr);
4419                     if (parent.tagName.toUpperCase() == 'HTML') {
4420                         val = '#fff';
4421                     }
4422                 }
4423             }
4424         } else {
4425             val = superclass.getAttribute.call(this, attr);
4426         }
4427
4428         return val;
4429     };
4430     proto.getAttribute = function(attr) {
4431         var el = this.getEl();
4432         if (this.patterns.color.test(attr)) {
4433             var val = fly(el).getStyle(attr);
4434
4435             if (this.patterns.transparent.test(val)) {
4436                 var parent = el.parentNode;
4437                 val = fly(parent).getStyle(attr);
4438
4439                 while (parent && this.patterns.transparent.test(val)) {
4440                     parent = parent.parentNode;
4441                     val = fly(parent).getStyle(attr);
4442                     if (parent.tagName.toUpperCase() == 'HTML') {
4443                         val = '#fff';
4444                     }
4445                 }
4446             }
4447         } else {
4448             val = superclass.getAttribute.call(this, attr);
4449         }
4450
4451         return val;
4452     };
4453
4454     proto.doMethod = function(attr, start, end) {
4455         var val;
4456
4457         if (this.patterns.color.test(attr)) {
4458             val = [];
4459             for (var i = 0, len = start.length; i < len; ++i) {
4460                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4461             }
4462
4463             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4464         }
4465         else {
4466             val = superclass.doMethod.call(this, attr, start, end);
4467         }
4468
4469         return val;
4470     };
4471
4472     proto.setRuntimeAttribute = function(attr) {
4473         superclass.setRuntimeAttribute.call(this, attr);
4474
4475         if (this.patterns.color.test(attr)) {
4476             var attributes = this.attributes;
4477             var start = this.parseColor(this.runtimeAttributes[attr].start);
4478             var end = this.parseColor(this.runtimeAttributes[attr].end);
4479
4480             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4481                 end = this.parseColor(attributes[attr].by);
4482
4483                 for (var i = 0, len = start.length; i < len; ++i) {
4484                     end[i] = start[i] + end[i];
4485                 }
4486             }
4487
4488             this.runtimeAttributes[attr].start = start;
4489             this.runtimeAttributes[attr].end = end;
4490         }
4491     };
4492 })();
4493
4494 /*
4495  * Portions of this file are based on pieces of Yahoo User Interface Library
4496  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4497  * YUI licensed under the BSD License:
4498  * http://developer.yahoo.net/yui/license.txt
4499  * <script type="text/javascript">
4500  *
4501  */
4502 Roo.lib.Easing = {
4503
4504
4505     easeNone: function (t, b, c, d) {
4506         return c * t / d + b;
4507     },
4508
4509
4510     easeIn: function (t, b, c, d) {
4511         return c * (t /= d) * t + b;
4512     },
4513
4514
4515     easeOut: function (t, b, c, d) {
4516         return -c * (t /= d) * (t - 2) + b;
4517     },
4518
4519
4520     easeBoth: function (t, b, c, d) {
4521         if ((t /= d / 2) < 1) {
4522             return c / 2 * t * t + b;
4523         }
4524
4525         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4526     },
4527
4528
4529     easeInStrong: function (t, b, c, d) {
4530         return c * (t /= d) * t * t * t + b;
4531     },
4532
4533
4534     easeOutStrong: function (t, b, c, d) {
4535         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4536     },
4537
4538
4539     easeBothStrong: function (t, b, c, d) {
4540         if ((t /= d / 2) < 1) {
4541             return c / 2 * t * t * t * t + b;
4542         }
4543
4544         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4545     },
4546
4547
4548
4549     elasticIn: function (t, b, c, d, a, p) {
4550         if (t == 0) {
4551             return b;
4552         }
4553         if ((t /= d) == 1) {
4554             return b + c;
4555         }
4556         if (!p) {
4557             p = d * .3;
4558         }
4559
4560         if (!a || a < Math.abs(c)) {
4561             a = c;
4562             var s = p / 4;
4563         }
4564         else {
4565             var s = p / (2 * Math.PI) * Math.asin(c / a);
4566         }
4567
4568         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4569     },
4570
4571
4572     elasticOut: function (t, b, c, d, a, p) {
4573         if (t == 0) {
4574             return b;
4575         }
4576         if ((t /= d) == 1) {
4577             return b + c;
4578         }
4579         if (!p) {
4580             p = d * .3;
4581         }
4582
4583         if (!a || a < Math.abs(c)) {
4584             a = c;
4585             var s = p / 4;
4586         }
4587         else {
4588             var s = p / (2 * Math.PI) * Math.asin(c / a);
4589         }
4590
4591         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4592     },
4593
4594
4595     elasticBoth: function (t, b, c, d, a, p) {
4596         if (t == 0) {
4597             return b;
4598         }
4599
4600         if ((t /= d / 2) == 2) {
4601             return b + c;
4602         }
4603
4604         if (!p) {
4605             p = d * (.3 * 1.5);
4606         }
4607
4608         if (!a || a < Math.abs(c)) {
4609             a = c;
4610             var s = p / 4;
4611         }
4612         else {
4613             var s = p / (2 * Math.PI) * Math.asin(c / a);
4614         }
4615
4616         if (t < 1) {
4617             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4618                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4619         }
4620         return a * Math.pow(2, -10 * (t -= 1)) *
4621                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4622     },
4623
4624
4625
4626     backIn: function (t, b, c, d, s) {
4627         if (typeof s == 'undefined') {
4628             s = 1.70158;
4629         }
4630         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4631     },
4632
4633
4634     backOut: function (t, b, c, d, s) {
4635         if (typeof s == 'undefined') {
4636             s = 1.70158;
4637         }
4638         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4639     },
4640
4641
4642     backBoth: function (t, b, c, d, s) {
4643         if (typeof s == 'undefined') {
4644             s = 1.70158;
4645         }
4646
4647         if ((t /= d / 2 ) < 1) {
4648             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4649         }
4650         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4651     },
4652
4653
4654     bounceIn: function (t, b, c, d) {
4655         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4656     },
4657
4658
4659     bounceOut: function (t, b, c, d) {
4660         if ((t /= d) < (1 / 2.75)) {
4661             return c * (7.5625 * t * t) + b;
4662         } else if (t < (2 / 2.75)) {
4663             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4664         } else if (t < (2.5 / 2.75)) {
4665             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4666         }
4667         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4668     },
4669
4670
4671     bounceBoth: function (t, b, c, d) {
4672         if (t < d / 2) {
4673             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4674         }
4675         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4676     }
4677 };/*
4678  * Portions of this file are based on pieces of Yahoo User Interface Library
4679  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4680  * YUI licensed under the BSD License:
4681  * http://developer.yahoo.net/yui/license.txt
4682  * <script type="text/javascript">
4683  *
4684  */
4685     (function() {
4686         Roo.lib.Motion = function(el, attributes, duration, method) {
4687             if (el) {
4688                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4689             }
4690         };
4691
4692         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4693
4694
4695         var Y = Roo.lib;
4696         var superclass = Y.Motion.superclass;
4697         var proto = Y.Motion.prototype;
4698
4699         proto.toString = function() {
4700             var el = this.getEl();
4701             var id = el.id || el.tagName;
4702             return ("Motion " + id);
4703         };
4704
4705         proto.patterns.points = /^points$/i;
4706
4707         proto.setAttribute = function(attr, val, unit) {
4708             if (this.patterns.points.test(attr)) {
4709                 unit = unit || 'px';
4710                 superclass.setAttribute.call(this, 'left', val[0], unit);
4711                 superclass.setAttribute.call(this, 'top', val[1], unit);
4712             } else {
4713                 superclass.setAttribute.call(this, attr, val, unit);
4714             }
4715         };
4716
4717         proto.getAttribute = function(attr) {
4718             if (this.patterns.points.test(attr)) {
4719                 var val = [
4720                         superclass.getAttribute.call(this, 'left'),
4721                         superclass.getAttribute.call(this, 'top')
4722                         ];
4723             } else {
4724                 val = superclass.getAttribute.call(this, attr);
4725             }
4726
4727             return val;
4728         };
4729
4730         proto.doMethod = function(attr, start, end) {
4731             var val = null;
4732
4733             if (this.patterns.points.test(attr)) {
4734                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4735                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4736             } else {
4737                 val = superclass.doMethod.call(this, attr, start, end);
4738             }
4739             return val;
4740         };
4741
4742         proto.setRuntimeAttribute = function(attr) {
4743             if (this.patterns.points.test(attr)) {
4744                 var el = this.getEl();
4745                 var attributes = this.attributes;
4746                 var start;
4747                 var control = attributes['points']['control'] || [];
4748                 var end;
4749                 var i, len;
4750
4751                 if (control.length > 0 && !(control[0] instanceof Array)) {
4752                     control = [control];
4753                 } else {
4754                     var tmp = [];
4755                     for (i = 0,len = control.length; i < len; ++i) {
4756                         tmp[i] = control[i];
4757                     }
4758                     control = tmp;
4759                 }
4760
4761                 Roo.fly(el).position();
4762
4763                 if (isset(attributes['points']['from'])) {
4764                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4765                 }
4766                 else {
4767                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4768                 }
4769
4770                 start = this.getAttribute('points');
4771
4772
4773                 if (isset(attributes['points']['to'])) {
4774                     end = translateValues.call(this, attributes['points']['to'], start);
4775
4776                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4777                     for (i = 0,len = control.length; i < len; ++i) {
4778                         control[i] = translateValues.call(this, control[i], start);
4779                     }
4780
4781
4782                 } else if (isset(attributes['points']['by'])) {
4783                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4784
4785                     for (i = 0,len = control.length; i < len; ++i) {
4786                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4787                     }
4788                 }
4789
4790                 this.runtimeAttributes[attr] = [start];
4791
4792                 if (control.length > 0) {
4793                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4794                 }
4795
4796                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4797             }
4798             else {
4799                 superclass.setRuntimeAttribute.call(this, attr);
4800             }
4801         };
4802
4803         var translateValues = function(val, start) {
4804             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4805             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4806
4807             return val;
4808         };
4809
4810         var isset = function(prop) {
4811             return (typeof prop !== 'undefined');
4812         };
4813     })();
4814 /*
4815  * Portions of this file are based on pieces of Yahoo User Interface Library
4816  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4817  * YUI licensed under the BSD License:
4818  * http://developer.yahoo.net/yui/license.txt
4819  * <script type="text/javascript">
4820  *
4821  */
4822     (function() {
4823         Roo.lib.Scroll = function(el, attributes, duration, method) {
4824             if (el) {
4825                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4826             }
4827         };
4828
4829         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4830
4831
4832         var Y = Roo.lib;
4833         var superclass = Y.Scroll.superclass;
4834         var proto = Y.Scroll.prototype;
4835
4836         proto.toString = function() {
4837             var el = this.getEl();
4838             var id = el.id || el.tagName;
4839             return ("Scroll " + id);
4840         };
4841
4842         proto.doMethod = function(attr, start, end) {
4843             var val = null;
4844
4845             if (attr == 'scroll') {
4846                 val = [
4847                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4848                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4849                         ];
4850
4851             } else {
4852                 val = superclass.doMethod.call(this, attr, start, end);
4853             }
4854             return val;
4855         };
4856
4857         proto.getAttribute = function(attr) {
4858             var val = null;
4859             var el = this.getEl();
4860
4861             if (attr == 'scroll') {
4862                 val = [ el.scrollLeft, el.scrollTop ];
4863             } else {
4864                 val = superclass.getAttribute.call(this, attr);
4865             }
4866
4867             return val;
4868         };
4869
4870         proto.setAttribute = function(attr, val, unit) {
4871             var el = this.getEl();
4872
4873             if (attr == 'scroll') {
4874                 el.scrollLeft = val[0];
4875                 el.scrollTop = val[1];
4876             } else {
4877                 superclass.setAttribute.call(this, attr, val, unit);
4878             }
4879         };
4880     })();
4881 /*
4882  * Based on:
4883  * Ext JS Library 1.1.1
4884  * Copyright(c) 2006-2007, Ext JS, LLC.
4885  *
4886  * Originally Released Under LGPL - original licence link has changed is not relivant.
4887  *
4888  * Fork - LGPL
4889  * <script type="text/javascript">
4890  */
4891
4892
4893 // nasty IE9 hack - what a pile of crap that is..
4894
4895  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4896     Range.prototype.createContextualFragment = function (html) {
4897         var doc = window.document;
4898         var container = doc.createElement("div");
4899         container.innerHTML = html;
4900         var frag = doc.createDocumentFragment(), n;
4901         while ((n = container.firstChild)) {
4902             frag.appendChild(n);
4903         }
4904         return frag;
4905     };
4906 }
4907
4908 /**
4909  * @class Roo.DomHelper
4910  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4911  * 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>.
4912  * @static
4913  */
4914 Roo.DomHelper = function(){
4915     var tempTableEl = null;
4916     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4917     var tableRe = /^table|tbody|tr|td$/i;
4918     var xmlns = {};
4919     // build as innerHTML where available
4920     /** @ignore */
4921     var createHtml = function(o){
4922         if(typeof o == 'string'){
4923             return o;
4924         }
4925         var b = "";
4926         if(!o.tag){
4927             o.tag = "div";
4928         }
4929         b += "<" + o.tag;
4930         for(var attr in o){
4931             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4932             if(attr == "style"){
4933                 var s = o["style"];
4934                 if(typeof s == "function"){
4935                     s = s.call();
4936                 }
4937                 if(typeof s == "string"){
4938                     b += ' style="' + s + '"';
4939                 }else if(typeof s == "object"){
4940                     b += ' style="';
4941                     for(var key in s){
4942                         if(typeof s[key] != "function"){
4943                             b += key + ":" + s[key] + ";";
4944                         }
4945                     }
4946                     b += '"';
4947                 }
4948             }else{
4949                 if(attr == "cls"){
4950                     b += ' class="' + o["cls"] + '"';
4951                 }else if(attr == "htmlFor"){
4952                     b += ' for="' + o["htmlFor"] + '"';
4953                 }else{
4954                     b += " " + attr + '="' + o[attr] + '"';
4955                 }
4956             }
4957         }
4958         if(emptyTags.test(o.tag)){
4959             b += "/>";
4960         }else{
4961             b += ">";
4962             var cn = o.children || o.cn;
4963             if(cn){
4964                 //http://bugs.kde.org/show_bug.cgi?id=71506
4965                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4966                     for(var i = 0, len = cn.length; i < len; i++) {
4967                         b += createHtml(cn[i], b);
4968                     }
4969                 }else{
4970                     b += createHtml(cn, b);
4971                 }
4972             }
4973             if(o.html){
4974                 b += o.html;
4975             }
4976             b += "</" + o.tag + ">";
4977         }
4978         return b;
4979     };
4980
4981     // build as dom
4982     /** @ignore */
4983     var createDom = function(o, parentNode){
4984          
4985         // defininition craeted..
4986         var ns = false;
4987         if (o.ns && o.ns != 'html') {
4988                
4989             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4990                 xmlns[o.ns] = o.xmlns;
4991                 ns = o.xmlns;
4992             }
4993             if (typeof(xmlns[o.ns]) == 'undefined') {
4994                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4995             }
4996             ns = xmlns[o.ns];
4997         }
4998         
4999         
5000         if (typeof(o) == 'string') {
5001             return parentNode.appendChild(document.createTextNode(o));
5002         }
5003         o.tag = o.tag || div;
5004         if (o.ns && Roo.isIE) {
5005             ns = false;
5006             o.tag = o.ns + ':' + o.tag;
5007             
5008         }
5009         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5010         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5011         for(var attr in o){
5012             
5013             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5014                     attr == "style" || typeof o[attr] == "function") { continue; }
5015                     
5016             if(attr=="cls" && Roo.isIE){
5017                 el.className = o["cls"];
5018             }else{
5019                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5020                 else { 
5021                     el[attr] = o[attr];
5022                 }
5023             }
5024         }
5025         Roo.DomHelper.applyStyles(el, o.style);
5026         var cn = o.children || o.cn;
5027         if(cn){
5028             //http://bugs.kde.org/show_bug.cgi?id=71506
5029              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5030                 for(var i = 0, len = cn.length; i < len; i++) {
5031                     createDom(cn[i], el);
5032                 }
5033             }else{
5034                 createDom(cn, el);
5035             }
5036         }
5037         if(o.html){
5038             el.innerHTML = o.html;
5039         }
5040         if(parentNode){
5041            parentNode.appendChild(el);
5042         }
5043         return el;
5044     };
5045
5046     var ieTable = function(depth, s, h, e){
5047         tempTableEl.innerHTML = [s, h, e].join('');
5048         var i = -1, el = tempTableEl;
5049         while(++i < depth && el.firstChild){
5050             el = el.firstChild;
5051         }
5052         return el;
5053     };
5054
5055     // kill repeat to save bytes
5056     var ts = '<table>',
5057         te = '</table>',
5058         tbs = ts+'<tbody>',
5059         tbe = '</tbody>'+te,
5060         trs = tbs + '<tr>',
5061         tre = '</tr>'+tbe;
5062
5063     /**
5064      * @ignore
5065      * Nasty code for IE's broken table implementation
5066      */
5067     var insertIntoTable = function(tag, where, el, html){
5068         if(!tempTableEl){
5069             tempTableEl = document.createElement('div');
5070         }
5071         var node;
5072         var before = null;
5073         if(tag == 'td'){
5074             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5075                 return;
5076             }
5077             if(where == 'beforebegin'){
5078                 before = el;
5079                 el = el.parentNode;
5080             } else{
5081                 before = el.nextSibling;
5082                 el = el.parentNode;
5083             }
5084             node = ieTable(4, trs, html, tre);
5085         }
5086         else if(tag == 'tr'){
5087             if(where == 'beforebegin'){
5088                 before = el;
5089                 el = el.parentNode;
5090                 node = ieTable(3, tbs, html, tbe);
5091             } else if(where == 'afterend'){
5092                 before = el.nextSibling;
5093                 el = el.parentNode;
5094                 node = ieTable(3, tbs, html, tbe);
5095             } else{ // INTO a TR
5096                 if(where == 'afterbegin'){
5097                     before = el.firstChild;
5098                 }
5099                 node = ieTable(4, trs, html, tre);
5100             }
5101         } else if(tag == 'tbody'){
5102             if(where == 'beforebegin'){
5103                 before = el;
5104                 el = el.parentNode;
5105                 node = ieTable(2, ts, html, te);
5106             } else if(where == 'afterend'){
5107                 before = el.nextSibling;
5108                 el = el.parentNode;
5109                 node = ieTable(2, ts, html, te);
5110             } else{
5111                 if(where == 'afterbegin'){
5112                     before = el.firstChild;
5113                 }
5114                 node = ieTable(3, tbs, html, tbe);
5115             }
5116         } else{ // TABLE
5117             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5118                 return;
5119             }
5120             if(where == 'afterbegin'){
5121                 before = el.firstChild;
5122             }
5123             node = ieTable(2, ts, html, te);
5124         }
5125         el.insertBefore(node, before);
5126         return node;
5127     };
5128
5129     return {
5130     /** True to force the use of DOM instead of html fragments @type Boolean */
5131     useDom : false,
5132
5133     /**
5134      * Returns the markup for the passed Element(s) config
5135      * @param {Object} o The Dom object spec (and children)
5136      * @return {String}
5137      */
5138     markup : function(o){
5139         return createHtml(o);
5140     },
5141
5142     /**
5143      * Applies a style specification to an element
5144      * @param {String/HTMLElement} el The element to apply styles to
5145      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5146      * a function which returns such a specification.
5147      */
5148     applyStyles : function(el, styles){
5149         if(styles){
5150            el = Roo.fly(el);
5151            if(typeof styles == "string"){
5152                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5153                var matches;
5154                while ((matches = re.exec(styles)) != null){
5155                    el.setStyle(matches[1], matches[2]);
5156                }
5157            }else if (typeof styles == "object"){
5158                for (var style in styles){
5159                   el.setStyle(style, styles[style]);
5160                }
5161            }else if (typeof styles == "function"){
5162                 Roo.DomHelper.applyStyles(el, styles.call());
5163            }
5164         }
5165     },
5166
5167     /**
5168      * Inserts an HTML fragment into the Dom
5169      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5170      * @param {HTMLElement} el The context element
5171      * @param {String} html The HTML fragmenet
5172      * @return {HTMLElement} The new node
5173      */
5174     insertHtml : function(where, el, html){
5175         where = where.toLowerCase();
5176         if(el.insertAdjacentHTML){
5177             if(tableRe.test(el.tagName)){
5178                 var rs;
5179                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5180                     return rs;
5181                 }
5182             }
5183             switch(where){
5184                 case "beforebegin":
5185                     el.insertAdjacentHTML('BeforeBegin', html);
5186                     return el.previousSibling;
5187                 case "afterbegin":
5188                     el.insertAdjacentHTML('AfterBegin', html);
5189                     return el.firstChild;
5190                 case "beforeend":
5191                     el.insertAdjacentHTML('BeforeEnd', html);
5192                     return el.lastChild;
5193                 case "afterend":
5194                     el.insertAdjacentHTML('AfterEnd', html);
5195                     return el.nextSibling;
5196             }
5197             throw 'Illegal insertion point -> "' + where + '"';
5198         }
5199         var range = el.ownerDocument.createRange();
5200         var frag;
5201         switch(where){
5202              case "beforebegin":
5203                 range.setStartBefore(el);
5204                 frag = range.createContextualFragment(html);
5205                 el.parentNode.insertBefore(frag, el);
5206                 return el.previousSibling;
5207              case "afterbegin":
5208                 if(el.firstChild){
5209                     range.setStartBefore(el.firstChild);
5210                     frag = range.createContextualFragment(html);
5211                     el.insertBefore(frag, el.firstChild);
5212                     return el.firstChild;
5213                 }else{
5214                     el.innerHTML = html;
5215                     return el.firstChild;
5216                 }
5217             case "beforeend":
5218                 if(el.lastChild){
5219                     range.setStartAfter(el.lastChild);
5220                     frag = range.createContextualFragment(html);
5221                     el.appendChild(frag);
5222                     return el.lastChild;
5223                 }else{
5224                     el.innerHTML = html;
5225                     return el.lastChild;
5226                 }
5227             case "afterend":
5228                 range.setStartAfter(el);
5229                 frag = range.createContextualFragment(html);
5230                 el.parentNode.insertBefore(frag, el.nextSibling);
5231                 return el.nextSibling;
5232             }
5233             throw 'Illegal insertion point -> "' + where + '"';
5234     },
5235
5236     /**
5237      * Creates new Dom element(s) and inserts them before el
5238      * @param {String/HTMLElement/Element} el The context element
5239      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5240      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5241      * @return {HTMLElement/Roo.Element} The new node
5242      */
5243     insertBefore : function(el, o, returnElement){
5244         return this.doInsert(el, o, returnElement, "beforeBegin");
5245     },
5246
5247     /**
5248      * Creates new Dom element(s) and inserts them after el
5249      * @param {String/HTMLElement/Element} el The context element
5250      * @param {Object} o The Dom object spec (and children)
5251      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5252      * @return {HTMLElement/Roo.Element} The new node
5253      */
5254     insertAfter : function(el, o, returnElement){
5255         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5256     },
5257
5258     /**
5259      * Creates new Dom element(s) and inserts them as the first child of el
5260      * @param {String/HTMLElement/Element} el The context element
5261      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5262      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5263      * @return {HTMLElement/Roo.Element} The new node
5264      */
5265     insertFirst : function(el, o, returnElement){
5266         return this.doInsert(el, o, returnElement, "afterBegin");
5267     },
5268
5269     // private
5270     doInsert : function(el, o, returnElement, pos, sibling){
5271         el = Roo.getDom(el);
5272         var newNode;
5273         if(this.useDom || o.ns){
5274             newNode = createDom(o, null);
5275             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5276         }else{
5277             var html = createHtml(o);
5278             newNode = this.insertHtml(pos, el, html);
5279         }
5280         return returnElement ? Roo.get(newNode, true) : newNode;
5281     },
5282
5283     /**
5284      * Creates new Dom element(s) and appends them to el
5285      * @param {String/HTMLElement/Element} el The context element
5286      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5287      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5288      * @return {HTMLElement/Roo.Element} The new node
5289      */
5290     append : function(el, o, returnElement){
5291         el = Roo.getDom(el);
5292         var newNode;
5293         if(this.useDom || o.ns){
5294             newNode = createDom(o, null);
5295             el.appendChild(newNode);
5296         }else{
5297             var html = createHtml(o);
5298             newNode = this.insertHtml("beforeEnd", el, html);
5299         }
5300         return returnElement ? Roo.get(newNode, true) : newNode;
5301     },
5302
5303     /**
5304      * Creates new Dom element(s) and overwrites the contents of el with them
5305      * @param {String/HTMLElement/Element} el The context element
5306      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5307      * @param {Boolean} returnElement (optional) true to return a Roo.Element
5308      * @return {HTMLElement/Roo.Element} The new node
5309      */
5310     overwrite : function(el, o, returnElement){
5311         el = Roo.getDom(el);
5312         if (o.ns) {
5313           
5314             while (el.childNodes.length) {
5315                 el.removeChild(el.firstChild);
5316             }
5317             createDom(o, el);
5318         } else {
5319             el.innerHTML = createHtml(o);   
5320         }
5321         
5322         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5323     },
5324
5325     /**
5326      * Creates a new Roo.DomHelper.Template from the Dom object spec
5327      * @param {Object} o The Dom object spec (and children)
5328      * @return {Roo.DomHelper.Template} The new template
5329      */
5330     createTemplate : function(o){
5331         var html = createHtml(o);
5332         return new Roo.Template(html);
5333     }
5334     };
5335 }();
5336 /*
5337  * Based on:
5338  * Ext JS Library 1.1.1
5339  * Copyright(c) 2006-2007, Ext JS, LLC.
5340  *
5341  * Originally Released Under LGPL - original licence link has changed is not relivant.
5342  *
5343  * Fork - LGPL
5344  * <script type="text/javascript">
5345  */
5346  
5347 /**
5348 * @class Roo.Template
5349 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5350 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5351 * Usage:
5352 <pre><code>
5353 var t = new Roo.Template({
5354     html :  '&lt;div name="{id}"&gt;' + 
5355         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5356         '&lt;/div&gt;',
5357     myformat: function (value, allValues) {
5358         return 'XX' + value;
5359     }
5360 });
5361 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5362 </code></pre>
5363 * For more information see this blog post with examples:
5364 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5365      - Create Elements using DOM, HTML fragments and Templates</a>. 
5366 * @constructor
5367 * @param {Object} cfg - Configuration object.
5368 */
5369 Roo.Template = function(cfg){
5370     // BC!
5371     if(cfg instanceof Array){
5372         cfg = cfg.join("");
5373     }else if(arguments.length > 1){
5374         cfg = Array.prototype.join.call(arguments, "");
5375     }
5376     
5377     
5378     if (typeof(cfg) == 'object') {
5379         Roo.apply(this,cfg)
5380     } else {
5381         // bc
5382         this.html = cfg;
5383     }
5384     if (this.url) {
5385         this.load();
5386     }
5387     
5388 };
5389 Roo.Template.prototype = {
5390     
5391     /**
5392      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5393      */
5394     onLoad : false,
5395     
5396     
5397     /**
5398      * @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..
5399      *                    it should be fixed so that template is observable...
5400      */
5401     url : false,
5402     /**
5403      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5404      */
5405     html : '',
5406     
5407     
5408     compiled : false,
5409     loaded : false,
5410     /**
5411      * Returns an HTML fragment of this template with the specified values applied.
5412      * @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'})
5413      * @return {String} The HTML fragment
5414      */
5415     
5416    
5417     
5418     applyTemplate : function(values){
5419         //Roo.log(["applyTemplate", values]);
5420         try {
5421            
5422             if(this.compiled){
5423                 return this.compiled(values);
5424             }
5425             var useF = this.disableFormats !== true;
5426             var fm = Roo.util.Format, tpl = this;
5427             var fn = function(m, name, format, args){
5428                 if(format && useF){
5429                     if(format.substr(0, 5) == "this."){
5430                         return tpl.call(format.substr(5), values[name], values);
5431                     }else{
5432                         if(args){
5433                             // quoted values are required for strings in compiled templates, 
5434                             // but for non compiled we need to strip them
5435                             // quoted reversed for jsmin
5436                             var re = /^\s*['"](.*)["']\s*$/;
5437                             args = args.split(',');
5438                             for(var i = 0, len = args.length; i < len; i++){
5439                                 args[i] = args[i].replace(re, "$1");
5440                             }
5441                             args = [values[name]].concat(args);
5442                         }else{
5443                             args = [values[name]];
5444                         }
5445                         return fm[format].apply(fm, args);
5446                     }
5447                 }else{
5448                     return values[name] !== undefined ? values[name] : "";
5449                 }
5450             };
5451             return this.html.replace(this.re, fn);
5452         } catch (e) {
5453             Roo.log(e);
5454             throw e;
5455         }
5456          
5457     },
5458     
5459     loading : false,
5460       
5461     load : function ()
5462     {
5463          
5464         if (this.loading) {
5465             return;
5466         }
5467         var _t = this;
5468         
5469         this.loading = true;
5470         this.compiled = false;
5471         
5472         var cx = new Roo.data.Connection();
5473         cx.request({
5474             url : this.url,
5475             method : 'GET',
5476             success : function (response) {
5477                 _t.loading = false;
5478                 _t.url = false;
5479                 
5480                 _t.set(response.responseText,true);
5481                 _t.loaded = true;
5482                 if (_t.onLoad) {
5483                     _t.onLoad();
5484                 }
5485              },
5486             failure : function(response) {
5487                 Roo.log("Template failed to load from " + _t.url);
5488                 _t.loading = false;
5489             }
5490         });
5491     },
5492
5493     /**
5494      * Sets the HTML used as the template and optionally compiles it.
5495      * @param {String} html
5496      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5497      * @return {Roo.Template} this
5498      */
5499     set : function(html, compile){
5500         this.html = html;
5501         this.compiled = false;
5502         if(compile){
5503             this.compile();
5504         }
5505         return this;
5506     },
5507     
5508     /**
5509      * True to disable format functions (defaults to false)
5510      * @type Boolean
5511      */
5512     disableFormats : false,
5513     
5514     /**
5515     * The regular expression used to match template variables 
5516     * @type RegExp
5517     * @property 
5518     */
5519     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5520     
5521     /**
5522      * Compiles the template into an internal function, eliminating the RegEx overhead.
5523      * @return {Roo.Template} this
5524      */
5525     compile : function(){
5526         var fm = Roo.util.Format;
5527         var useF = this.disableFormats !== true;
5528         var sep = Roo.isGecko ? "+" : ",";
5529         var fn = function(m, name, format, args){
5530             if(format && useF){
5531                 args = args ? ',' + args : "";
5532                 if(format.substr(0, 5) != "this."){
5533                     format = "fm." + format + '(';
5534                 }else{
5535                     format = 'this.call("'+ format.substr(5) + '", ';
5536                     args = ", values";
5537                 }
5538             }else{
5539                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5540             }
5541             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5542         };
5543         var body;
5544         // branched to use + in gecko and [].join() in others
5545         if(Roo.isGecko){
5546             body = "this.compiled = function(values){ return '" +
5547                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5548                     "';};";
5549         }else{
5550             body = ["this.compiled = function(values){ return ['"];
5551             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5552             body.push("'].join('');};");
5553             body = body.join('');
5554         }
5555         /**
5556          * eval:var:values
5557          * eval:var:fm
5558          */
5559         eval(body);
5560         return this;
5561     },
5562     
5563     // private function used to call members
5564     call : function(fnName, value, allValues){
5565         return this[fnName](value, allValues);
5566     },
5567     
5568     /**
5569      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5570      * @param {String/HTMLElement/Roo.Element} el The context element
5571      * @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'})
5572      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5573      * @return {HTMLElement/Roo.Element} The new node or Element
5574      */
5575     insertFirst: function(el, values, returnElement){
5576         return this.doInsert('afterBegin', el, values, returnElement);
5577     },
5578
5579     /**
5580      * Applies the supplied values to the template and inserts the new node(s) before el.
5581      * @param {String/HTMLElement/Roo.Element} el The context element
5582      * @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'})
5583      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5584      * @return {HTMLElement/Roo.Element} The new node or Element
5585      */
5586     insertBefore: function(el, values, returnElement){
5587         return this.doInsert('beforeBegin', el, values, returnElement);
5588     },
5589
5590     /**
5591      * Applies the supplied values to the template and inserts the new node(s) after el.
5592      * @param {String/HTMLElement/Roo.Element} el The context element
5593      * @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'})
5594      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5595      * @return {HTMLElement/Roo.Element} The new node or Element
5596      */
5597     insertAfter : function(el, values, returnElement){
5598         return this.doInsert('afterEnd', el, values, returnElement);
5599     },
5600     
5601     /**
5602      * Applies the supplied values to the template and appends the new node(s) to el.
5603      * @param {String/HTMLElement/Roo.Element} el The context element
5604      * @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'})
5605      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5606      * @return {HTMLElement/Roo.Element} The new node or Element
5607      */
5608     append : function(el, values, returnElement){
5609         return this.doInsert('beforeEnd', el, values, returnElement);
5610     },
5611
5612     doInsert : function(where, el, values, returnEl){
5613         el = Roo.getDom(el);
5614         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5615         return returnEl ? Roo.get(newNode, true) : newNode;
5616     },
5617
5618     /**
5619      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5620      * @param {String/HTMLElement/Roo.Element} el The context element
5621      * @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'})
5622      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5623      * @return {HTMLElement/Roo.Element} The new node or Element
5624      */
5625     overwrite : function(el, values, returnElement){
5626         el = Roo.getDom(el);
5627         el.innerHTML = this.applyTemplate(values);
5628         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5629     }
5630 };
5631 /**
5632  * Alias for {@link #applyTemplate}
5633  * @method
5634  */
5635 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5636
5637 // backwards compat
5638 Roo.DomHelper.Template = Roo.Template;
5639
5640 /**
5641  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5642  * @param {String/HTMLElement} el A DOM element or its id
5643  * @returns {Roo.Template} The created template
5644  * @static
5645  */
5646 Roo.Template.from = function(el){
5647     el = Roo.getDom(el);
5648     return new Roo.Template(el.value || el.innerHTML);
5649 };/*
5650  * Based on:
5651  * Ext JS Library 1.1.1
5652  * Copyright(c) 2006-2007, Ext JS, LLC.
5653  *
5654  * Originally Released Under LGPL - original licence link has changed is not relivant.
5655  *
5656  * Fork - LGPL
5657  * <script type="text/javascript">
5658  */
5659  
5660
5661 /*
5662  * This is code is also distributed under MIT license for use
5663  * with jQuery and prototype JavaScript libraries.
5664  */
5665 /**
5666  * @class Roo.DomQuery
5667 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).
5668 <p>
5669 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>
5670
5671 <p>
5672 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.
5673 </p>
5674 <h4>Element Selectors:</h4>
5675 <ul class="list">
5676     <li> <b>*</b> any element</li>
5677     <li> <b>E</b> an element with the tag E</li>
5678     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5679     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5680     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5681     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5682 </ul>
5683 <h4>Attribute Selectors:</h4>
5684 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5685 <ul class="list">
5686     <li> <b>E[foo]</b> has an attribute "foo"</li>
5687     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5688     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5689     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5690     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5691     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5692     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5693 </ul>
5694 <h4>Pseudo Classes:</h4>
5695 <ul class="list">
5696     <li> <b>E:first-child</b> E is the first child of its parent</li>
5697     <li> <b>E:last-child</b> E is the last child of its parent</li>
5698     <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>
5699     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5700     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5701     <li> <b>E:only-child</b> E is the only child of its parent</li>
5702     <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>
5703     <li> <b>E:first</b> the first E in the resultset</li>
5704     <li> <b>E:last</b> the last E in the resultset</li>
5705     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5706     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5707     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5708     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5709     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5710     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5711     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5712     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5713     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5714 </ul>
5715 <h4>CSS Value Selectors:</h4>
5716 <ul class="list">
5717     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5718     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5719     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5720     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5721     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5722     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5723 </ul>
5724  * @static
5725  */
5726 Roo.DomQuery = function(){
5727     var cache = {}, simpleCache = {}, valueCache = {};
5728     var nonSpace = /\S/;
5729     var trimRe = /^\s+|\s+$/g;
5730     var tplRe = /\{(\d+)\}/g;
5731     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5732     var tagTokenRe = /^(#)?([\w-\*]+)/;
5733     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5734
5735     function child(p, index){
5736         var i = 0;
5737         var n = p.firstChild;
5738         while(n){
5739             if(n.nodeType == 1){
5740                if(++i == index){
5741                    return n;
5742                }
5743             }
5744             n = n.nextSibling;
5745         }
5746         return null;
5747     };
5748
5749     function next(n){
5750         while((n = n.nextSibling) && n.nodeType != 1);
5751         return n;
5752     };
5753
5754     function prev(n){
5755         while((n = n.previousSibling) && n.nodeType != 1);
5756         return n;
5757     };
5758
5759     function children(d){
5760         var n = d.firstChild, ni = -1;
5761             while(n){
5762                 var nx = n.nextSibling;
5763                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5764                     d.removeChild(n);
5765                 }else{
5766                     n.nodeIndex = ++ni;
5767                 }
5768                 n = nx;
5769             }
5770             return this;
5771         };
5772
5773     function byClassName(c, a, v){
5774         if(!v){
5775             return c;
5776         }
5777         var r = [], ri = -1, cn;
5778         for(var i = 0, ci; ci = c[i]; i++){
5779             
5780             
5781             if((' '+
5782                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5783                  +' ').indexOf(v) != -1){
5784                 r[++ri] = ci;
5785             }
5786         }
5787         return r;
5788     };
5789
5790     function attrValue(n, attr){
5791         if(!n.tagName && typeof n.length != "undefined"){
5792             n = n[0];
5793         }
5794         if(!n){
5795             return null;
5796         }
5797         if(attr == "for"){
5798             return n.htmlFor;
5799         }
5800         if(attr == "class" || attr == "className"){
5801             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5802         }
5803         return n.getAttribute(attr) || n[attr];
5804
5805     };
5806
5807     function getNodes(ns, mode, tagName){
5808         var result = [], ri = -1, cs;
5809         if(!ns){
5810             return result;
5811         }
5812         tagName = tagName || "*";
5813         if(typeof ns.getElementsByTagName != "undefined"){
5814             ns = [ns];
5815         }
5816         if(!mode){
5817             for(var i = 0, ni; ni = ns[i]; i++){
5818                 cs = ni.getElementsByTagName(tagName);
5819                 for(var j = 0, ci; ci = cs[j]; j++){
5820                     result[++ri] = ci;
5821                 }
5822             }
5823         }else if(mode == "/" || mode == ">"){
5824             var utag = tagName.toUpperCase();
5825             for(var i = 0, ni, cn; ni = ns[i]; i++){
5826                 cn = ni.children || ni.childNodes;
5827                 for(var j = 0, cj; cj = cn[j]; j++){
5828                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5829                         result[++ri] = cj;
5830                     }
5831                 }
5832             }
5833         }else if(mode == "+"){
5834             var utag = tagName.toUpperCase();
5835             for(var i = 0, n; n = ns[i]; i++){
5836                 while((n = n.nextSibling) && n.nodeType != 1);
5837                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5838                     result[++ri] = n;
5839                 }
5840             }
5841         }else if(mode == "~"){
5842             for(var i = 0, n; n = ns[i]; i++){
5843                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5844                 if(n){
5845                     result[++ri] = n;
5846                 }
5847             }
5848         }
5849         return result;
5850     };
5851
5852     function concat(a, b){
5853         if(b.slice){
5854             return a.concat(b);
5855         }
5856         for(var i = 0, l = b.length; i < l; i++){
5857             a[a.length] = b[i];
5858         }
5859         return a;
5860     }
5861
5862     function byTag(cs, tagName){
5863         if(cs.tagName || cs == document){
5864             cs = [cs];
5865         }
5866         if(!tagName){
5867             return cs;
5868         }
5869         var r = [], ri = -1;
5870         tagName = tagName.toLowerCase();
5871         for(var i = 0, ci; ci = cs[i]; i++){
5872             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5873                 r[++ri] = ci;
5874             }
5875         }
5876         return r;
5877     };
5878
5879     function byId(cs, attr, id){
5880         if(cs.tagName || cs == document){
5881             cs = [cs];
5882         }
5883         if(!id){
5884             return cs;
5885         }
5886         var r = [], ri = -1;
5887         for(var i = 0,ci; ci = cs[i]; i++){
5888             if(ci && ci.id == id){
5889                 r[++ri] = ci;
5890                 return r;
5891             }
5892         }
5893         return r;
5894     };
5895
5896     function byAttribute(cs, attr, value, op, custom){
5897         var r = [], ri = -1, st = custom=="{";
5898         var f = Roo.DomQuery.operators[op];
5899         for(var i = 0, ci; ci = cs[i]; i++){
5900             var a;
5901             if(st){
5902                 a = Roo.DomQuery.getStyle(ci, attr);
5903             }
5904             else if(attr == "class" || attr == "className"){
5905                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
5906             }else if(attr == "for"){
5907                 a = ci.htmlFor;
5908             }else if(attr == "href"){
5909                 a = ci.getAttribute("href", 2);
5910             }else{
5911                 a = ci.getAttribute(attr);
5912             }
5913             if((f && f(a, value)) || (!f && a)){
5914                 r[++ri] = ci;
5915             }
5916         }
5917         return r;
5918     };
5919
5920     function byPseudo(cs, name, value){
5921         return Roo.DomQuery.pseudos[name](cs, value);
5922     };
5923
5924     // This is for IE MSXML which does not support expandos.
5925     // IE runs the same speed using setAttribute, however FF slows way down
5926     // and Safari completely fails so they need to continue to use expandos.
5927     var isIE = window.ActiveXObject ? true : false;
5928
5929     // this eval is stop the compressor from
5930     // renaming the variable to something shorter
5931     
5932     /** eval:var:batch */
5933     var batch = 30803; 
5934
5935     var key = 30803;
5936
5937     function nodupIEXml(cs){
5938         var d = ++key;
5939         cs[0].setAttribute("_nodup", d);
5940         var r = [cs[0]];
5941         for(var i = 1, len = cs.length; i < len; i++){
5942             var c = cs[i];
5943             if(!c.getAttribute("_nodup") != d){
5944                 c.setAttribute("_nodup", d);
5945                 r[r.length] = c;
5946             }
5947         }
5948         for(var i = 0, len = cs.length; i < len; i++){
5949             cs[i].removeAttribute("_nodup");
5950         }
5951         return r;
5952     }
5953
5954     function nodup(cs){
5955         if(!cs){
5956             return [];
5957         }
5958         var len = cs.length, c, i, r = cs, cj, ri = -1;
5959         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5960             return cs;
5961         }
5962         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5963             return nodupIEXml(cs);
5964         }
5965         var d = ++key;
5966         cs[0]._nodup = d;
5967         for(i = 1; c = cs[i]; i++){
5968             if(c._nodup != d){
5969                 c._nodup = d;
5970             }else{
5971                 r = [];
5972                 for(var j = 0; j < i; j++){
5973                     r[++ri] = cs[j];
5974                 }
5975                 for(j = i+1; cj = cs[j]; j++){
5976                     if(cj._nodup != d){
5977                         cj._nodup = d;
5978                         r[++ri] = cj;
5979                     }
5980                 }
5981                 return r;
5982             }
5983         }
5984         return r;
5985     }
5986
5987     function quickDiffIEXml(c1, c2){
5988         var d = ++key;
5989         for(var i = 0, len = c1.length; i < len; i++){
5990             c1[i].setAttribute("_qdiff", d);
5991         }
5992         var r = [];
5993         for(var i = 0, len = c2.length; i < len; i++){
5994             if(c2[i].getAttribute("_qdiff") != d){
5995                 r[r.length] = c2[i];
5996             }
5997         }
5998         for(var i = 0, len = c1.length; i < len; i++){
5999            c1[i].removeAttribute("_qdiff");
6000         }
6001         return r;
6002     }
6003
6004     function quickDiff(c1, c2){
6005         var len1 = c1.length;
6006         if(!len1){
6007             return c2;
6008         }
6009         if(isIE && c1[0].selectSingleNode){
6010             return quickDiffIEXml(c1, c2);
6011         }
6012         var d = ++key;
6013         for(var i = 0; i < len1; i++){
6014             c1[i]._qdiff = d;
6015         }
6016         var r = [];
6017         for(var i = 0, len = c2.length; i < len; i++){
6018             if(c2[i]._qdiff != d){
6019                 r[r.length] = c2[i];
6020             }
6021         }
6022         return r;
6023     }
6024
6025     function quickId(ns, mode, root, id){
6026         if(ns == root){
6027            var d = root.ownerDocument || root;
6028            return d.getElementById(id);
6029         }
6030         ns = getNodes(ns, mode, "*");
6031         return byId(ns, null, id);
6032     }
6033
6034     return {
6035         getStyle : function(el, name){
6036             return Roo.fly(el).getStyle(name);
6037         },
6038         /**
6039          * Compiles a selector/xpath query into a reusable function. The returned function
6040          * takes one parameter "root" (optional), which is the context node from where the query should start.
6041          * @param {String} selector The selector/xpath query
6042          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6043          * @return {Function}
6044          */
6045         compile : function(path, type){
6046             type = type || "select";
6047             
6048             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6049             var q = path, mode, lq;
6050             var tk = Roo.DomQuery.matchers;
6051             var tklen = tk.length;
6052             var mm;
6053
6054             // accept leading mode switch
6055             var lmode = q.match(modeRe);
6056             if(lmode && lmode[1]){
6057                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6058                 q = q.replace(lmode[1], "");
6059             }
6060             // strip leading slashes
6061             while(path.substr(0, 1)=="/"){
6062                 path = path.substr(1);
6063             }
6064
6065             while(q && lq != q){
6066                 lq = q;
6067                 var tm = q.match(tagTokenRe);
6068                 if(type == "select"){
6069                     if(tm){
6070                         if(tm[1] == "#"){
6071                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6072                         }else{
6073                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6074                         }
6075                         q = q.replace(tm[0], "");
6076                     }else if(q.substr(0, 1) != '@'){
6077                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6078                     }
6079                 }else{
6080                     if(tm){
6081                         if(tm[1] == "#"){
6082                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6083                         }else{
6084                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6085                         }
6086                         q = q.replace(tm[0], "");
6087                     }
6088                 }
6089                 while(!(mm = q.match(modeRe))){
6090                     var matched = false;
6091                     for(var j = 0; j < tklen; j++){
6092                         var t = tk[j];
6093                         var m = q.match(t.re);
6094                         if(m){
6095                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6096                                                     return m[i];
6097                                                 });
6098                             q = q.replace(m[0], "");
6099                             matched = true;
6100                             break;
6101                         }
6102                     }
6103                     // prevent infinite loop on bad selector
6104                     if(!matched){
6105                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6106                     }
6107                 }
6108                 if(mm[1]){
6109                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6110                     q = q.replace(mm[1], "");
6111                 }
6112             }
6113             fn[fn.length] = "return nodup(n);\n}";
6114             
6115              /** 
6116               * list of variables that need from compression as they are used by eval.
6117              *  eval:var:batch 
6118              *  eval:var:nodup
6119              *  eval:var:byTag
6120              *  eval:var:ById
6121              *  eval:var:getNodes
6122              *  eval:var:quickId
6123              *  eval:var:mode
6124              *  eval:var:root
6125              *  eval:var:n
6126              *  eval:var:byClassName
6127              *  eval:var:byPseudo
6128              *  eval:var:byAttribute
6129              *  eval:var:attrValue
6130              * 
6131              **/ 
6132             eval(fn.join(""));
6133             return f;
6134         },
6135
6136         /**
6137          * Selects a group of elements.
6138          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6139          * @param {Node} root (optional) The start of the query (defaults to document).
6140          * @return {Array}
6141          */
6142         select : function(path, root, type){
6143             if(!root || root == document){
6144                 root = document;
6145             }
6146             if(typeof root == "string"){
6147                 root = document.getElementById(root);
6148             }
6149             var paths = path.split(",");
6150             var results = [];
6151             for(var i = 0, len = paths.length; i < len; i++){
6152                 var p = paths[i].replace(trimRe, "");
6153                 if(!cache[p]){
6154                     cache[p] = Roo.DomQuery.compile(p);
6155                     if(!cache[p]){
6156                         throw p + " is not a valid selector";
6157                     }
6158                 }
6159                 var result = cache[p](root);
6160                 if(result && result != document){
6161                     results = results.concat(result);
6162                 }
6163             }
6164             if(paths.length > 1){
6165                 return nodup(results);
6166             }
6167             return results;
6168         },
6169
6170         /**
6171          * Selects a single element.
6172          * @param {String} selector The selector/xpath query
6173          * @param {Node} root (optional) The start of the query (defaults to document).
6174          * @return {Element}
6175          */
6176         selectNode : function(path, root){
6177             return Roo.DomQuery.select(path, root)[0];
6178         },
6179
6180         /**
6181          * Selects the value of a node, optionally replacing null with the defaultValue.
6182          * @param {String} selector The selector/xpath query
6183          * @param {Node} root (optional) The start of the query (defaults to document).
6184          * @param {String} defaultValue
6185          */
6186         selectValue : function(path, root, defaultValue){
6187             path = path.replace(trimRe, "");
6188             if(!valueCache[path]){
6189                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6190             }
6191             var n = valueCache[path](root);
6192             n = n[0] ? n[0] : n;
6193             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6194             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6195         },
6196
6197         /**
6198          * Selects the value of a node, parsing integers and floats.
6199          * @param {String} selector The selector/xpath query
6200          * @param {Node} root (optional) The start of the query (defaults to document).
6201          * @param {Number} defaultValue
6202          * @return {Number}
6203          */
6204         selectNumber : function(path, root, defaultValue){
6205             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6206             return parseFloat(v);
6207         },
6208
6209         /**
6210          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6211          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6212          * @param {String} selector The simple selector to test
6213          * @return {Boolean}
6214          */
6215         is : function(el, ss){
6216             if(typeof el == "string"){
6217                 el = document.getElementById(el);
6218             }
6219             var isArray = (el instanceof Array);
6220             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6221             return isArray ? (result.length == el.length) : (result.length > 0);
6222         },
6223
6224         /**
6225          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6226          * @param {Array} el An array of elements to filter
6227          * @param {String} selector The simple selector to test
6228          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6229          * the selector instead of the ones that match
6230          * @return {Array}
6231          */
6232         filter : function(els, ss, nonMatches){
6233             ss = ss.replace(trimRe, "");
6234             if(!simpleCache[ss]){
6235                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6236             }
6237             var result = simpleCache[ss](els);
6238             return nonMatches ? quickDiff(result, els) : result;
6239         },
6240
6241         /**
6242          * Collection of matching regular expressions and code snippets.
6243          */
6244         matchers : [{
6245                 re: /^\.([\w-]+)/,
6246                 select: 'n = byClassName(n, null, " {1} ");'
6247             }, {
6248                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6249                 select: 'n = byPseudo(n, "{1}", "{2}");'
6250             },{
6251                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6252                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6253             }, {
6254                 re: /^#([\w-]+)/,
6255                 select: 'n = byId(n, null, "{1}");'
6256             },{
6257                 re: /^@([\w-]+)/,
6258                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6259             }
6260         ],
6261
6262         /**
6263          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6264          * 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;.
6265          */
6266         operators : {
6267             "=" : function(a, v){
6268                 return a == v;
6269             },
6270             "!=" : function(a, v){
6271                 return a != v;
6272             },
6273             "^=" : function(a, v){
6274                 return a && a.substr(0, v.length) == v;
6275             },
6276             "$=" : function(a, v){
6277                 return a && a.substr(a.length-v.length) == v;
6278             },
6279             "*=" : function(a, v){
6280                 return a && a.indexOf(v) !== -1;
6281             },
6282             "%=" : function(a, v){
6283                 return (a % v) == 0;
6284             },
6285             "|=" : function(a, v){
6286                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6287             },
6288             "~=" : function(a, v){
6289                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6290             }
6291         },
6292
6293         /**
6294          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6295          * and the argument (if any) supplied in the selector.
6296          */
6297         pseudos : {
6298             "first-child" : function(c){
6299                 var r = [], ri = -1, n;
6300                 for(var i = 0, ci; ci = n = c[i]; i++){
6301                     while((n = n.previousSibling) && n.nodeType != 1);
6302                     if(!n){
6303                         r[++ri] = ci;
6304                     }
6305                 }
6306                 return r;
6307             },
6308
6309             "last-child" : function(c){
6310                 var r = [], ri = -1, n;
6311                 for(var i = 0, ci; ci = n = c[i]; i++){
6312                     while((n = n.nextSibling) && n.nodeType != 1);
6313                     if(!n){
6314                         r[++ri] = ci;
6315                     }
6316                 }
6317                 return r;
6318             },
6319
6320             "nth-child" : function(c, a) {
6321                 var r = [], ri = -1;
6322                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6323                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6324                 for(var i = 0, n; n = c[i]; i++){
6325                     var pn = n.parentNode;
6326                     if (batch != pn._batch) {
6327                         var j = 0;
6328                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6329                             if(cn.nodeType == 1){
6330                                cn.nodeIndex = ++j;
6331                             }
6332                         }
6333                         pn._batch = batch;
6334                     }
6335                     if (f == 1) {
6336                         if (l == 0 || n.nodeIndex == l){
6337                             r[++ri] = n;
6338                         }
6339                     } else if ((n.nodeIndex + l) % f == 0){
6340                         r[++ri] = n;
6341                     }
6342                 }
6343
6344                 return r;
6345             },
6346
6347             "only-child" : function(c){
6348                 var r = [], ri = -1;;
6349                 for(var i = 0, ci; ci = c[i]; i++){
6350                     if(!prev(ci) && !next(ci)){
6351                         r[++ri] = ci;
6352                     }
6353                 }
6354                 return r;
6355             },
6356
6357             "empty" : function(c){
6358                 var r = [], ri = -1;
6359                 for(var i = 0, ci; ci = c[i]; i++){
6360                     var cns = ci.childNodes, j = 0, cn, empty = true;
6361                     while(cn = cns[j]){
6362                         ++j;
6363                         if(cn.nodeType == 1 || cn.nodeType == 3){
6364                             empty = false;
6365                             break;
6366                         }
6367                     }
6368                     if(empty){
6369                         r[++ri] = ci;
6370                     }
6371                 }
6372                 return r;
6373             },
6374
6375             "contains" : function(c, v){
6376                 var r = [], ri = -1;
6377                 for(var i = 0, ci; ci = c[i]; i++){
6378                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6379                         r[++ri] = ci;
6380                     }
6381                 }
6382                 return r;
6383             },
6384
6385             "nodeValue" : function(c, v){
6386                 var r = [], ri = -1;
6387                 for(var i = 0, ci; ci = c[i]; i++){
6388                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6389                         r[++ri] = ci;
6390                     }
6391                 }
6392                 return r;
6393             },
6394
6395             "checked" : function(c){
6396                 var r = [], ri = -1;
6397                 for(var i = 0, ci; ci = c[i]; i++){
6398                     if(ci.checked == true){
6399                         r[++ri] = ci;
6400                     }
6401                 }
6402                 return r;
6403             },
6404
6405             "not" : function(c, ss){
6406                 return Roo.DomQuery.filter(c, ss, true);
6407             },
6408
6409             "odd" : function(c){
6410                 return this["nth-child"](c, "odd");
6411             },
6412
6413             "even" : function(c){
6414                 return this["nth-child"](c, "even");
6415             },
6416
6417             "nth" : function(c, a){
6418                 return c[a-1] || [];
6419             },
6420
6421             "first" : function(c){
6422                 return c[0] || [];
6423             },
6424
6425             "last" : function(c){
6426                 return c[c.length-1] || [];
6427             },
6428
6429             "has" : function(c, ss){
6430                 var s = Roo.DomQuery.select;
6431                 var r = [], ri = -1;
6432                 for(var i = 0, ci; ci = c[i]; i++){
6433                     if(s(ss, ci).length > 0){
6434                         r[++ri] = ci;
6435                     }
6436                 }
6437                 return r;
6438             },
6439
6440             "next" : function(c, ss){
6441                 var is = Roo.DomQuery.is;
6442                 var r = [], ri = -1;
6443                 for(var i = 0, ci; ci = c[i]; i++){
6444                     var n = next(ci);
6445                     if(n && is(n, ss)){
6446                         r[++ri] = ci;
6447                     }
6448                 }
6449                 return r;
6450             },
6451
6452             "prev" : function(c, ss){
6453                 var is = Roo.DomQuery.is;
6454                 var r = [], ri = -1;
6455                 for(var i = 0, ci; ci = c[i]; i++){
6456                     var n = prev(ci);
6457                     if(n && is(n, ss)){
6458                         r[++ri] = ci;
6459                     }
6460                 }
6461                 return r;
6462             }
6463         }
6464     };
6465 }();
6466
6467 /**
6468  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6469  * @param {String} path The selector/xpath query
6470  * @param {Node} root (optional) The start of the query (defaults to document).
6471  * @return {Array}
6472  * @member Roo
6473  * @method query
6474  */
6475 Roo.query = Roo.DomQuery.select;
6476 /*
6477  * Based on:
6478  * Ext JS Library 1.1.1
6479  * Copyright(c) 2006-2007, Ext JS, LLC.
6480  *
6481  * Originally Released Under LGPL - original licence link has changed is not relivant.
6482  *
6483  * Fork - LGPL
6484  * <script type="text/javascript">
6485  */
6486
6487 /**
6488  * @class Roo.util.Observable
6489  * Base class that provides a common interface for publishing events. Subclasses are expected to
6490  * to have a property "events" with all the events defined.<br>
6491  * For example:
6492  * <pre><code>
6493  Employee = function(name){
6494     this.name = name;
6495     this.addEvents({
6496         "fired" : true,
6497         "quit" : true
6498     });
6499  }
6500  Roo.extend(Employee, Roo.util.Observable);
6501 </code></pre>
6502  * @param {Object} config properties to use (incuding events / listeners)
6503  */
6504
6505 Roo.util.Observable = function(cfg){
6506     
6507     cfg = cfg|| {};
6508     this.addEvents(cfg.events || {});
6509     if (cfg.events) {
6510         delete cfg.events; // make sure
6511     }
6512      
6513     Roo.apply(this, cfg);
6514     
6515     if(this.listeners){
6516         this.on(this.listeners);
6517         delete this.listeners;
6518     }
6519 };
6520 Roo.util.Observable.prototype = {
6521     /** 
6522  * @cfg {Object} listeners  list of events and functions to call for this object, 
6523  * For example :
6524  * <pre><code>
6525     listeners :  { 
6526        'click' : function(e) {
6527            ..... 
6528         } ,
6529         .... 
6530     } 
6531   </code></pre>
6532  */
6533     
6534     
6535     /**
6536      * Fires the specified event with the passed parameters (minus the event name).
6537      * @param {String} eventName
6538      * @param {Object...} args Variable number of parameters are passed to handlers
6539      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6540      */
6541     fireEvent : function(){
6542         var ce = this.events[arguments[0].toLowerCase()];
6543         if(typeof ce == "object"){
6544             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6545         }else{
6546             return true;
6547         }
6548     },
6549
6550     // private
6551     filterOptRe : /^(?:scope|delay|buffer|single)$/,
6552
6553     /**
6554      * Appends an event handler to this component
6555      * @param {String}   eventName The type of event to listen for
6556      * @param {Function} handler The method the event invokes
6557      * @param {Object}   scope (optional) The scope in which to execute the handler
6558      * function. The handler function's "this" context.
6559      * @param {Object}   options (optional) An object containing handler configuration
6560      * properties. This may contain any of the following properties:<ul>
6561      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6562      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6563      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6564      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6565      * by the specified number of milliseconds. If the event fires again within that time, the original
6566      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6567      * </ul><br>
6568      * <p>
6569      * <b>Combining Options</b><br>
6570      * Using the options argument, it is possible to combine different types of listeners:<br>
6571      * <br>
6572      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6573                 <pre><code>
6574                 el.on('click', this.onClick, this, {
6575                         single: true,
6576                 delay: 100,
6577                 forumId: 4
6578                 });
6579                 </code></pre>
6580      * <p>
6581      * <b>Attaching multiple handlers in 1 call</b><br>
6582      * The method also allows for a single argument to be passed which is a config object containing properties
6583      * which specify multiple handlers.
6584      * <pre><code>
6585                 el.on({
6586                         'click': {
6587                         fn: this.onClick,
6588                         scope: this,
6589                         delay: 100
6590                 }, 
6591                 'mouseover': {
6592                         fn: this.onMouseOver,
6593                         scope: this
6594                 },
6595                 'mouseout': {
6596                         fn: this.onMouseOut,
6597                         scope: this
6598                 }
6599                 });
6600                 </code></pre>
6601      * <p>
6602      * Or a shorthand syntax which passes the same scope object to all handlers:
6603         <pre><code>
6604                 el.on({
6605                         'click': this.onClick,
6606                 'mouseover': this.onMouseOver,
6607                 'mouseout': this.onMouseOut,
6608                 scope: this
6609                 });
6610                 </code></pre>
6611      */
6612     addListener : function(eventName, fn, scope, o){
6613         if(typeof eventName == "object"){
6614             o = eventName;
6615             for(var e in o){
6616                 if(this.filterOptRe.test(e)){
6617                     continue;
6618                 }
6619                 if(typeof o[e] == "function"){
6620                     // shared options
6621                     this.addListener(e, o[e], o.scope,  o);
6622                 }else{
6623                     // individual options
6624                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
6625                 }
6626             }
6627             return;
6628         }
6629         o = (!o || typeof o == "boolean") ? {} : o;
6630         eventName = eventName.toLowerCase();
6631         var ce = this.events[eventName] || true;
6632         if(typeof ce == "boolean"){
6633             ce = new Roo.util.Event(this, eventName);
6634             this.events[eventName] = ce;
6635         }
6636         ce.addListener(fn, scope, o);
6637     },
6638
6639     /**
6640      * Removes a listener
6641      * @param {String}   eventName     The type of event to listen for
6642      * @param {Function} handler        The handler to remove
6643      * @param {Object}   scope  (optional) The scope (this object) for the handler
6644      */
6645     removeListener : function(eventName, fn, scope){
6646         var ce = this.events[eventName.toLowerCase()];
6647         if(typeof ce == "object"){
6648             ce.removeListener(fn, scope);
6649         }
6650     },
6651
6652     /**
6653      * Removes all listeners for this object
6654      */
6655     purgeListeners : function(){
6656         for(var evt in this.events){
6657             if(typeof this.events[evt] == "object"){
6658                  this.events[evt].clearListeners();
6659             }
6660         }
6661     },
6662
6663     relayEvents : function(o, events){
6664         var createHandler = function(ename){
6665             return function(){
6666                  
6667                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6668             };
6669         };
6670         for(var i = 0, len = events.length; i < len; i++){
6671             var ename = events[i];
6672             if(!this.events[ename]){
6673                 this.events[ename] = true;
6674             };
6675             o.on(ename, createHandler(ename), this);
6676         }
6677     },
6678
6679     /**
6680      * Used to define events on this Observable
6681      * @param {Object} object The object with the events defined
6682      */
6683     addEvents : function(o){
6684         if(!this.events){
6685             this.events = {};
6686         }
6687         Roo.applyIf(this.events, o);
6688     },
6689
6690     /**
6691      * Checks to see if this object has any listeners for a specified event
6692      * @param {String} eventName The name of the event to check for
6693      * @return {Boolean} True if the event is being listened for, else false
6694      */
6695     hasListener : function(eventName){
6696         var e = this.events[eventName];
6697         return typeof e == "object" && e.listeners.length > 0;
6698     }
6699 };
6700 /**
6701  * Appends an event handler to this element (shorthand for addListener)
6702  * @param {String}   eventName     The type of event to listen for
6703  * @param {Function} handler        The method the event invokes
6704  * @param {Object}   scope (optional) The scope in which to execute the handler
6705  * function. The handler function's "this" context.
6706  * @param {Object}   options  (optional)
6707  * @method
6708  */
6709 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6710 /**
6711  * Removes a listener (shorthand for removeListener)
6712  * @param {String}   eventName     The type of event to listen for
6713  * @param {Function} handler        The handler to remove
6714  * @param {Object}   scope  (optional) The scope (this object) for the handler
6715  * @method
6716  */
6717 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6718
6719 /**
6720  * Starts capture on the specified Observable. All events will be passed
6721  * to the supplied function with the event name + standard signature of the event
6722  * <b>before</b> the event is fired. If the supplied function returns false,
6723  * the event will not fire.
6724  * @param {Observable} o The Observable to capture
6725  * @param {Function} fn The function to call
6726  * @param {Object} scope (optional) The scope (this object) for the fn
6727  * @static
6728  */
6729 Roo.util.Observable.capture = function(o, fn, scope){
6730     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6731 };
6732
6733 /**
6734  * Removes <b>all</b> added captures from the Observable.
6735  * @param {Observable} o The Observable to release
6736  * @static
6737  */
6738 Roo.util.Observable.releaseCapture = function(o){
6739     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6740 };
6741
6742 (function(){
6743
6744     var createBuffered = function(h, o, scope){
6745         var task = new Roo.util.DelayedTask();
6746         return function(){
6747             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6748         };
6749     };
6750
6751     var createSingle = function(h, e, fn, scope){
6752         return function(){
6753             e.removeListener(fn, scope);
6754             return h.apply(scope, arguments);
6755         };
6756     };
6757
6758     var createDelayed = function(h, o, scope){
6759         return function(){
6760             var args = Array.prototype.slice.call(arguments, 0);
6761             setTimeout(function(){
6762                 h.apply(scope, args);
6763             }, o.delay || 10);
6764         };
6765     };
6766
6767     Roo.util.Event = function(obj, name){
6768         this.name = name;
6769         this.obj = obj;
6770         this.listeners = [];
6771     };
6772
6773     Roo.util.Event.prototype = {
6774         addListener : function(fn, scope, options){
6775             var o = options || {};
6776             scope = scope || this.obj;
6777             if(!this.isListening(fn, scope)){
6778                 var l = {fn: fn, scope: scope, options: o};
6779                 var h = fn;
6780                 if(o.delay){
6781                     h = createDelayed(h, o, scope);
6782                 }
6783                 if(o.single){
6784                     h = createSingle(h, this, fn, scope);
6785                 }
6786                 if(o.buffer){
6787                     h = createBuffered(h, o, scope);
6788                 }
6789                 l.fireFn = h;
6790                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6791                     this.listeners.push(l);
6792                 }else{
6793                     this.listeners = this.listeners.slice(0);
6794                     this.listeners.push(l);
6795                 }
6796             }
6797         },
6798
6799         findListener : function(fn, scope){
6800             scope = scope || this.obj;
6801             var ls = this.listeners;
6802             for(var i = 0, len = ls.length; i < len; i++){
6803                 var l = ls[i];
6804                 if(l.fn == fn && l.scope == scope){
6805                     return i;
6806                 }
6807             }
6808             return -1;
6809         },
6810
6811         isListening : function(fn, scope){
6812             return this.findListener(fn, scope) != -1;
6813         },
6814
6815         removeListener : function(fn, scope){
6816             var index;
6817             if((index = this.findListener(fn, scope)) != -1){
6818                 if(!this.firing){
6819                     this.listeners.splice(index, 1);
6820                 }else{
6821                     this.listeners = this.listeners.slice(0);
6822                     this.listeners.splice(index, 1);
6823                 }
6824                 return true;
6825             }
6826             return false;
6827         },
6828
6829         clearListeners : function(){
6830             this.listeners = [];
6831         },
6832
6833         fire : function(){
6834             var ls = this.listeners, scope, len = ls.length;
6835             if(len > 0){
6836                 this.firing = true;
6837                 var args = Array.prototype.slice.call(arguments, 0);                
6838                 for(var i = 0; i < len; i++){
6839                     var l = ls[i];
6840                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6841                         this.firing = false;
6842                         return false;
6843                     }
6844                 }
6845                 this.firing = false;
6846             }
6847             return true;
6848         }
6849     };
6850 })();/*
6851  * RooJS Library 
6852  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6853  *
6854  * Licence LGPL 
6855  *
6856  */
6857  
6858 /**
6859  * @class Roo.Document
6860  * @extends Roo.util.Observable
6861  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6862  * 
6863  * @param {Object} config the methods and properties of the 'base' class for the application.
6864  * 
6865  *  Generic Page handler - implement this to start your app..
6866  * 
6867  * eg.
6868  *  MyProject = new Roo.Document({
6869         events : {
6870             'load' : true // your events..
6871         },
6872         listeners : {
6873             'ready' : function() {
6874                 // fired on Roo.onReady()
6875             }
6876         }
6877  * 
6878  */
6879 Roo.Document = function(cfg) {
6880      
6881     this.addEvents({ 
6882         'ready' : true
6883     });
6884     Roo.util.Observable.call(this,cfg);
6885     
6886     var _this = this;
6887     
6888     Roo.onReady(function() {
6889         _this.fireEvent('ready');
6890     },null,false);
6891     
6892     
6893 }
6894
6895 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6896  * Based on:
6897  * Ext JS Library 1.1.1
6898  * Copyright(c) 2006-2007, Ext JS, LLC.
6899  *
6900  * Originally Released Under LGPL - original licence link has changed is not relivant.
6901  *
6902  * Fork - LGPL
6903  * <script type="text/javascript">
6904  */
6905
6906 /**
6907  * @class Roo.EventManager
6908  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6909  * several useful events directly.
6910  * See {@link Roo.EventObject} for more details on normalized event objects.
6911  * @static
6912  */
6913 Roo.EventManager = function(){
6914     var docReadyEvent, docReadyProcId, docReadyState = false;
6915     var resizeEvent, resizeTask, textEvent, textSize;
6916     var E = Roo.lib.Event;
6917     var D = Roo.lib.Dom;
6918
6919     
6920     
6921
6922     var fireDocReady = function(){
6923         if(!docReadyState){
6924             docReadyState = true;
6925             Roo.isReady = true;
6926             if(docReadyProcId){
6927                 clearInterval(docReadyProcId);
6928             }
6929             if(Roo.isGecko || Roo.isOpera) {
6930                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6931             }
6932             if(Roo.isIE){
6933                 var defer = document.getElementById("ie-deferred-loader");
6934                 if(defer){
6935                     defer.onreadystatechange = null;
6936                     defer.parentNode.removeChild(defer);
6937                 }
6938             }
6939             if(docReadyEvent){
6940                 docReadyEvent.fire();
6941                 docReadyEvent.clearListeners();
6942             }
6943         }
6944     };
6945     
6946     var initDocReady = function(){
6947         docReadyEvent = new Roo.util.Event();
6948         if(Roo.isGecko || Roo.isOpera) {
6949             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6950         }else if(Roo.isIE){
6951             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6952             var defer = document.getElementById("ie-deferred-loader");
6953             defer.onreadystatechange = function(){
6954                 if(this.readyState == "complete"){
6955                     fireDocReady();
6956                 }
6957             };
6958         }else if(Roo.isSafari){ 
6959             docReadyProcId = setInterval(function(){
6960                 var rs = document.readyState;
6961                 if(rs == "complete") {
6962                     fireDocReady();     
6963                  }
6964             }, 10);
6965         }
6966         // no matter what, make sure it fires on load
6967         E.on(window, "load", fireDocReady);
6968     };
6969
6970     var createBuffered = function(h, o){
6971         var task = new Roo.util.DelayedTask(h);
6972         return function(e){
6973             // create new event object impl so new events don't wipe out properties
6974             e = new Roo.EventObjectImpl(e);
6975             task.delay(o.buffer, h, null, [e]);
6976         };
6977     };
6978
6979     var createSingle = function(h, el, ename, fn){
6980         return function(e){
6981             Roo.EventManager.removeListener(el, ename, fn);
6982             h(e);
6983         };
6984     };
6985
6986     var createDelayed = function(h, o){
6987         return function(e){
6988             // create new event object impl so new events don't wipe out properties
6989             e = new Roo.EventObjectImpl(e);
6990             setTimeout(function(){
6991                 h(e);
6992             }, o.delay || 10);
6993         };
6994     };
6995     var transitionEndVal = false;
6996     
6997     var transitionEnd = function()
6998     {
6999         if (transitionEndVal) {
7000             return transitionEndVal;
7001         }
7002         var el = document.createElement('div');
7003
7004         var transEndEventNames = {
7005             WebkitTransition : 'webkitTransitionEnd',
7006             MozTransition    : 'transitionend',
7007             OTransition      : 'oTransitionEnd otransitionend',
7008             transition       : 'transitionend'
7009         };
7010     
7011         for (var name in transEndEventNames) {
7012             if (el.style[name] !== undefined) {
7013                 transitionEndVal = transEndEventNames[name];
7014                 return  transitionEndVal ;
7015             }
7016         }
7017     }
7018     
7019   
7020
7021     var listen = function(element, ename, opt, fn, scope)
7022     {
7023         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7024         fn = fn || o.fn; scope = scope || o.scope;
7025         var el = Roo.getDom(element);
7026         
7027         
7028         if(!el){
7029             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7030         }
7031         
7032         if (ename == 'transitionend') {
7033             ename = transitionEnd();
7034         }
7035         var h = function(e){
7036             e = Roo.EventObject.setEvent(e);
7037             var t;
7038             if(o.delegate){
7039                 t = e.getTarget(o.delegate, el);
7040                 if(!t){
7041                     return;
7042                 }
7043             }else{
7044                 t = e.target;
7045             }
7046             if(o.stopEvent === true){
7047                 e.stopEvent();
7048             }
7049             if(o.preventDefault === true){
7050                e.preventDefault();
7051             }
7052             if(o.stopPropagation === true){
7053                 e.stopPropagation();
7054             }
7055
7056             if(o.normalized === false){
7057                 e = e.browserEvent;
7058             }
7059
7060             fn.call(scope || el, e, t, o);
7061         };
7062         if(o.delay){
7063             h = createDelayed(h, o);
7064         }
7065         if(o.single){
7066             h = createSingle(h, el, ename, fn);
7067         }
7068         if(o.buffer){
7069             h = createBuffered(h, o);
7070         }
7071         
7072         fn._handlers = fn._handlers || [];
7073         
7074         
7075         fn._handlers.push([Roo.id(el), ename, h]);
7076         
7077         
7078          
7079         E.on(el, ename, h); // this adds the actuall listener to the object..
7080         
7081         
7082         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7083             el.addEventListener("DOMMouseScroll", h, false);
7084             E.on(window, 'unload', function(){
7085                 el.removeEventListener("DOMMouseScroll", h, false);
7086             });
7087         }
7088         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7089             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7090         }
7091         return h;
7092     };
7093
7094     var stopListening = function(el, ename, fn){
7095         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7096         if(hds){
7097             for(var i = 0, len = hds.length; i < len; i++){
7098                 var h = hds[i];
7099                 if(h[0] == id && h[1] == ename){
7100                     hd = h[2];
7101                     hds.splice(i, 1);
7102                     break;
7103                 }
7104             }
7105         }
7106         E.un(el, ename, hd);
7107         el = Roo.getDom(el);
7108         if(ename == "mousewheel" && el.addEventListener){
7109             el.removeEventListener("DOMMouseScroll", hd, false);
7110         }
7111         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7112             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7113         }
7114     };
7115
7116     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7117     
7118     var pub = {
7119         
7120         
7121         /** 
7122          * Fix for doc tools
7123          * @scope Roo.EventManager
7124          */
7125         
7126         
7127         /** 
7128          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7129          * object with a Roo.EventObject
7130          * @param {Function} fn        The method the event invokes
7131          * @param {Object}   scope    An object that becomes the scope of the handler
7132          * @param {boolean}  override If true, the obj passed in becomes
7133          *                             the execution scope of the listener
7134          * @return {Function} The wrapped function
7135          * @deprecated
7136          */
7137         wrap : function(fn, scope, override){
7138             return function(e){
7139                 Roo.EventObject.setEvent(e);
7140                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7141             };
7142         },
7143         
7144         /**
7145      * Appends an event handler to an element (shorthand for addListener)
7146      * @param {String/HTMLElement}   element        The html element or id to assign the
7147      * @param {String}   eventName The type of event to listen for
7148      * @param {Function} handler The method the event invokes
7149      * @param {Object}   scope (optional) The scope in which to execute the handler
7150      * function. The handler function's "this" context.
7151      * @param {Object}   options (optional) An object containing handler configuration
7152      * properties. This may contain any of the following properties:<ul>
7153      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7154      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7155      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7156      * <li>preventDefault {Boolean} True to prevent the default action</li>
7157      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7158      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7159      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7160      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7161      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7162      * by the specified number of milliseconds. If the event fires again within that time, the original
7163      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7164      * </ul><br>
7165      * <p>
7166      * <b>Combining Options</b><br>
7167      * Using the options argument, it is possible to combine different types of listeners:<br>
7168      * <br>
7169      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7170      * Code:<pre><code>
7171 el.on('click', this.onClick, this, {
7172     single: true,
7173     delay: 100,
7174     stopEvent : true,
7175     forumId: 4
7176 });</code></pre>
7177      * <p>
7178      * <b>Attaching multiple handlers in 1 call</b><br>
7179       * The method also allows for a single argument to be passed which is a config object containing properties
7180      * which specify multiple handlers.
7181      * <p>
7182      * Code:<pre><code>
7183 el.on({
7184     'click' : {
7185         fn: this.onClick
7186         scope: this,
7187         delay: 100
7188     },
7189     'mouseover' : {
7190         fn: this.onMouseOver
7191         scope: this
7192     },
7193     'mouseout' : {
7194         fn: this.onMouseOut
7195         scope: this
7196     }
7197 });</code></pre>
7198      * <p>
7199      * Or a shorthand syntax:<br>
7200      * Code:<pre><code>
7201 el.on({
7202     'click' : this.onClick,
7203     'mouseover' : this.onMouseOver,
7204     'mouseout' : this.onMouseOut
7205     scope: this
7206 });</code></pre>
7207      */
7208         addListener : function(element, eventName, fn, scope, options){
7209             if(typeof eventName == "object"){
7210                 var o = eventName;
7211                 for(var e in o){
7212                     if(propRe.test(e)){
7213                         continue;
7214                     }
7215                     if(typeof o[e] == "function"){
7216                         // shared options
7217                         listen(element, e, o, o[e], o.scope);
7218                     }else{
7219                         // individual options
7220                         listen(element, e, o[e]);
7221                     }
7222                 }
7223                 return;
7224             }
7225             return listen(element, eventName, options, fn, scope);
7226         },
7227         
7228         /**
7229          * Removes an event handler
7230          *
7231          * @param {String/HTMLElement}   element        The id or html element to remove the 
7232          *                             event from
7233          * @param {String}   eventName     The type of event
7234          * @param {Function} fn
7235          * @return {Boolean} True if a listener was actually removed
7236          */
7237         removeListener : function(element, eventName, fn){
7238             return stopListening(element, eventName, fn);
7239         },
7240         
7241         /**
7242          * Fires when the document is ready (before onload and before images are loaded). Can be 
7243          * accessed shorthanded Roo.onReady().
7244          * @param {Function} fn        The method the event invokes
7245          * @param {Object}   scope    An  object that becomes the scope of the handler
7246          * @param {boolean}  options
7247          */
7248         onDocumentReady : function(fn, scope, options){
7249             if(docReadyState){ // if it already fired
7250                 docReadyEvent.addListener(fn, scope, options);
7251                 docReadyEvent.fire();
7252                 docReadyEvent.clearListeners();
7253                 return;
7254             }
7255             if(!docReadyEvent){
7256                 initDocReady();
7257             }
7258             docReadyEvent.addListener(fn, scope, options);
7259         },
7260         
7261         /**
7262          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7263          * @param {Function} fn        The method the event invokes
7264          * @param {Object}   scope    An object that becomes the scope of the handler
7265          * @param {boolean}  options
7266          */
7267         onWindowResize : function(fn, scope, options)
7268         {
7269             if(!resizeEvent){
7270                 resizeEvent = new Roo.util.Event();
7271                 resizeTask = new Roo.util.DelayedTask(function(){
7272                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7273                 });
7274                 E.on(window, "resize", function()
7275                 {
7276                     if (Roo.isIE) {
7277                         resizeTask.delay(50);
7278                     } else {
7279                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7280                     }
7281                 });
7282             }
7283             resizeEvent.addListener(fn, scope, options);
7284         },
7285
7286         /**
7287          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7288          * @param {Function} fn        The method the event invokes
7289          * @param {Object}   scope    An object that becomes the scope of the handler
7290          * @param {boolean}  options
7291          */
7292         onTextResize : function(fn, scope, options){
7293             if(!textEvent){
7294                 textEvent = new Roo.util.Event();
7295                 var textEl = new Roo.Element(document.createElement('div'));
7296                 textEl.dom.className = 'x-text-resize';
7297                 textEl.dom.innerHTML = 'X';
7298                 textEl.appendTo(document.body);
7299                 textSize = textEl.dom.offsetHeight;
7300                 setInterval(function(){
7301                     if(textEl.dom.offsetHeight != textSize){
7302                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7303                     }
7304                 }, this.textResizeInterval);
7305             }
7306             textEvent.addListener(fn, scope, options);
7307         },
7308
7309         /**
7310          * Removes the passed window resize listener.
7311          * @param {Function} fn        The method the event invokes
7312          * @param {Object}   scope    The scope of handler
7313          */
7314         removeResizeListener : function(fn, scope){
7315             if(resizeEvent){
7316                 resizeEvent.removeListener(fn, scope);
7317             }
7318         },
7319
7320         // private
7321         fireResize : function(){
7322             if(resizeEvent){
7323                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7324             }   
7325         },
7326         /**
7327          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7328          */
7329         ieDeferSrc : false,
7330         /**
7331          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7332          */
7333         textResizeInterval : 50
7334     };
7335     
7336     /**
7337      * Fix for doc tools
7338      * @scopeAlias pub=Roo.EventManager
7339      */
7340     
7341      /**
7342      * Appends an event handler to an element (shorthand for addListener)
7343      * @param {String/HTMLElement}   element        The html element or id to assign the
7344      * @param {String}   eventName The type of event to listen for
7345      * @param {Function} handler The method the event invokes
7346      * @param {Object}   scope (optional) The scope in which to execute the handler
7347      * function. The handler function's "this" context.
7348      * @param {Object}   options (optional) An object containing handler configuration
7349      * properties. This may contain any of the following properties:<ul>
7350      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7351      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7352      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7353      * <li>preventDefault {Boolean} True to prevent the default action</li>
7354      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7355      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7356      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7357      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7358      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7359      * by the specified number of milliseconds. If the event fires again within that time, the original
7360      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7361      * </ul><br>
7362      * <p>
7363      * <b>Combining Options</b><br>
7364      * Using the options argument, it is possible to combine different types of listeners:<br>
7365      * <br>
7366      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7367      * Code:<pre><code>
7368 el.on('click', this.onClick, this, {
7369     single: true,
7370     delay: 100,
7371     stopEvent : true,
7372     forumId: 4
7373 });</code></pre>
7374      * <p>
7375      * <b>Attaching multiple handlers in 1 call</b><br>
7376       * The method also allows for a single argument to be passed which is a config object containing properties
7377      * which specify multiple handlers.
7378      * <p>
7379      * Code:<pre><code>
7380 el.on({
7381     'click' : {
7382         fn: this.onClick
7383         scope: this,
7384         delay: 100
7385     },
7386     'mouseover' : {
7387         fn: this.onMouseOver
7388         scope: this
7389     },
7390     'mouseout' : {
7391         fn: this.onMouseOut
7392         scope: this
7393     }
7394 });</code></pre>
7395      * <p>
7396      * Or a shorthand syntax:<br>
7397      * Code:<pre><code>
7398 el.on({
7399     'click' : this.onClick,
7400     'mouseover' : this.onMouseOver,
7401     'mouseout' : this.onMouseOut
7402     scope: this
7403 });</code></pre>
7404      */
7405     pub.on = pub.addListener;
7406     pub.un = pub.removeListener;
7407
7408     pub.stoppedMouseDownEvent = new Roo.util.Event();
7409     return pub;
7410 }();
7411 /**
7412   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
7413   * @param {Function} fn        The method the event invokes
7414   * @param {Object}   scope    An  object that becomes the scope of the handler
7415   * @param {boolean}  override If true, the obj passed in becomes
7416   *                             the execution scope of the listener
7417   * @member Roo
7418   * @method onReady
7419  */
7420 Roo.onReady = Roo.EventManager.onDocumentReady;
7421
7422 Roo.onReady(function(){
7423     var bd = Roo.get(document.body);
7424     if(!bd){ return; }
7425
7426     var cls = [
7427             Roo.isIE ? "roo-ie"
7428             : Roo.isIE11 ? "roo-ie11"
7429             : Roo.isEdge ? "roo-edge"
7430             : Roo.isGecko ? "roo-gecko"
7431             : Roo.isOpera ? "roo-opera"
7432             : Roo.isSafari ? "roo-safari" : ""];
7433
7434     if(Roo.isMac){
7435         cls.push("roo-mac");
7436     }
7437     if(Roo.isLinux){
7438         cls.push("roo-linux");
7439     }
7440     if(Roo.isIOS){
7441         cls.push("roo-ios");
7442     }
7443     if(Roo.isTouch){
7444         cls.push("roo-touch");
7445     }
7446     if(Roo.isBorderBox){
7447         cls.push('roo-border-box');
7448     }
7449     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7450         var p = bd.dom.parentNode;
7451         if(p){
7452             p.className += ' roo-strict';
7453         }
7454     }
7455     bd.addClass(cls.join(' '));
7456 });
7457
7458 /**
7459  * @class Roo.EventObject
7460  * EventObject exposes the Yahoo! UI Event functionality directly on the object
7461  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
7462  * Example:
7463  * <pre><code>
7464  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7465     e.preventDefault();
7466     var target = e.getTarget();
7467     ...
7468  }
7469  var myDiv = Roo.get("myDiv");
7470  myDiv.on("click", handleClick);
7471  //or
7472  Roo.EventManager.on("myDiv", 'click', handleClick);
7473  Roo.EventManager.addListener("myDiv", 'click', handleClick);
7474  </code></pre>
7475  * @static
7476  */
7477 Roo.EventObject = function(){
7478     
7479     var E = Roo.lib.Event;
7480     
7481     // safari keypress events for special keys return bad keycodes
7482     var safariKeys = {
7483         63234 : 37, // left
7484         63235 : 39, // right
7485         63232 : 38, // up
7486         63233 : 40, // down
7487         63276 : 33, // page up
7488         63277 : 34, // page down
7489         63272 : 46, // delete
7490         63273 : 36, // home
7491         63275 : 35  // end
7492     };
7493
7494     // normalize button clicks
7495     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7496                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7497
7498     Roo.EventObjectImpl = function(e){
7499         if(e){
7500             this.setEvent(e.browserEvent || e);
7501         }
7502     };
7503     Roo.EventObjectImpl.prototype = {
7504         /**
7505          * Used to fix doc tools.
7506          * @scope Roo.EventObject.prototype
7507          */
7508             
7509
7510         
7511         
7512         /** The normal browser event */
7513         browserEvent : null,
7514         /** The button pressed in a mouse event */
7515         button : -1,
7516         /** True if the shift key was down during the event */
7517         shiftKey : false,
7518         /** True if the control key was down during the event */
7519         ctrlKey : false,
7520         /** True if the alt key was down during the event */
7521         altKey : false,
7522
7523         /** Key constant 
7524         * @type Number */
7525         BACKSPACE : 8,
7526         /** Key constant 
7527         * @type Number */
7528         TAB : 9,
7529         /** Key constant 
7530         * @type Number */
7531         RETURN : 13,
7532         /** Key constant 
7533         * @type Number */
7534         ENTER : 13,
7535         /** Key constant 
7536         * @type Number */
7537         SHIFT : 16,
7538         /** Key constant 
7539         * @type Number */
7540         CONTROL : 17,
7541         /** Key constant 
7542         * @type Number */
7543         ESC : 27,
7544         /** Key constant 
7545         * @type Number */
7546         SPACE : 32,
7547         /** Key constant 
7548         * @type Number */
7549         PAGEUP : 33,
7550         /** Key constant 
7551         * @type Number */
7552         PAGEDOWN : 34,
7553         /** Key constant 
7554         * @type Number */
7555         END : 35,
7556         /** Key constant 
7557         * @type Number */
7558         HOME : 36,
7559         /** Key constant 
7560         * @type Number */
7561         LEFT : 37,
7562         /** Key constant 
7563         * @type Number */
7564         UP : 38,
7565         /** Key constant 
7566         * @type Number */
7567         RIGHT : 39,
7568         /** Key constant 
7569         * @type Number */
7570         DOWN : 40,
7571         /** Key constant 
7572         * @type Number */
7573         DELETE : 46,
7574         /** Key constant 
7575         * @type Number */
7576         F5 : 116,
7577
7578            /** @private */
7579         setEvent : function(e){
7580             if(e == this || (e && e.browserEvent)){ // already wrapped
7581                 return e;
7582             }
7583             this.browserEvent = e;
7584             if(e){
7585                 // normalize buttons
7586                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7587                 if(e.type == 'click' && this.button == -1){
7588                     this.button = 0;
7589                 }
7590                 this.type = e.type;
7591                 this.shiftKey = e.shiftKey;
7592                 // mac metaKey behaves like ctrlKey
7593                 this.ctrlKey = e.ctrlKey || e.metaKey;
7594                 this.altKey = e.altKey;
7595                 // in getKey these will be normalized for the mac
7596                 this.keyCode = e.keyCode;
7597                 // keyup warnings on firefox.
7598                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7599                 // cache the target for the delayed and or buffered events
7600                 this.target = E.getTarget(e);
7601                 // same for XY
7602                 this.xy = E.getXY(e);
7603             }else{
7604                 this.button = -1;
7605                 this.shiftKey = false;
7606                 this.ctrlKey = false;
7607                 this.altKey = false;
7608                 this.keyCode = 0;
7609                 this.charCode =0;
7610                 this.target = null;
7611                 this.xy = [0, 0];
7612             }
7613             return this;
7614         },
7615
7616         /**
7617          * Stop the event (preventDefault and stopPropagation)
7618          */
7619         stopEvent : function(){
7620             if(this.browserEvent){
7621                 if(this.browserEvent.type == 'mousedown'){
7622                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7623                 }
7624                 E.stopEvent(this.browserEvent);
7625             }
7626         },
7627
7628         /**
7629          * Prevents the browsers default handling of the event.
7630          */
7631         preventDefault : function(){
7632             if(this.browserEvent){
7633                 E.preventDefault(this.browserEvent);
7634             }
7635         },
7636
7637         /** @private */
7638         isNavKeyPress : function(){
7639             var k = this.keyCode;
7640             k = Roo.isSafari ? (safariKeys[k] || k) : k;
7641             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7642         },
7643
7644         isSpecialKey : function(){
7645             var k = this.keyCode;
7646             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
7647             (k == 16) || (k == 17) ||
7648             (k >= 18 && k <= 20) ||
7649             (k >= 33 && k <= 35) ||
7650             (k >= 36 && k <= 39) ||
7651             (k >= 44 && k <= 45);
7652         },
7653         /**
7654          * Cancels bubbling of the event.
7655          */
7656         stopPropagation : function(){
7657             if(this.browserEvent){
7658                 if(this.type == 'mousedown'){
7659                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7660                 }
7661                 E.stopPropagation(this.browserEvent);
7662             }
7663         },
7664
7665         /**
7666          * Gets the key code for the event.
7667          * @return {Number}
7668          */
7669         getCharCode : function(){
7670             return this.charCode || this.keyCode;
7671         },
7672
7673         /**
7674          * Returns a normalized keyCode for the event.
7675          * @return {Number} The key code
7676          */
7677         getKey : function(){
7678             var k = this.keyCode || this.charCode;
7679             return Roo.isSafari ? (safariKeys[k] || k) : k;
7680         },
7681
7682         /**
7683          * Gets the x coordinate of the event.
7684          * @return {Number}
7685          */
7686         getPageX : function(){
7687             return this.xy[0];
7688         },
7689
7690         /**
7691          * Gets the y coordinate of the event.
7692          * @return {Number}
7693          */
7694         getPageY : function(){
7695             return this.xy[1];
7696         },
7697
7698         /**
7699          * Gets the time of the event.
7700          * @return {Number}
7701          */
7702         getTime : function(){
7703             if(this.browserEvent){
7704                 return E.getTime(this.browserEvent);
7705             }
7706             return null;
7707         },
7708
7709         /**
7710          * Gets the page coordinates of the event.
7711          * @return {Array} The xy values like [x, y]
7712          */
7713         getXY : function(){
7714             return this.xy;
7715         },
7716
7717         /**
7718          * Gets the target for the event.
7719          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7720          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7721                 search as a number or element (defaults to 10 || document.body)
7722          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7723          * @return {HTMLelement}
7724          */
7725         getTarget : function(selector, maxDepth, returnEl){
7726             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7727         },
7728         /**
7729          * Gets the related target.
7730          * @return {HTMLElement}
7731          */
7732         getRelatedTarget : function(){
7733             if(this.browserEvent){
7734                 return E.getRelatedTarget(this.browserEvent);
7735             }
7736             return null;
7737         },
7738
7739         /**
7740          * Normalizes mouse wheel delta across browsers
7741          * @return {Number} The delta
7742          */
7743         getWheelDelta : function(){
7744             var e = this.browserEvent;
7745             var delta = 0;
7746             if(e.wheelDelta){ /* IE/Opera. */
7747                 delta = e.wheelDelta/120;
7748             }else if(e.detail){ /* Mozilla case. */
7749                 delta = -e.detail/3;
7750             }
7751             return delta;
7752         },
7753
7754         /**
7755          * Returns true if the control, meta, shift or alt key was pressed during this event.
7756          * @return {Boolean}
7757          */
7758         hasModifier : function(){
7759             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7760         },
7761
7762         /**
7763          * Returns true if the target of this event equals el or is a child of el
7764          * @param {String/HTMLElement/Element} el
7765          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7766          * @return {Boolean}
7767          */
7768         within : function(el, related){
7769             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7770             return t && Roo.fly(el).contains(t);
7771         },
7772
7773         getPoint : function(){
7774             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7775         }
7776     };
7777
7778     return new Roo.EventObjectImpl();
7779 }();
7780             
7781     /*
7782  * Based on:
7783  * Ext JS Library 1.1.1
7784  * Copyright(c) 2006-2007, Ext JS, LLC.
7785  *
7786  * Originally Released Under LGPL - original licence link has changed is not relivant.
7787  *
7788  * Fork - LGPL
7789  * <script type="text/javascript">
7790  */
7791
7792  
7793 // was in Composite Element!??!?!
7794  
7795 (function(){
7796     var D = Roo.lib.Dom;
7797     var E = Roo.lib.Event;
7798     var A = Roo.lib.Anim;
7799
7800     // local style camelizing for speed
7801     var propCache = {};
7802     var camelRe = /(-[a-z])/gi;
7803     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7804     var view = document.defaultView;
7805
7806 /**
7807  * @class Roo.Element
7808  * Represents an Element in the DOM.<br><br>
7809  * Usage:<br>
7810 <pre><code>
7811 var el = Roo.get("my-div");
7812
7813 // or with getEl
7814 var el = getEl("my-div");
7815
7816 // or with a DOM element
7817 var el = Roo.get(myDivElement);
7818 </code></pre>
7819  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7820  * each call instead of constructing a new one.<br><br>
7821  * <b>Animations</b><br />
7822  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7823  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7824 <pre>
7825 Option    Default   Description
7826 --------- --------  ---------------------------------------------
7827 duration  .35       The duration of the animation in seconds
7828 easing    easeOut   The YUI easing method
7829 callback  none      A function to execute when the anim completes
7830 scope     this      The scope (this) of the callback function
7831 </pre>
7832 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7833 * manipulate the animation. Here's an example:
7834 <pre><code>
7835 var el = Roo.get("my-div");
7836
7837 // no animation
7838 el.setWidth(100);
7839
7840 // default animation
7841 el.setWidth(100, true);
7842
7843 // animation with some options set
7844 el.setWidth(100, {
7845     duration: 1,
7846     callback: this.foo,
7847     scope: this
7848 });
7849
7850 // using the "anim" property to get the Anim object
7851 var opt = {
7852     duration: 1,
7853     callback: this.foo,
7854     scope: this
7855 };
7856 el.setWidth(100, opt);
7857 ...
7858 if(opt.anim.isAnimated()){
7859     opt.anim.stop();
7860 }
7861 </code></pre>
7862 * <b> Composite (Collections of) Elements</b><br />
7863  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7864  * @constructor Create a new Element directly.
7865  * @param {String/HTMLElement} element
7866  * @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).
7867  */
7868     Roo.Element = function(element, forceNew)
7869     {
7870         var dom = typeof element == "string" ?
7871                 document.getElementById(element) : element;
7872         
7873         this.listeners = {};
7874         
7875         if(!dom){ // invalid id/element
7876             return null;
7877         }
7878         var id = dom.id;
7879         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7880             return Roo.Element.cache[id];
7881         }
7882
7883         /**
7884          * The DOM element
7885          * @type HTMLElement
7886          */
7887         this.dom = dom;
7888
7889         /**
7890          * The DOM element ID
7891          * @type String
7892          */
7893         this.id = id || Roo.id(dom);
7894         
7895         return this; // assumed for cctor?
7896     };
7897
7898     var El = Roo.Element;
7899
7900     El.prototype = {
7901         /**
7902          * The element's default display mode  (defaults to "") 
7903          * @type String
7904          */
7905         originalDisplay : "",
7906
7907         
7908         // note this is overridden in BS version..
7909         visibilityMode : 1, 
7910         /**
7911          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7912          * @type String
7913          */
7914         defaultUnit : "px",
7915         
7916         /**
7917          * Sets the element's visibility mode. When setVisible() is called it
7918          * will use this to determine whether to set the visibility or the display property.
7919          * @param visMode Element.VISIBILITY or Element.DISPLAY
7920          * @return {Roo.Element} this
7921          */
7922         setVisibilityMode : function(visMode){
7923             this.visibilityMode = visMode;
7924             return this;
7925         },
7926         /**
7927          * Convenience method for setVisibilityMode(Element.DISPLAY)
7928          * @param {String} display (optional) What to set display to when visible
7929          * @return {Roo.Element} this
7930          */
7931         enableDisplayMode : function(display){
7932             this.setVisibilityMode(El.DISPLAY);
7933             if(typeof display != "undefined") { this.originalDisplay = display; }
7934             return this;
7935         },
7936
7937         /**
7938          * 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)
7939          * @param {String} selector The simple selector to test
7940          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7941                 search as a number or element (defaults to 10 || document.body)
7942          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7943          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7944          */
7945         findParent : function(simpleSelector, maxDepth, returnEl){
7946             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7947             maxDepth = maxDepth || 50;
7948             if(typeof maxDepth != "number"){
7949                 stopEl = Roo.getDom(maxDepth);
7950                 maxDepth = 10;
7951             }
7952             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7953                 if(dq.is(p, simpleSelector)){
7954                     return returnEl ? Roo.get(p) : p;
7955                 }
7956                 depth++;
7957                 p = p.parentNode;
7958             }
7959             return null;
7960         },
7961
7962
7963         /**
7964          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7965          * @param {String} selector The simple selector to test
7966          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7967                 search as a number or element (defaults to 10 || document.body)
7968          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7969          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7970          */
7971         findParentNode : function(simpleSelector, maxDepth, returnEl){
7972             var p = Roo.fly(this.dom.parentNode, '_internal');
7973             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7974         },
7975         
7976         /**
7977          * Looks at  the scrollable parent element
7978          */
7979         findScrollableParent : function()
7980         {
7981             var overflowRegex = /(auto|scroll)/;
7982             
7983             if(this.getStyle('position') === 'fixed'){
7984                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7985             }
7986             
7987             var excludeStaticParent = this.getStyle('position') === "absolute";
7988             
7989             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7990                 
7991                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7992                     continue;
7993                 }
7994                 
7995                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7996                     return parent;
7997                 }
7998                 
7999                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8000                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8001                 }
8002             }
8003             
8004             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8005         },
8006
8007         /**
8008          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8009          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8010          * @param {String} selector The simple selector to test
8011          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8012                 search as a number or element (defaults to 10 || document.body)
8013          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8014          */
8015         up : function(simpleSelector, maxDepth){
8016             return this.findParentNode(simpleSelector, maxDepth, true);
8017         },
8018
8019
8020
8021         /**
8022          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8023          * @param {String} selector The simple selector to test
8024          * @return {Boolean} True if this element matches the selector, else false
8025          */
8026         is : function(simpleSelector){
8027             return Roo.DomQuery.is(this.dom, simpleSelector);
8028         },
8029
8030         /**
8031          * Perform animation on this element.
8032          * @param {Object} args The YUI animation control args
8033          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8034          * @param {Function} onComplete (optional) Function to call when animation completes
8035          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8036          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8037          * @return {Roo.Element} this
8038          */
8039         animate : function(args, duration, onComplete, easing, animType){
8040             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8041             return this;
8042         },
8043
8044         /*
8045          * @private Internal animation call
8046          */
8047         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8048             animType = animType || 'run';
8049             opt = opt || {};
8050             var anim = Roo.lib.Anim[animType](
8051                 this.dom, args,
8052                 (opt.duration || defaultDur) || .35,
8053                 (opt.easing || defaultEase) || 'easeOut',
8054                 function(){
8055                     Roo.callback(cb, this);
8056                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8057                 },
8058                 this
8059             );
8060             opt.anim = anim;
8061             return anim;
8062         },
8063
8064         // private legacy anim prep
8065         preanim : function(a, i){
8066             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8067         },
8068
8069         /**
8070          * Removes worthless text nodes
8071          * @param {Boolean} forceReclean (optional) By default the element
8072          * keeps track if it has been cleaned already so
8073          * you can call this over and over. However, if you update the element and
8074          * need to force a reclean, you can pass true.
8075          */
8076         clean : function(forceReclean){
8077             if(this.isCleaned && forceReclean !== true){
8078                 return this;
8079             }
8080             var ns = /\S/;
8081             var d = this.dom, n = d.firstChild, ni = -1;
8082             while(n){
8083                 var nx = n.nextSibling;
8084                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8085                     d.removeChild(n);
8086                 }else{
8087                     n.nodeIndex = ++ni;
8088                 }
8089                 n = nx;
8090             }
8091             this.isCleaned = true;
8092             return this;
8093         },
8094
8095         // private
8096         calcOffsetsTo : function(el){
8097             el = Roo.get(el);
8098             var d = el.dom;
8099             var restorePos = false;
8100             if(el.getStyle('position') == 'static'){
8101                 el.position('relative');
8102                 restorePos = true;
8103             }
8104             var x = 0, y =0;
8105             var op = this.dom;
8106             while(op && op != d && op.tagName != 'HTML'){
8107                 x+= op.offsetLeft;
8108                 y+= op.offsetTop;
8109                 op = op.offsetParent;
8110             }
8111             if(restorePos){
8112                 el.position('static');
8113             }
8114             return [x, y];
8115         },
8116
8117         /**
8118          * Scrolls this element into view within the passed container.
8119          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8120          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8121          * @return {Roo.Element} this
8122          */
8123         scrollIntoView : function(container, hscroll){
8124             var c = Roo.getDom(container) || document.body;
8125             var el = this.dom;
8126
8127             var o = this.calcOffsetsTo(c),
8128                 l = o[0],
8129                 t = o[1],
8130                 b = t+el.offsetHeight,
8131                 r = l+el.offsetWidth;
8132
8133             var ch = c.clientHeight;
8134             var ct = parseInt(c.scrollTop, 10);
8135             var cl = parseInt(c.scrollLeft, 10);
8136             var cb = ct + ch;
8137             var cr = cl + c.clientWidth;
8138
8139             if(t < ct){
8140                 c.scrollTop = t;
8141             }else if(b > cb){
8142                 c.scrollTop = b-ch;
8143             }
8144
8145             if(hscroll !== false){
8146                 if(l < cl){
8147                     c.scrollLeft = l;
8148                 }else if(r > cr){
8149                     c.scrollLeft = r-c.clientWidth;
8150                 }
8151             }
8152             return this;
8153         },
8154
8155         // private
8156         scrollChildIntoView : function(child, hscroll){
8157             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8158         },
8159
8160         /**
8161          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8162          * the new height may not be available immediately.
8163          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8164          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8165          * @param {Function} onComplete (optional) Function to call when animation completes
8166          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8167          * @return {Roo.Element} this
8168          */
8169         autoHeight : function(animate, duration, onComplete, easing){
8170             var oldHeight = this.getHeight();
8171             this.clip();
8172             this.setHeight(1); // force clipping
8173             setTimeout(function(){
8174                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8175                 if(!animate){
8176                     this.setHeight(height);
8177                     this.unclip();
8178                     if(typeof onComplete == "function"){
8179                         onComplete();
8180                     }
8181                 }else{
8182                     this.setHeight(oldHeight); // restore original height
8183                     this.setHeight(height, animate, duration, function(){
8184                         this.unclip();
8185                         if(typeof onComplete == "function") { onComplete(); }
8186                     }.createDelegate(this), easing);
8187                 }
8188             }.createDelegate(this), 0);
8189             return this;
8190         },
8191
8192         /**
8193          * Returns true if this element is an ancestor of the passed element
8194          * @param {HTMLElement/String} el The element to check
8195          * @return {Boolean} True if this element is an ancestor of el, else false
8196          */
8197         contains : function(el){
8198             if(!el){return false;}
8199             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8200         },
8201
8202         /**
8203          * Checks whether the element is currently visible using both visibility and display properties.
8204          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8205          * @return {Boolean} True if the element is currently visible, else false
8206          */
8207         isVisible : function(deep) {
8208             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8209             if(deep !== true || !vis){
8210                 return vis;
8211             }
8212             var p = this.dom.parentNode;
8213             while(p && p.tagName.toLowerCase() != "body"){
8214                 if(!Roo.fly(p, '_isVisible').isVisible()){
8215                     return false;
8216                 }
8217                 p = p.parentNode;
8218             }
8219             return true;
8220         },
8221
8222         /**
8223          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8224          * @param {String} selector The CSS selector
8225          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8226          * @return {CompositeElement/CompositeElementLite} The composite element
8227          */
8228         select : function(selector, unique){
8229             return El.select(selector, unique, this.dom);
8230         },
8231
8232         /**
8233          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8234          * @param {String} selector The CSS selector
8235          * @return {Array} An array of the matched nodes
8236          */
8237         query : function(selector, unique){
8238             return Roo.DomQuery.select(selector, this.dom);
8239         },
8240
8241         /**
8242          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8243          * @param {String} selector The CSS selector
8244          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8245          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8246          */
8247         child : function(selector, returnDom){
8248             var n = Roo.DomQuery.selectNode(selector, this.dom);
8249             return returnDom ? n : Roo.get(n);
8250         },
8251
8252         /**
8253          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8254          * @param {String} selector The CSS selector
8255          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8256          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8257          */
8258         down : function(selector, returnDom){
8259             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8260             return returnDom ? n : Roo.get(n);
8261         },
8262
8263         /**
8264          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8265          * @param {String} group The group the DD object is member of
8266          * @param {Object} config The DD config object
8267          * @param {Object} overrides An object containing methods to override/implement on the DD object
8268          * @return {Roo.dd.DD} The DD object
8269          */
8270         initDD : function(group, config, overrides){
8271             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8272             return Roo.apply(dd, overrides);
8273         },
8274
8275         /**
8276          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8277          * @param {String} group The group the DDProxy object is member of
8278          * @param {Object} config The DDProxy config object
8279          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8280          * @return {Roo.dd.DDProxy} The DDProxy object
8281          */
8282         initDDProxy : function(group, config, overrides){
8283             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8284             return Roo.apply(dd, overrides);
8285         },
8286
8287         /**
8288          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8289          * @param {String} group The group the DDTarget object is member of
8290          * @param {Object} config The DDTarget config object
8291          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8292          * @return {Roo.dd.DDTarget} The DDTarget object
8293          */
8294         initDDTarget : function(group, config, overrides){
8295             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8296             return Roo.apply(dd, overrides);
8297         },
8298
8299         /**
8300          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8301          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8302          * @param {Boolean} visible Whether the element is visible
8303          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8304          * @return {Roo.Element} this
8305          */
8306          setVisible : function(visible, animate){
8307             if(!animate || !A){
8308                 if(this.visibilityMode == El.DISPLAY){
8309                     this.setDisplayed(visible);
8310                 }else{
8311                     this.fixDisplay();
8312                     this.dom.style.visibility = visible ? "visible" : "hidden";
8313                 }
8314             }else{
8315                 // closure for composites
8316                 var dom = this.dom;
8317                 var visMode = this.visibilityMode;
8318                 if(visible){
8319                     this.setOpacity(.01);
8320                     this.setVisible(true);
8321                 }
8322                 this.anim({opacity: { to: (visible?1:0) }},
8323                       this.preanim(arguments, 1),
8324                       null, .35, 'easeIn', function(){
8325                          if(!visible){
8326                              if(visMode == El.DISPLAY){
8327                                  dom.style.display = "none";
8328                              }else{
8329                                  dom.style.visibility = "hidden";
8330                              }
8331                              Roo.get(dom).setOpacity(1);
8332                          }
8333                      });
8334             }
8335             return this;
8336         },
8337
8338         /**
8339          * Returns true if display is not "none"
8340          * @return {Boolean}
8341          */
8342         isDisplayed : function() {
8343             return this.getStyle("display") != "none";
8344         },
8345
8346         /**
8347          * Toggles the element's visibility or display, depending on visibility mode.
8348          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8349          * @return {Roo.Element} this
8350          */
8351         toggle : function(animate){
8352             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8353             return this;
8354         },
8355
8356         /**
8357          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8358          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8359          * @return {Roo.Element} this
8360          */
8361         setDisplayed : function(value) {
8362             if(typeof value == "boolean"){
8363                value = value ? this.originalDisplay : "none";
8364             }
8365             this.setStyle("display", value);
8366             return this;
8367         },
8368
8369         /**
8370          * Tries to focus the element. Any exceptions are caught and ignored.
8371          * @return {Roo.Element} this
8372          */
8373         focus : function() {
8374             try{
8375                 this.dom.focus();
8376             }catch(e){}
8377             return this;
8378         },
8379
8380         /**
8381          * Tries to blur the element. Any exceptions are caught and ignored.
8382          * @return {Roo.Element} this
8383          */
8384         blur : function() {
8385             try{
8386                 this.dom.blur();
8387             }catch(e){}
8388             return this;
8389         },
8390
8391         /**
8392          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8393          * @param {String/Array} className The CSS class to add, or an array of classes
8394          * @return {Roo.Element} this
8395          */
8396         addClass : function(className){
8397             if(className instanceof Array){
8398                 for(var i = 0, len = className.length; i < len; i++) {
8399                     this.addClass(className[i]);
8400                 }
8401             }else{
8402                 if(className && !this.hasClass(className)){
8403                     if (this.dom instanceof SVGElement) {
8404                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
8405                     } else {
8406                         this.dom.className = this.dom.className + " " + className;
8407                     }
8408                 }
8409             }
8410             return this;
8411         },
8412
8413         /**
8414          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8415          * @param {String/Array} className The CSS class to add, or an array of classes
8416          * @return {Roo.Element} this
8417          */
8418         radioClass : function(className){
8419             var siblings = this.dom.parentNode.childNodes;
8420             for(var i = 0; i < siblings.length; i++) {
8421                 var s = siblings[i];
8422                 if(s.nodeType == 1){
8423                     Roo.get(s).removeClass(className);
8424                 }
8425             }
8426             this.addClass(className);
8427             return this;
8428         },
8429
8430         /**
8431          * Removes one or more CSS classes from the element.
8432          * @param {String/Array} className The CSS class to remove, or an array of classes
8433          * @return {Roo.Element} this
8434          */
8435         removeClass : function(className){
8436             
8437             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8438             if(!className || !cn){
8439                 return this;
8440             }
8441             if(className instanceof Array){
8442                 for(var i = 0, len = className.length; i < len; i++) {
8443                     this.removeClass(className[i]);
8444                 }
8445             }else{
8446                 if(this.hasClass(className)){
8447                     var re = this.classReCache[className];
8448                     if (!re) {
8449                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8450                        this.classReCache[className] = re;
8451                     }
8452                     if (this.dom instanceof SVGElement) {
8453                         this.dom.className.baseVal = cn.replace(re, " ");
8454                     } else {
8455                         this.dom.className = cn.replace(re, " ");
8456                     }
8457                 }
8458             }
8459             return this;
8460         },
8461
8462         // private
8463         classReCache: {},
8464
8465         /**
8466          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8467          * @param {String} className The CSS class to toggle
8468          * @return {Roo.Element} this
8469          */
8470         toggleClass : function(className){
8471             if(this.hasClass(className)){
8472                 this.removeClass(className);
8473             }else{
8474                 this.addClass(className);
8475             }
8476             return this;
8477         },
8478
8479         /**
8480          * Checks if the specified CSS class exists on this element's DOM node.
8481          * @param {String} className The CSS class to check for
8482          * @return {Boolean} True if the class exists, else false
8483          */
8484         hasClass : function(className){
8485             if (this.dom instanceof SVGElement) {
8486                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
8487             } 
8488             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8489         },
8490
8491         /**
8492          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
8493          * @param {String} oldClassName The CSS class to replace
8494          * @param {String} newClassName The replacement CSS class
8495          * @return {Roo.Element} this
8496          */
8497         replaceClass : function(oldClassName, newClassName){
8498             this.removeClass(oldClassName);
8499             this.addClass(newClassName);
8500             return this;
8501         },
8502
8503         /**
8504          * Returns an object with properties matching the styles requested.
8505          * For example, el.getStyles('color', 'font-size', 'width') might return
8506          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8507          * @param {String} style1 A style name
8508          * @param {String} style2 A style name
8509          * @param {String} etc.
8510          * @return {Object} The style object
8511          */
8512         getStyles : function(){
8513             var a = arguments, len = a.length, r = {};
8514             for(var i = 0; i < len; i++){
8515                 r[a[i]] = this.getStyle(a[i]);
8516             }
8517             return r;
8518         },
8519
8520         /**
8521          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8522          * @param {String} property The style property whose value is returned.
8523          * @return {String} The current value of the style property for this element.
8524          */
8525         getStyle : function(){
8526             return view && view.getComputedStyle ?
8527                 function(prop){
8528                     var el = this.dom, v, cs, camel;
8529                     if(prop == 'float'){
8530                         prop = "cssFloat";
8531                     }
8532                     if(el.style && (v = el.style[prop])){
8533                         return v;
8534                     }
8535                     if(cs = view.getComputedStyle(el, "")){
8536                         if(!(camel = propCache[prop])){
8537                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
8538                         }
8539                         return cs[camel];
8540                     }
8541                     return null;
8542                 } :
8543                 function(prop){
8544                     var el = this.dom, v, cs, camel;
8545                     if(prop == 'opacity'){
8546                         if(typeof el.style.filter == 'string'){
8547                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8548                             if(m){
8549                                 var fv = parseFloat(m[1]);
8550                                 if(!isNaN(fv)){
8551                                     return fv ? fv / 100 : 0;
8552                                 }
8553                             }
8554                         }
8555                         return 1;
8556                     }else if(prop == 'float'){
8557                         prop = "styleFloat";
8558                     }
8559                     if(!(camel = propCache[prop])){
8560                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
8561                     }
8562                     if(v = el.style[camel]){
8563                         return v;
8564                     }
8565                     if(cs = el.currentStyle){
8566                         return cs[camel];
8567                     }
8568                     return null;
8569                 };
8570         }(),
8571
8572         /**
8573          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8574          * @param {String/Object} property The style property to be set, or an object of multiple styles.
8575          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8576          * @return {Roo.Element} this
8577          */
8578         setStyle : function(prop, value){
8579             if(typeof prop == "string"){
8580                 
8581                 if (prop == 'float') {
8582                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
8583                     return this;
8584                 }
8585                 
8586                 var camel;
8587                 if(!(camel = propCache[prop])){
8588                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
8589                 }
8590                 
8591                 if(camel == 'opacity') {
8592                     this.setOpacity(value);
8593                 }else{
8594                     this.dom.style[camel] = value;
8595                 }
8596             }else{
8597                 for(var style in prop){
8598                     if(typeof prop[style] != "function"){
8599                        this.setStyle(style, prop[style]);
8600                     }
8601                 }
8602             }
8603             return this;
8604         },
8605
8606         /**
8607          * More flexible version of {@link #setStyle} for setting style properties.
8608          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8609          * a function which returns such a specification.
8610          * @return {Roo.Element} this
8611          */
8612         applyStyles : function(style){
8613             Roo.DomHelper.applyStyles(this.dom, style);
8614             return this;
8615         },
8616
8617         /**
8618           * 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).
8619           * @return {Number} The X position of the element
8620           */
8621         getX : function(){
8622             return D.getX(this.dom);
8623         },
8624
8625         /**
8626           * 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).
8627           * @return {Number} The Y position of the element
8628           */
8629         getY : function(){
8630             return D.getY(this.dom);
8631         },
8632
8633         /**
8634           * 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).
8635           * @return {Array} The XY position of the element
8636           */
8637         getXY : function(){
8638             return D.getXY(this.dom);
8639         },
8640
8641         /**
8642          * 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).
8643          * @param {Number} The X position of the element
8644          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8645          * @return {Roo.Element} this
8646          */
8647         setX : function(x, animate){
8648             if(!animate || !A){
8649                 D.setX(this.dom, x);
8650             }else{
8651                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8652             }
8653             return this;
8654         },
8655
8656         /**
8657          * 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).
8658          * @param {Number} The Y position of the element
8659          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8660          * @return {Roo.Element} this
8661          */
8662         setY : function(y, animate){
8663             if(!animate || !A){
8664                 D.setY(this.dom, y);
8665             }else{
8666                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8667             }
8668             return this;
8669         },
8670
8671         /**
8672          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8673          * @param {String} left The left CSS property value
8674          * @return {Roo.Element} this
8675          */
8676         setLeft : function(left){
8677             this.setStyle("left", this.addUnits(left));
8678             return this;
8679         },
8680
8681         /**
8682          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8683          * @param {String} top The top CSS property value
8684          * @return {Roo.Element} this
8685          */
8686         setTop : function(top){
8687             this.setStyle("top", this.addUnits(top));
8688             return this;
8689         },
8690
8691         /**
8692          * Sets the element's CSS right style.
8693          * @param {String} right The right CSS property value
8694          * @return {Roo.Element} this
8695          */
8696         setRight : function(right){
8697             this.setStyle("right", this.addUnits(right));
8698             return this;
8699         },
8700
8701         /**
8702          * Sets the element's CSS bottom style.
8703          * @param {String} bottom The bottom CSS property value
8704          * @return {Roo.Element} this
8705          */
8706         setBottom : function(bottom){
8707             this.setStyle("bottom", this.addUnits(bottom));
8708             return this;
8709         },
8710
8711         /**
8712          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8713          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8714          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8715          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8716          * @return {Roo.Element} this
8717          */
8718         setXY : function(pos, animate){
8719             if(!animate || !A){
8720                 D.setXY(this.dom, pos);
8721             }else{
8722                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8723             }
8724             return this;
8725         },
8726
8727         /**
8728          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8729          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8730          * @param {Number} x X value for new position (coordinates are page-based)
8731          * @param {Number} y Y value for new position (coordinates are page-based)
8732          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8733          * @return {Roo.Element} this
8734          */
8735         setLocation : function(x, y, animate){
8736             this.setXY([x, y], this.preanim(arguments, 2));
8737             return this;
8738         },
8739
8740         /**
8741          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8742          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8743          * @param {Number} x X value for new position (coordinates are page-based)
8744          * @param {Number} y Y value for new position (coordinates are page-based)
8745          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8746          * @return {Roo.Element} this
8747          */
8748         moveTo : function(x, y, animate){
8749             this.setXY([x, y], this.preanim(arguments, 2));
8750             return this;
8751         },
8752
8753         /**
8754          * Returns the region of the given element.
8755          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8756          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8757          */
8758         getRegion : function(){
8759             return D.getRegion(this.dom);
8760         },
8761
8762         /**
8763          * Returns the offset height of the element
8764          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8765          * @return {Number} The element's height
8766          */
8767         getHeight : function(contentHeight){
8768             var h = this.dom.offsetHeight || 0;
8769             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8770         },
8771
8772         /**
8773          * Returns the offset width of the element
8774          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8775          * @return {Number} The element's width
8776          */
8777         getWidth : function(contentWidth){
8778             var w = this.dom.offsetWidth || 0;
8779             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8780         },
8781
8782         /**
8783          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8784          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8785          * if a height has not been set using CSS.
8786          * @return {Number}
8787          */
8788         getComputedHeight : function(){
8789             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8790             if(!h){
8791                 h = parseInt(this.getStyle('height'), 10) || 0;
8792                 if(!this.isBorderBox()){
8793                     h += this.getFrameWidth('tb');
8794                 }
8795             }
8796             return h;
8797         },
8798
8799         /**
8800          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8801          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8802          * if a width has not been set using CSS.
8803          * @return {Number}
8804          */
8805         getComputedWidth : function(){
8806             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8807             if(!w){
8808                 w = parseInt(this.getStyle('width'), 10) || 0;
8809                 if(!this.isBorderBox()){
8810                     w += this.getFrameWidth('lr');
8811                 }
8812             }
8813             return w;
8814         },
8815
8816         /**
8817          * Returns the size of the element.
8818          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8819          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8820          */
8821         getSize : function(contentSize){
8822             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8823         },
8824
8825         /**
8826          * Returns the width and height of the viewport.
8827          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8828          */
8829         getViewSize : function(){
8830             var d = this.dom, doc = document, aw = 0, ah = 0;
8831             if(d == doc || d == doc.body){
8832                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8833             }else{
8834                 return {
8835                     width : d.clientWidth,
8836                     height: d.clientHeight
8837                 };
8838             }
8839         },
8840
8841         /**
8842          * Returns the value of the "value" attribute
8843          * @param {Boolean} asNumber true to parse the value as a number
8844          * @return {String/Number}
8845          */
8846         getValue : function(asNumber){
8847             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8848         },
8849
8850         // private
8851         adjustWidth : function(width){
8852             if(typeof width == "number"){
8853                 if(this.autoBoxAdjust && !this.isBorderBox()){
8854                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8855                 }
8856                 if(width < 0){
8857                     width = 0;
8858                 }
8859             }
8860             return width;
8861         },
8862
8863         // private
8864         adjustHeight : function(height){
8865             if(typeof height == "number"){
8866                if(this.autoBoxAdjust && !this.isBorderBox()){
8867                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8868                }
8869                if(height < 0){
8870                    height = 0;
8871                }
8872             }
8873             return height;
8874         },
8875
8876         /**
8877          * Set the width of the element
8878          * @param {Number} width The new width
8879          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8880          * @return {Roo.Element} this
8881          */
8882         setWidth : function(width, animate){
8883             width = this.adjustWidth(width);
8884             if(!animate || !A){
8885                 this.dom.style.width = this.addUnits(width);
8886             }else{
8887                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8888             }
8889             return this;
8890         },
8891
8892         /**
8893          * Set the height of the element
8894          * @param {Number} height The new height
8895          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8896          * @return {Roo.Element} this
8897          */
8898          setHeight : function(height, animate){
8899             height = this.adjustHeight(height);
8900             if(!animate || !A){
8901                 this.dom.style.height = this.addUnits(height);
8902             }else{
8903                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8904             }
8905             return this;
8906         },
8907
8908         /**
8909          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8910          * @param {Number} width The new width
8911          * @param {Number} height The new height
8912          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8913          * @return {Roo.Element} this
8914          */
8915          setSize : function(width, height, animate){
8916             if(typeof width == "object"){ // in case of object from getSize()
8917                 height = width.height; width = width.width;
8918             }
8919             width = this.adjustWidth(width); height = this.adjustHeight(height);
8920             if(!animate || !A){
8921                 this.dom.style.width = this.addUnits(width);
8922                 this.dom.style.height = this.addUnits(height);
8923             }else{
8924                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8925             }
8926             return this;
8927         },
8928
8929         /**
8930          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8931          * @param {Number} x X value for new position (coordinates are page-based)
8932          * @param {Number} y Y value for new position (coordinates are page-based)
8933          * @param {Number} width The new width
8934          * @param {Number} height The new height
8935          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8936          * @return {Roo.Element} this
8937          */
8938         setBounds : function(x, y, width, height, animate){
8939             if(!animate || !A){
8940                 this.setSize(width, height);
8941                 this.setLocation(x, y);
8942             }else{
8943                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8944                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8945                               this.preanim(arguments, 4), 'motion');
8946             }
8947             return this;
8948         },
8949
8950         /**
8951          * 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.
8952          * @param {Roo.lib.Region} region The region to fill
8953          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8954          * @return {Roo.Element} this
8955          */
8956         setRegion : function(region, animate){
8957             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8958             return this;
8959         },
8960
8961         /**
8962          * Appends an event handler
8963          *
8964          * @param {String}   eventName     The type of event to append
8965          * @param {Function} fn        The method the event invokes
8966          * @param {Object} scope       (optional) The scope (this object) of the fn
8967          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8968          */
8969         addListener : function(eventName, fn, scope, options)
8970         {
8971             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
8972                 this.addListener('touchstart', this.onTapHandler, this);
8973             }
8974             
8975             // we need to handle a special case where dom element is a svg element.
8976             // in this case we do not actua
8977             if (!this.dom) {
8978                 return;
8979             }
8980             
8981             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
8982                 if (typeof(this.listeners[eventName]) == 'undefined') {
8983                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
8984                 }
8985                 this.listeners[eventName].addListener(fn, scope, options);
8986                 return;
8987             }
8988             
8989                 
8990             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8991             
8992             
8993         },
8994         tapedTwice : false,
8995         onTapHandler : function(event)
8996         {
8997             if(!this.tapedTwice) {
8998                 this.tapedTwice = true;
8999                 var s = this;
9000                 setTimeout( function() {
9001                     s.tapedTwice = false;
9002                 }, 300 );
9003                 return;
9004             }
9005             event.preventDefault();
9006             var revent = new MouseEvent('dblclick',  {
9007                 view: window,
9008                 bubbles: true,
9009                 cancelable: true
9010             });
9011              
9012             this.dom.dispatchEvent(revent);
9013             //action on double tap goes below
9014              
9015         }, 
9016  
9017         /**
9018          * Removes an event handler from this element
9019          * @param {String} eventName the type of event to remove
9020          * @param {Function} fn the method the event invokes
9021          * @param {Function} scope (needed for svg fake listeners)
9022          * @return {Roo.Element} this
9023          */
9024         removeListener : function(eventName, fn, scope){
9025             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9026             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9027                 return this;
9028             }
9029             this.listeners[eventName].removeListener(fn, scope);
9030             return this;
9031         },
9032
9033         /**
9034          * Removes all previous added listeners from this element
9035          * @return {Roo.Element} this
9036          */
9037         removeAllListeners : function(){
9038             E.purgeElement(this.dom);
9039             this.listeners = {};
9040             return this;
9041         },
9042
9043         relayEvent : function(eventName, observable){
9044             this.on(eventName, function(e){
9045                 observable.fireEvent(eventName, e);
9046             });
9047         },
9048
9049         
9050         /**
9051          * Set the opacity of the element
9052          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9053          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9054          * @return {Roo.Element} this
9055          */
9056          setOpacity : function(opacity, animate){
9057             if(!animate || !A){
9058                 var s = this.dom.style;
9059                 if(Roo.isIE){
9060                     s.zoom = 1;
9061                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9062                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9063                 }else{
9064                     s.opacity = opacity;
9065                 }
9066             }else{
9067                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9068             }
9069             return this;
9070         },
9071
9072         /**
9073          * Gets the left X coordinate
9074          * @param {Boolean} local True to get the local css position instead of page coordinate
9075          * @return {Number}
9076          */
9077         getLeft : function(local){
9078             if(!local){
9079                 return this.getX();
9080             }else{
9081                 return parseInt(this.getStyle("left"), 10) || 0;
9082             }
9083         },
9084
9085         /**
9086          * Gets the right X coordinate of the element (element X position + element width)
9087          * @param {Boolean} local True to get the local css position instead of page coordinate
9088          * @return {Number}
9089          */
9090         getRight : function(local){
9091             if(!local){
9092                 return this.getX() + this.getWidth();
9093             }else{
9094                 return (this.getLeft(true) + this.getWidth()) || 0;
9095             }
9096         },
9097
9098         /**
9099          * Gets the top Y coordinate
9100          * @param {Boolean} local True to get the local css position instead of page coordinate
9101          * @return {Number}
9102          */
9103         getTop : function(local) {
9104             if(!local){
9105                 return this.getY();
9106             }else{
9107                 return parseInt(this.getStyle("top"), 10) || 0;
9108             }
9109         },
9110
9111         /**
9112          * Gets the bottom Y coordinate of the element (element Y position + element height)
9113          * @param {Boolean} local True to get the local css position instead of page coordinate
9114          * @return {Number}
9115          */
9116         getBottom : function(local){
9117             if(!local){
9118                 return this.getY() + this.getHeight();
9119             }else{
9120                 return (this.getTop(true) + this.getHeight()) || 0;
9121             }
9122         },
9123
9124         /**
9125         * Initializes positioning on this element. If a desired position is not passed, it will make the
9126         * the element positioned relative IF it is not already positioned.
9127         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9128         * @param {Number} zIndex (optional) The zIndex to apply
9129         * @param {Number} x (optional) Set the page X position
9130         * @param {Number} y (optional) Set the page Y position
9131         */
9132         position : function(pos, zIndex, x, y){
9133             if(!pos){
9134                if(this.getStyle('position') == 'static'){
9135                    this.setStyle('position', 'relative');
9136                }
9137             }else{
9138                 this.setStyle("position", pos);
9139             }
9140             if(zIndex){
9141                 this.setStyle("z-index", zIndex);
9142             }
9143             if(x !== undefined && y !== undefined){
9144                 this.setXY([x, y]);
9145             }else if(x !== undefined){
9146                 this.setX(x);
9147             }else if(y !== undefined){
9148                 this.setY(y);
9149             }
9150         },
9151
9152         /**
9153         * Clear positioning back to the default when the document was loaded
9154         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9155         * @return {Roo.Element} this
9156          */
9157         clearPositioning : function(value){
9158             value = value ||'';
9159             this.setStyle({
9160                 "left": value,
9161                 "right": value,
9162                 "top": value,
9163                 "bottom": value,
9164                 "z-index": "",
9165                 "position" : "static"
9166             });
9167             return this;
9168         },
9169
9170         /**
9171         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9172         * snapshot before performing an update and then restoring the element.
9173         * @return {Object}
9174         */
9175         getPositioning : function(){
9176             var l = this.getStyle("left");
9177             var t = this.getStyle("top");
9178             return {
9179                 "position" : this.getStyle("position"),
9180                 "left" : l,
9181                 "right" : l ? "" : this.getStyle("right"),
9182                 "top" : t,
9183                 "bottom" : t ? "" : this.getStyle("bottom"),
9184                 "z-index" : this.getStyle("z-index")
9185             };
9186         },
9187
9188         /**
9189          * Gets the width of the border(s) for the specified side(s)
9190          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9191          * passing lr would get the border (l)eft width + the border (r)ight width.
9192          * @return {Number} The width of the sides passed added together
9193          */
9194         getBorderWidth : function(side){
9195             return this.addStyles(side, El.borders);
9196         },
9197
9198         /**
9199          * Gets the width of the padding(s) for the specified side(s)
9200          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9201          * passing lr would get the padding (l)eft + the padding (r)ight.
9202          * @return {Number} The padding of the sides passed added together
9203          */
9204         getPadding : function(side){
9205             return this.addStyles(side, El.paddings);
9206         },
9207
9208         /**
9209         * Set positioning with an object returned by getPositioning().
9210         * @param {Object} posCfg
9211         * @return {Roo.Element} this
9212          */
9213         setPositioning : function(pc){
9214             this.applyStyles(pc);
9215             if(pc.right == "auto"){
9216                 this.dom.style.right = "";
9217             }
9218             if(pc.bottom == "auto"){
9219                 this.dom.style.bottom = "";
9220             }
9221             return this;
9222         },
9223
9224         // private
9225         fixDisplay : function(){
9226             if(this.getStyle("display") == "none"){
9227                 this.setStyle("visibility", "hidden");
9228                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9229                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9230                     this.setStyle("display", "block");
9231                 }
9232             }
9233         },
9234
9235         /**
9236          * Quick set left and top adding default units
9237          * @param {String} left The left CSS property value
9238          * @param {String} top The top CSS property value
9239          * @return {Roo.Element} this
9240          */
9241          setLeftTop : function(left, top){
9242             this.dom.style.left = this.addUnits(left);
9243             this.dom.style.top = this.addUnits(top);
9244             return this;
9245         },
9246
9247         /**
9248          * Move this element relative to its current position.
9249          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9250          * @param {Number} distance How far to move the element in pixels
9251          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9252          * @return {Roo.Element} this
9253          */
9254          move : function(direction, distance, animate){
9255             var xy = this.getXY();
9256             direction = direction.toLowerCase();
9257             switch(direction){
9258                 case "l":
9259                 case "left":
9260                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9261                     break;
9262                case "r":
9263                case "right":
9264                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9265                     break;
9266                case "t":
9267                case "top":
9268                case "up":
9269                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9270                     break;
9271                case "b":
9272                case "bottom":
9273                case "down":
9274                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9275                     break;
9276             }
9277             return this;
9278         },
9279
9280         /**
9281          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9282          * @return {Roo.Element} this
9283          */
9284         clip : function(){
9285             if(!this.isClipped){
9286                this.isClipped = true;
9287                this.originalClip = {
9288                    "o": this.getStyle("overflow"),
9289                    "x": this.getStyle("overflow-x"),
9290                    "y": this.getStyle("overflow-y")
9291                };
9292                this.setStyle("overflow", "hidden");
9293                this.setStyle("overflow-x", "hidden");
9294                this.setStyle("overflow-y", "hidden");
9295             }
9296             return this;
9297         },
9298
9299         /**
9300          *  Return clipping (overflow) to original clipping before clip() was called
9301          * @return {Roo.Element} this
9302          */
9303         unclip : function(){
9304             if(this.isClipped){
9305                 this.isClipped = false;
9306                 var o = this.originalClip;
9307                 if(o.o){this.setStyle("overflow", o.o);}
9308                 if(o.x){this.setStyle("overflow-x", o.x);}
9309                 if(o.y){this.setStyle("overflow-y", o.y);}
9310             }
9311             return this;
9312         },
9313
9314
9315         /**
9316          * Gets the x,y coordinates specified by the anchor position on the element.
9317          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9318          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9319          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9320          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9321          * @return {Array} [x, y] An array containing the element's x and y coordinates
9322          */
9323         getAnchorXY : function(anchor, local, s){
9324             //Passing a different size is useful for pre-calculating anchors,
9325             //especially for anchored animations that change the el size.
9326
9327             var w, h, vp = false;
9328             if(!s){
9329                 var d = this.dom;
9330                 if(d == document.body || d == document){
9331                     vp = true;
9332                     w = D.getViewWidth(); h = D.getViewHeight();
9333                 }else{
9334                     w = this.getWidth(); h = this.getHeight();
9335                 }
9336             }else{
9337                 w = s.width;  h = s.height;
9338             }
9339             var x = 0, y = 0, r = Math.round;
9340             switch((anchor || "tl").toLowerCase()){
9341                 case "c":
9342                     x = r(w*.5);
9343                     y = r(h*.5);
9344                 break;
9345                 case "t":
9346                     x = r(w*.5);
9347                     y = 0;
9348                 break;
9349                 case "l":
9350                     x = 0;
9351                     y = r(h*.5);
9352                 break;
9353                 case "r":
9354                     x = w;
9355                     y = r(h*.5);
9356                 break;
9357                 case "b":
9358                     x = r(w*.5);
9359                     y = h;
9360                 break;
9361                 case "tl":
9362                     x = 0;
9363                     y = 0;
9364                 break;
9365                 case "bl":
9366                     x = 0;
9367                     y = h;
9368                 break;
9369                 case "br":
9370                     x = w;
9371                     y = h;
9372                 break;
9373                 case "tr":
9374                     x = w;
9375                     y = 0;
9376                 break;
9377             }
9378             if(local === true){
9379                 return [x, y];
9380             }
9381             if(vp){
9382                 var sc = this.getScroll();
9383                 return [x + sc.left, y + sc.top];
9384             }
9385             //Add the element's offset xy
9386             var o = this.getXY();
9387             return [x+o[0], y+o[1]];
9388         },
9389
9390         /**
9391          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9392          * supported position values.
9393          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9394          * @param {String} position The position to align to.
9395          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9396          * @return {Array} [x, y]
9397          */
9398         getAlignToXY : function(el, p, o)
9399         {
9400             el = Roo.get(el);
9401             var d = this.dom;
9402             if(!el.dom){
9403                 throw "Element.alignTo with an element that doesn't exist";
9404             }
9405             var c = false; //constrain to viewport
9406             var p1 = "", p2 = "";
9407             o = o || [0,0];
9408
9409             if(!p){
9410                 p = "tl-bl";
9411             }else if(p == "?"){
9412                 p = "tl-bl?";
9413             }else if(p.indexOf("-") == -1){
9414                 p = "tl-" + p;
9415             }
9416             p = p.toLowerCase();
9417             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9418             if(!m){
9419                throw "Element.alignTo with an invalid alignment " + p;
9420             }
9421             p1 = m[1]; p2 = m[2]; c = !!m[3];
9422
9423             //Subtract the aligned el's internal xy from the target's offset xy
9424             //plus custom offset to get the aligned el's new offset xy
9425             var a1 = this.getAnchorXY(p1, true);
9426             var a2 = el.getAnchorXY(p2, false);
9427             var x = a2[0] - a1[0] + o[0];
9428             var y = a2[1] - a1[1] + o[1];
9429             if(c){
9430                 //constrain the aligned el to viewport if necessary
9431                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9432                 // 5px of margin for ie
9433                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9434
9435                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9436                 //perpendicular to the vp border, allow the aligned el to slide on that border,
9437                 //otherwise swap the aligned el to the opposite border of the target.
9438                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9439                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9440                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
9441                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9442
9443                var doc = document;
9444                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9445                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9446
9447                if((x+w) > dw + scrollX){
9448                     x = swapX ? r.left-w : dw+scrollX-w;
9449                 }
9450                if(x < scrollX){
9451                    x = swapX ? r.right : scrollX;
9452                }
9453                if((y+h) > dh + scrollY){
9454                     y = swapY ? r.top-h : dh+scrollY-h;
9455                 }
9456                if (y < scrollY){
9457                    y = swapY ? r.bottom : scrollY;
9458                }
9459             }
9460             return [x,y];
9461         },
9462
9463         // private
9464         getConstrainToXY : function(){
9465             var os = {top:0, left:0, bottom:0, right: 0};
9466
9467             return function(el, local, offsets, proposedXY){
9468                 el = Roo.get(el);
9469                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9470
9471                 var vw, vh, vx = 0, vy = 0;
9472                 if(el.dom == document.body || el.dom == document){
9473                     vw = Roo.lib.Dom.getViewWidth();
9474                     vh = Roo.lib.Dom.getViewHeight();
9475                 }else{
9476                     vw = el.dom.clientWidth;
9477                     vh = el.dom.clientHeight;
9478                     if(!local){
9479                         var vxy = el.getXY();
9480                         vx = vxy[0];
9481                         vy = vxy[1];
9482                     }
9483                 }
9484
9485                 var s = el.getScroll();
9486
9487                 vx += offsets.left + s.left;
9488                 vy += offsets.top + s.top;
9489
9490                 vw -= offsets.right;
9491                 vh -= offsets.bottom;
9492
9493                 var vr = vx+vw;
9494                 var vb = vy+vh;
9495
9496                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9497                 var x = xy[0], y = xy[1];
9498                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9499
9500                 // only move it if it needs it
9501                 var moved = false;
9502
9503                 // first validate right/bottom
9504                 if((x + w) > vr){
9505                     x = vr - w;
9506                     moved = true;
9507                 }
9508                 if((y + h) > vb){
9509                     y = vb - h;
9510                     moved = true;
9511                 }
9512                 // then make sure top/left isn't negative
9513                 if(x < vx){
9514                     x = vx;
9515                     moved = true;
9516                 }
9517                 if(y < vy){
9518                     y = vy;
9519                     moved = true;
9520                 }
9521                 return moved ? [x, y] : false;
9522             };
9523         }(),
9524
9525         // private
9526         adjustForConstraints : function(xy, parent, offsets){
9527             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
9528         },
9529
9530         /**
9531          * Aligns this element with another element relative to the specified anchor points. If the other element is the
9532          * document it aligns it to the viewport.
9533          * The position parameter is optional, and can be specified in any one of the following formats:
9534          * <ul>
9535          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9536          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9537          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
9538          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
9539          *   <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
9540          *       element's anchor point, and the second value is used as the target's anchor point.</li>
9541          * </ul>
9542          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
9543          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9544          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
9545          * that specified in order to enforce the viewport constraints.
9546          * Following are all of the supported anchor positions:
9547     <pre>
9548     Value  Description
9549     -----  -----------------------------
9550     tl     The top left corner (default)
9551     t      The center of the top edge
9552     tr     The top right corner
9553     l      The center of the left edge
9554     c      In the center of the element
9555     r      The center of the right edge
9556     bl     The bottom left corner
9557     b      The center of the bottom edge
9558     br     The bottom right corner
9559     </pre>
9560     Example Usage:
9561     <pre><code>
9562     // align el to other-el using the default positioning ("tl-bl", non-constrained)
9563     el.alignTo("other-el");
9564
9565     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9566     el.alignTo("other-el", "tr?");
9567
9568     // align the bottom right corner of el with the center left edge of other-el
9569     el.alignTo("other-el", "br-l?");
9570
9571     // align the center of el with the bottom left corner of other-el and
9572     // adjust the x position by -6 pixels (and the y position by 0)
9573     el.alignTo("other-el", "c-bl", [-6, 0]);
9574     </code></pre>
9575          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9576          * @param {String} position The position to align to.
9577          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9578          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9579          * @return {Roo.Element} this
9580          */
9581         alignTo : function(element, position, offsets, animate){
9582             var xy = this.getAlignToXY(element, position, offsets);
9583             this.setXY(xy, this.preanim(arguments, 3));
9584             return this;
9585         },
9586
9587         /**
9588          * Anchors an element to another element and realigns it when the window is resized.
9589          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9590          * @param {String} position The position to align to.
9591          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9592          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9593          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9594          * is a number, it is used as the buffer delay (defaults to 50ms).
9595          * @param {Function} callback The function to call after the animation finishes
9596          * @return {Roo.Element} this
9597          */
9598         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9599             var action = function(){
9600                 this.alignTo(el, alignment, offsets, animate);
9601                 Roo.callback(callback, this);
9602             };
9603             Roo.EventManager.onWindowResize(action, this);
9604             var tm = typeof monitorScroll;
9605             if(tm != 'undefined'){
9606                 Roo.EventManager.on(window, 'scroll', action, this,
9607                     {buffer: tm == 'number' ? monitorScroll : 50});
9608             }
9609             action.call(this); // align immediately
9610             return this;
9611         },
9612         /**
9613          * Clears any opacity settings from this element. Required in some cases for IE.
9614          * @return {Roo.Element} this
9615          */
9616         clearOpacity : function(){
9617             if (window.ActiveXObject) {
9618                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9619                     this.dom.style.filter = "";
9620                 }
9621             } else {
9622                 this.dom.style.opacity = "";
9623                 this.dom.style["-moz-opacity"] = "";
9624                 this.dom.style["-khtml-opacity"] = "";
9625             }
9626             return this;
9627         },
9628
9629         /**
9630          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9631          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9632          * @return {Roo.Element} this
9633          */
9634         hide : function(animate){
9635             this.setVisible(false, this.preanim(arguments, 0));
9636             return this;
9637         },
9638
9639         /**
9640         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9641         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9642          * @return {Roo.Element} this
9643          */
9644         show : function(animate){
9645             this.setVisible(true, this.preanim(arguments, 0));
9646             return this;
9647         },
9648
9649         /**
9650          * @private Test if size has a unit, otherwise appends the default
9651          */
9652         addUnits : function(size){
9653             return Roo.Element.addUnits(size, this.defaultUnit);
9654         },
9655
9656         /**
9657          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9658          * @return {Roo.Element} this
9659          */
9660         beginMeasure : function(){
9661             var el = this.dom;
9662             if(el.offsetWidth || el.offsetHeight){
9663                 return this; // offsets work already
9664             }
9665             var changed = [];
9666             var p = this.dom, b = document.body; // start with this element
9667             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9668                 var pe = Roo.get(p);
9669                 if(pe.getStyle('display') == 'none'){
9670                     changed.push({el: p, visibility: pe.getStyle("visibility")});
9671                     p.style.visibility = "hidden";
9672                     p.style.display = "block";
9673                 }
9674                 p = p.parentNode;
9675             }
9676             this._measureChanged = changed;
9677             return this;
9678
9679         },
9680
9681         /**
9682          * Restores displays to before beginMeasure was called
9683          * @return {Roo.Element} this
9684          */
9685         endMeasure : function(){
9686             var changed = this._measureChanged;
9687             if(changed){
9688                 for(var i = 0, len = changed.length; i < len; i++) {
9689                     var r = changed[i];
9690                     r.el.style.visibility = r.visibility;
9691                     r.el.style.display = "none";
9692                 }
9693                 this._measureChanged = null;
9694             }
9695             return this;
9696         },
9697
9698         /**
9699         * Update the innerHTML of this element, optionally searching for and processing scripts
9700         * @param {String} html The new HTML
9701         * @param {Boolean} loadScripts (optional) true to look for and process scripts
9702         * @param {Function} callback For async script loading you can be noticed when the update completes
9703         * @return {Roo.Element} this
9704          */
9705         update : function(html, loadScripts, callback){
9706             if(typeof html == "undefined"){
9707                 html = "";
9708             }
9709             if(loadScripts !== true){
9710                 this.dom.innerHTML = html;
9711                 if(typeof callback == "function"){
9712                     callback();
9713                 }
9714                 return this;
9715             }
9716             var id = Roo.id();
9717             var dom = this.dom;
9718
9719             html += '<span id="' + id + '"></span>';
9720
9721             E.onAvailable(id, function(){
9722                 var hd = document.getElementsByTagName("head")[0];
9723                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9724                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9725                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9726
9727                 var match;
9728                 while(match = re.exec(html)){
9729                     var attrs = match[1];
9730                     var srcMatch = attrs ? attrs.match(srcRe) : false;
9731                     if(srcMatch && srcMatch[2]){
9732                        var s = document.createElement("script");
9733                        s.src = srcMatch[2];
9734                        var typeMatch = attrs.match(typeRe);
9735                        if(typeMatch && typeMatch[2]){
9736                            s.type = typeMatch[2];
9737                        }
9738                        hd.appendChild(s);
9739                     }else if(match[2] && match[2].length > 0){
9740                         if(window.execScript) {
9741                            window.execScript(match[2]);
9742                         } else {
9743                             /**
9744                              * eval:var:id
9745                              * eval:var:dom
9746                              * eval:var:html
9747                              * 
9748                              */
9749                            window.eval(match[2]);
9750                         }
9751                     }
9752                 }
9753                 var el = document.getElementById(id);
9754                 if(el){el.parentNode.removeChild(el);}
9755                 if(typeof callback == "function"){
9756                     callback();
9757                 }
9758             });
9759             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9760             return this;
9761         },
9762
9763         /**
9764          * Direct access to the UpdateManager update() method (takes the same parameters).
9765          * @param {String/Function} url The url for this request or a function to call to get the url
9766          * @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}
9767          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9768          * @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.
9769          * @return {Roo.Element} this
9770          */
9771         load : function(){
9772             var um = this.getUpdateManager();
9773             um.update.apply(um, arguments);
9774             return this;
9775         },
9776
9777         /**
9778         * Gets this element's UpdateManager
9779         * @return {Roo.UpdateManager} The UpdateManager
9780         */
9781         getUpdateManager : function(){
9782             if(!this.updateManager){
9783                 this.updateManager = new Roo.UpdateManager(this);
9784             }
9785             return this.updateManager;
9786         },
9787
9788         /**
9789          * Disables text selection for this element (normalized across browsers)
9790          * @return {Roo.Element} this
9791          */
9792         unselectable : function(){
9793             this.dom.unselectable = "on";
9794             this.swallowEvent("selectstart", true);
9795             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9796             this.addClass("x-unselectable");
9797             return this;
9798         },
9799
9800         /**
9801         * Calculates the x, y to center this element on the screen
9802         * @return {Array} The x, y values [x, y]
9803         */
9804         getCenterXY : function(){
9805             return this.getAlignToXY(document, 'c-c');
9806         },
9807
9808         /**
9809         * Centers the Element in either the viewport, or another Element.
9810         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9811         */
9812         center : function(centerIn){
9813             this.alignTo(centerIn || document, 'c-c');
9814             return this;
9815         },
9816
9817         /**
9818          * Tests various css rules/browsers to determine if this element uses a border box
9819          * @return {Boolean}
9820          */
9821         isBorderBox : function(){
9822             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9823         },
9824
9825         /**
9826          * Return a box {x, y, width, height} that can be used to set another elements
9827          * size/location to match this element.
9828          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9829          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9830          * @return {Object} box An object in the format {x, y, width, height}
9831          */
9832         getBox : function(contentBox, local){
9833             var xy;
9834             if(!local){
9835                 xy = this.getXY();
9836             }else{
9837                 var left = parseInt(this.getStyle("left"), 10) || 0;
9838                 var top = parseInt(this.getStyle("top"), 10) || 0;
9839                 xy = [left, top];
9840             }
9841             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9842             if(!contentBox){
9843                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9844             }else{
9845                 var l = this.getBorderWidth("l")+this.getPadding("l");
9846                 var r = this.getBorderWidth("r")+this.getPadding("r");
9847                 var t = this.getBorderWidth("t")+this.getPadding("t");
9848                 var b = this.getBorderWidth("b")+this.getPadding("b");
9849                 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)};
9850             }
9851             bx.right = bx.x + bx.width;
9852             bx.bottom = bx.y + bx.height;
9853             return bx;
9854         },
9855
9856         /**
9857          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9858          for more information about the sides.
9859          * @param {String} sides
9860          * @return {Number}
9861          */
9862         getFrameWidth : function(sides, onlyContentBox){
9863             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9864         },
9865
9866         /**
9867          * 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.
9868          * @param {Object} box The box to fill {x, y, width, height}
9869          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9870          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9871          * @return {Roo.Element} this
9872          */
9873         setBox : function(box, adjust, animate){
9874             var w = box.width, h = box.height;
9875             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9876                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9877                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9878             }
9879             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9880             return this;
9881         },
9882
9883         /**
9884          * Forces the browser to repaint this element
9885          * @return {Roo.Element} this
9886          */
9887          repaint : function(){
9888             var dom = this.dom;
9889             this.addClass("x-repaint");
9890             setTimeout(function(){
9891                 Roo.get(dom).removeClass("x-repaint");
9892             }, 1);
9893             return this;
9894         },
9895
9896         /**
9897          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9898          * then it returns the calculated width of the sides (see getPadding)
9899          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9900          * @return {Object/Number}
9901          */
9902         getMargins : function(side){
9903             if(!side){
9904                 return {
9905                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9906                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9907                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9908                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9909                 };
9910             }else{
9911                 return this.addStyles(side, El.margins);
9912              }
9913         },
9914
9915         // private
9916         addStyles : function(sides, styles){
9917             var val = 0, v, w;
9918             for(var i = 0, len = sides.length; i < len; i++){
9919                 v = this.getStyle(styles[sides.charAt(i)]);
9920                 if(v){
9921                      w = parseInt(v, 10);
9922                      if(w){ val += w; }
9923                 }
9924             }
9925             return val;
9926         },
9927
9928         /**
9929          * Creates a proxy element of this element
9930          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9931          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9932          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9933          * @return {Roo.Element} The new proxy element
9934          */
9935         createProxy : function(config, renderTo, matchBox){
9936             if(renderTo){
9937                 renderTo = Roo.getDom(renderTo);
9938             }else{
9939                 renderTo = document.body;
9940             }
9941             config = typeof config == "object" ?
9942                 config : {tag : "div", cls: config};
9943             var proxy = Roo.DomHelper.append(renderTo, config, true);
9944             if(matchBox){
9945                proxy.setBox(this.getBox());
9946             }
9947             return proxy;
9948         },
9949
9950         /**
9951          * Puts a mask over this element to disable user interaction. Requires core.css.
9952          * This method can only be applied to elements which accept child nodes.
9953          * @param {String} msg (optional) A message to display in the mask
9954          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
9955          * @return {Element} The mask  element
9956          */
9957         mask : function(msg, msgCls)
9958         {
9959             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9960                 this.setStyle("position", "relative");
9961             }
9962             if(!this._mask){
9963                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9964             }
9965             
9966             this.addClass("x-masked");
9967             this._mask.setDisplayed(true);
9968             
9969             // we wander
9970             var z = 0;
9971             var dom = this.dom;
9972             while (dom && dom.style) {
9973                 if (!isNaN(parseInt(dom.style.zIndex))) {
9974                     z = Math.max(z, parseInt(dom.style.zIndex));
9975                 }
9976                 dom = dom.parentNode;
9977             }
9978             // if we are masking the body - then it hides everything..
9979             if (this.dom == document.body) {
9980                 z = 1000000;
9981                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9982                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9983             }
9984            
9985             if(typeof msg == 'string'){
9986                 if(!this._maskMsg){
9987                     this._maskMsg = Roo.DomHelper.append(this.dom, {
9988                         cls: "roo-el-mask-msg", 
9989                         cn: [
9990                             {
9991                                 tag: 'i',
9992                                 cls: 'fa fa-spinner fa-spin'
9993                             },
9994                             {
9995                                 tag: 'div'
9996                             }   
9997                         ]
9998                     }, true);
9999                 }
10000                 var mm = this._maskMsg;
10001                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10002                 if (mm.dom.lastChild) { // weird IE issue?
10003                     mm.dom.lastChild.innerHTML = msg;
10004                 }
10005                 mm.setDisplayed(true);
10006                 mm.center(this);
10007                 mm.setStyle('z-index', z + 102);
10008             }
10009             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10010                 this._mask.setHeight(this.getHeight());
10011             }
10012             this._mask.setStyle('z-index', z + 100);
10013             
10014             return this._mask;
10015         },
10016
10017         /**
10018          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10019          * it is cached for reuse.
10020          */
10021         unmask : function(removeEl){
10022             if(this._mask){
10023                 if(removeEl === true){
10024                     this._mask.remove();
10025                     delete this._mask;
10026                     if(this._maskMsg){
10027                         this._maskMsg.remove();
10028                         delete this._maskMsg;
10029                     }
10030                 }else{
10031                     this._mask.setDisplayed(false);
10032                     if(this._maskMsg){
10033                         this._maskMsg.setDisplayed(false);
10034                     }
10035                 }
10036             }
10037             this.removeClass("x-masked");
10038         },
10039
10040         /**
10041          * Returns true if this element is masked
10042          * @return {Boolean}
10043          */
10044         isMasked : function(){
10045             return this._mask && this._mask.isVisible();
10046         },
10047
10048         /**
10049          * Creates an iframe shim for this element to keep selects and other windowed objects from
10050          * showing through.
10051          * @return {Roo.Element} The new shim element
10052          */
10053         createShim : function(){
10054             var el = document.createElement('iframe');
10055             el.frameBorder = 'no';
10056             el.className = 'roo-shim';
10057             if(Roo.isIE && Roo.isSecure){
10058                 el.src = Roo.SSL_SECURE_URL;
10059             }
10060             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10061             shim.autoBoxAdjust = false;
10062             return shim;
10063         },
10064
10065         /**
10066          * Removes this element from the DOM and deletes it from the cache
10067          */
10068         remove : function(){
10069             if(this.dom.parentNode){
10070                 this.dom.parentNode.removeChild(this.dom);
10071             }
10072             delete El.cache[this.dom.id];
10073         },
10074
10075         /**
10076          * Sets up event handlers to add and remove a css class when the mouse is over this element
10077          * @param {String} className
10078          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10079          * mouseout events for children elements
10080          * @return {Roo.Element} this
10081          */
10082         addClassOnOver : function(className, preventFlicker){
10083             this.on("mouseover", function(){
10084                 Roo.fly(this, '_internal').addClass(className);
10085             }, this.dom);
10086             var removeFn = function(e){
10087                 if(preventFlicker !== true || !e.within(this, true)){
10088                     Roo.fly(this, '_internal').removeClass(className);
10089                 }
10090             };
10091             this.on("mouseout", removeFn, this.dom);
10092             return this;
10093         },
10094
10095         /**
10096          * Sets up event handlers to add and remove a css class when this element has the focus
10097          * @param {String} className
10098          * @return {Roo.Element} this
10099          */
10100         addClassOnFocus : function(className){
10101             this.on("focus", function(){
10102                 Roo.fly(this, '_internal').addClass(className);
10103             }, this.dom);
10104             this.on("blur", function(){
10105                 Roo.fly(this, '_internal').removeClass(className);
10106             }, this.dom);
10107             return this;
10108         },
10109         /**
10110          * 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)
10111          * @param {String} className
10112          * @return {Roo.Element} this
10113          */
10114         addClassOnClick : function(className){
10115             var dom = this.dom;
10116             this.on("mousedown", function(){
10117                 Roo.fly(dom, '_internal').addClass(className);
10118                 var d = Roo.get(document);
10119                 var fn = function(){
10120                     Roo.fly(dom, '_internal').removeClass(className);
10121                     d.removeListener("mouseup", fn);
10122                 };
10123                 d.on("mouseup", fn);
10124             });
10125             return this;
10126         },
10127
10128         /**
10129          * Stops the specified event from bubbling and optionally prevents the default action
10130          * @param {String} eventName
10131          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10132          * @return {Roo.Element} this
10133          */
10134         swallowEvent : function(eventName, preventDefault){
10135             var fn = function(e){
10136                 e.stopPropagation();
10137                 if(preventDefault){
10138                     e.preventDefault();
10139                 }
10140             };
10141             if(eventName instanceof Array){
10142                 for(var i = 0, len = eventName.length; i < len; i++){
10143                      this.on(eventName[i], fn);
10144                 }
10145                 return this;
10146             }
10147             this.on(eventName, fn);
10148             return this;
10149         },
10150
10151         /**
10152          * @private
10153          */
10154         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10155
10156         /**
10157          * Sizes this element to its parent element's dimensions performing
10158          * neccessary box adjustments.
10159          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10160          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10161          * @return {Roo.Element} this
10162          */
10163         fitToParent : function(monitorResize, targetParent) {
10164           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10165           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10166           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10167             return this;
10168           }
10169           var p = Roo.get(targetParent || this.dom.parentNode);
10170           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10171           if (monitorResize === true) {
10172             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10173             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10174           }
10175           return this;
10176         },
10177
10178         /**
10179          * Gets the next sibling, skipping text nodes
10180          * @return {HTMLElement} The next sibling or null
10181          */
10182         getNextSibling : function(){
10183             var n = this.dom.nextSibling;
10184             while(n && n.nodeType != 1){
10185                 n = n.nextSibling;
10186             }
10187             return n;
10188         },
10189
10190         /**
10191          * Gets the previous sibling, skipping text nodes
10192          * @return {HTMLElement} The previous sibling or null
10193          */
10194         getPrevSibling : function(){
10195             var n = this.dom.previousSibling;
10196             while(n && n.nodeType != 1){
10197                 n = n.previousSibling;
10198             }
10199             return n;
10200         },
10201
10202
10203         /**
10204          * Appends the passed element(s) to this element
10205          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10206          * @return {Roo.Element} this
10207          */
10208         appendChild: function(el){
10209             el = Roo.get(el);
10210             el.appendTo(this);
10211             return this;
10212         },
10213
10214         /**
10215          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10216          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10217          * automatically generated with the specified attributes.
10218          * @param {HTMLElement} insertBefore (optional) a child element of this element
10219          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10220          * @return {Roo.Element} The new child element
10221          */
10222         createChild: function(config, insertBefore, returnDom){
10223             config = config || {tag:'div'};
10224             if(insertBefore){
10225                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10226             }
10227             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10228         },
10229
10230         /**
10231          * Appends this element to the passed element
10232          * @param {String/HTMLElement/Element} el The new parent element
10233          * @return {Roo.Element} this
10234          */
10235         appendTo: function(el){
10236             el = Roo.getDom(el);
10237             el.appendChild(this.dom);
10238             return this;
10239         },
10240
10241         /**
10242          * Inserts this element before the passed element in the DOM
10243          * @param {String/HTMLElement/Element} el The element to insert before
10244          * @return {Roo.Element} this
10245          */
10246         insertBefore: function(el){
10247             el = Roo.getDom(el);
10248             el.parentNode.insertBefore(this.dom, el);
10249             return this;
10250         },
10251
10252         /**
10253          * Inserts this element after the passed element in the DOM
10254          * @param {String/HTMLElement/Element} el The element to insert after
10255          * @return {Roo.Element} this
10256          */
10257         insertAfter: function(el){
10258             el = Roo.getDom(el);
10259             el.parentNode.insertBefore(this.dom, el.nextSibling);
10260             return this;
10261         },
10262
10263         /**
10264          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10265          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10266          * @return {Roo.Element} The new child
10267          */
10268         insertFirst: function(el, returnDom){
10269             el = el || {};
10270             if(typeof el == 'object' && !el.nodeType){ // dh config
10271                 return this.createChild(el, this.dom.firstChild, returnDom);
10272             }else{
10273                 el = Roo.getDom(el);
10274                 this.dom.insertBefore(el, this.dom.firstChild);
10275                 return !returnDom ? Roo.get(el) : el;
10276             }
10277         },
10278
10279         /**
10280          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10281          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10282          * @param {String} where (optional) 'before' or 'after' defaults to before
10283          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10284          * @return {Roo.Element} the inserted Element
10285          */
10286         insertSibling: function(el, where, returnDom){
10287             where = where ? where.toLowerCase() : 'before';
10288             el = el || {};
10289             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10290
10291             if(typeof el == 'object' && !el.nodeType){ // dh config
10292                 if(where == 'after' && !this.dom.nextSibling){
10293                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10294                 }else{
10295                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10296                 }
10297
10298             }else{
10299                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10300                             where == 'before' ? this.dom : this.dom.nextSibling);
10301                 if(!returnDom){
10302                     rt = Roo.get(rt);
10303                 }
10304             }
10305             return rt;
10306         },
10307
10308         /**
10309          * Creates and wraps this element with another element
10310          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10311          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10312          * @return {HTMLElement/Element} The newly created wrapper element
10313          */
10314         wrap: function(config, returnDom){
10315             if(!config){
10316                 config = {tag: "div"};
10317             }
10318             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10319             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10320             return newEl;
10321         },
10322
10323         /**
10324          * Replaces the passed element with this element
10325          * @param {String/HTMLElement/Element} el The element to replace
10326          * @return {Roo.Element} this
10327          */
10328         replace: function(el){
10329             el = Roo.get(el);
10330             this.insertBefore(el);
10331             el.remove();
10332             return this;
10333         },
10334
10335         /**
10336          * Inserts an html fragment into this element
10337          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10338          * @param {String} html The HTML fragment
10339          * @param {Boolean} returnEl True to return an Roo.Element
10340          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10341          */
10342         insertHtml : function(where, html, returnEl){
10343             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10344             return returnEl ? Roo.get(el) : el;
10345         },
10346
10347         /**
10348          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10349          * @param {Object} o The object with the attributes
10350          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10351          * @return {Roo.Element} this
10352          */
10353         set : function(o, useSet){
10354             var el = this.dom;
10355             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10356             for(var attr in o){
10357                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10358                 if(attr=="cls"){
10359                     el.className = o["cls"];
10360                 }else{
10361                     if(useSet) {
10362                         el.setAttribute(attr, o[attr]);
10363                     } else {
10364                         el[attr] = o[attr];
10365                     }
10366                 }
10367             }
10368             if(o.style){
10369                 Roo.DomHelper.applyStyles(el, o.style);
10370             }
10371             return this;
10372         },
10373
10374         /**
10375          * Convenience method for constructing a KeyMap
10376          * @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:
10377          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10378          * @param {Function} fn The function to call
10379          * @param {Object} scope (optional) The scope of the function
10380          * @return {Roo.KeyMap} The KeyMap created
10381          */
10382         addKeyListener : function(key, fn, scope){
10383             var config;
10384             if(typeof key != "object" || key instanceof Array){
10385                 config = {
10386                     key: key,
10387                     fn: fn,
10388                     scope: scope
10389                 };
10390             }else{
10391                 config = {
10392                     key : key.key,
10393                     shift : key.shift,
10394                     ctrl : key.ctrl,
10395                     alt : key.alt,
10396                     fn: fn,
10397                     scope: scope
10398                 };
10399             }
10400             return new Roo.KeyMap(this, config);
10401         },
10402
10403         /**
10404          * Creates a KeyMap for this element
10405          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10406          * @return {Roo.KeyMap} The KeyMap created
10407          */
10408         addKeyMap : function(config){
10409             return new Roo.KeyMap(this, config);
10410         },
10411
10412         /**
10413          * Returns true if this element is scrollable.
10414          * @return {Boolean}
10415          */
10416          isScrollable : function(){
10417             var dom = this.dom;
10418             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10419         },
10420
10421         /**
10422          * 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().
10423          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10424          * @param {Number} value The new scroll value
10425          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10426          * @return {Element} this
10427          */
10428
10429         scrollTo : function(side, value, animate){
10430             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10431             if(!animate || !A){
10432                 this.dom[prop] = value;
10433             }else{
10434                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10435                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10436             }
10437             return this;
10438         },
10439
10440         /**
10441          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10442          * within this element's scrollable range.
10443          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10444          * @param {Number} distance How far to scroll the element in pixels
10445          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10446          * @return {Boolean} Returns true if a scroll was triggered or false if the element
10447          * was scrolled as far as it could go.
10448          */
10449          scroll : function(direction, distance, animate){
10450              if(!this.isScrollable()){
10451                  return;
10452              }
10453              var el = this.dom;
10454              var l = el.scrollLeft, t = el.scrollTop;
10455              var w = el.scrollWidth, h = el.scrollHeight;
10456              var cw = el.clientWidth, ch = el.clientHeight;
10457              direction = direction.toLowerCase();
10458              var scrolled = false;
10459              var a = this.preanim(arguments, 2);
10460              switch(direction){
10461                  case "l":
10462                  case "left":
10463                      if(w - l > cw){
10464                          var v = Math.min(l + distance, w-cw);
10465                          this.scrollTo("left", v, a);
10466                          scrolled = true;
10467                      }
10468                      break;
10469                 case "r":
10470                 case "right":
10471                      if(l > 0){
10472                          var v = Math.max(l - distance, 0);
10473                          this.scrollTo("left", v, a);
10474                          scrolled = true;
10475                      }
10476                      break;
10477                 case "t":
10478                 case "top":
10479                 case "up":
10480                      if(t > 0){
10481                          var v = Math.max(t - distance, 0);
10482                          this.scrollTo("top", v, a);
10483                          scrolled = true;
10484                      }
10485                      break;
10486                 case "b":
10487                 case "bottom":
10488                 case "down":
10489                      if(h - t > ch){
10490                          var v = Math.min(t + distance, h-ch);
10491                          this.scrollTo("top", v, a);
10492                          scrolled = true;
10493                      }
10494                      break;
10495              }
10496              return scrolled;
10497         },
10498
10499         /**
10500          * Translates the passed page coordinates into left/top css values for this element
10501          * @param {Number/Array} x The page x or an array containing [x, y]
10502          * @param {Number} y The page y
10503          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10504          */
10505         translatePoints : function(x, y){
10506             if(typeof x == 'object' || x instanceof Array){
10507                 y = x[1]; x = x[0];
10508             }
10509             var p = this.getStyle('position');
10510             var o = this.getXY();
10511
10512             var l = parseInt(this.getStyle('left'), 10);
10513             var t = parseInt(this.getStyle('top'), 10);
10514
10515             if(isNaN(l)){
10516                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10517             }
10518             if(isNaN(t)){
10519                 t = (p == "relative") ? 0 : this.dom.offsetTop;
10520             }
10521
10522             return {left: (x - o[0] + l), top: (y - o[1] + t)};
10523         },
10524
10525         /**
10526          * Returns the current scroll position of the element.
10527          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10528          */
10529         getScroll : function(){
10530             var d = this.dom, doc = document;
10531             if(d == doc || d == doc.body){
10532                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10533                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10534                 return {left: l, top: t};
10535             }else{
10536                 return {left: d.scrollLeft, top: d.scrollTop};
10537             }
10538         },
10539
10540         /**
10541          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10542          * are convert to standard 6 digit hex color.
10543          * @param {String} attr The css attribute
10544          * @param {String} defaultValue The default value to use when a valid color isn't found
10545          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10546          * YUI color anims.
10547          */
10548         getColor : function(attr, defaultValue, prefix){
10549             var v = this.getStyle(attr);
10550             if(!v || v == "transparent" || v == "inherit") {
10551                 return defaultValue;
10552             }
10553             var color = typeof prefix == "undefined" ? "#" : prefix;
10554             if(v.substr(0, 4) == "rgb("){
10555                 var rvs = v.slice(4, v.length -1).split(",");
10556                 for(var i = 0; i < 3; i++){
10557                     var h = parseInt(rvs[i]).toString(16);
10558                     if(h < 16){
10559                         h = "0" + h;
10560                     }
10561                     color += h;
10562                 }
10563             } else {
10564                 if(v.substr(0, 1) == "#"){
10565                     if(v.length == 4) {
10566                         for(var i = 1; i < 4; i++){
10567                             var c = v.charAt(i);
10568                             color +=  c + c;
10569                         }
10570                     }else if(v.length == 7){
10571                         color += v.substr(1);
10572                     }
10573                 }
10574             }
10575             return(color.length > 5 ? color.toLowerCase() : defaultValue);
10576         },
10577
10578         /**
10579          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10580          * gradient background, rounded corners and a 4-way shadow.
10581          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10582          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10583          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10584          * @return {Roo.Element} this
10585          */
10586         boxWrap : function(cls){
10587             cls = cls || 'x-box';
10588             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10589             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10590             return el;
10591         },
10592
10593         /**
10594          * Returns the value of a namespaced attribute from the element's underlying DOM node.
10595          * @param {String} namespace The namespace in which to look for the attribute
10596          * @param {String} name The attribute name
10597          * @return {String} The attribute value
10598          */
10599         getAttributeNS : Roo.isIE ? function(ns, name){
10600             var d = this.dom;
10601             var type = typeof d[ns+":"+name];
10602             if(type != 'undefined' && type != 'unknown'){
10603                 return d[ns+":"+name];
10604             }
10605             return d[name];
10606         } : function(ns, name){
10607             var d = this.dom;
10608             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10609         },
10610         
10611         
10612         /**
10613          * Sets or Returns the value the dom attribute value
10614          * @param {String|Object} name The attribute name (or object to set multiple attributes)
10615          * @param {String} value (optional) The value to set the attribute to
10616          * @return {String} The attribute value
10617          */
10618         attr : function(name){
10619             if (arguments.length > 1) {
10620                 this.dom.setAttribute(name, arguments[1]);
10621                 return arguments[1];
10622             }
10623             if (typeof(name) == 'object') {
10624                 for(var i in name) {
10625                     this.attr(i, name[i]);
10626                 }
10627                 return name;
10628             }
10629             
10630             
10631             if (!this.dom.hasAttribute(name)) {
10632                 return undefined;
10633             }
10634             return this.dom.getAttribute(name);
10635         }
10636         
10637         
10638         
10639     };
10640
10641     var ep = El.prototype;
10642
10643     /**
10644      * Appends an event handler (Shorthand for addListener)
10645      * @param {String}   eventName     The type of event to append
10646      * @param {Function} fn        The method the event invokes
10647      * @param {Object} scope       (optional) The scope (this object) of the fn
10648      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
10649      * @method
10650      */
10651     ep.on = ep.addListener;
10652         // backwards compat
10653     ep.mon = ep.addListener;
10654
10655     /**
10656      * Removes an event handler from this element (shorthand for removeListener)
10657      * @param {String} eventName the type of event to remove
10658      * @param {Function} fn the method the event invokes
10659      * @return {Roo.Element} this
10660      * @method
10661      */
10662     ep.un = ep.removeListener;
10663
10664     /**
10665      * true to automatically adjust width and height settings for box-model issues (default to true)
10666      */
10667     ep.autoBoxAdjust = true;
10668
10669     // private
10670     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10671
10672     // private
10673     El.addUnits = function(v, defaultUnit){
10674         if(v === "" || v == "auto"){
10675             return v;
10676         }
10677         if(v === undefined){
10678             return '';
10679         }
10680         if(typeof v == "number" || !El.unitPattern.test(v)){
10681             return v + (defaultUnit || 'px');
10682         }
10683         return v;
10684     };
10685
10686     // special markup used throughout Roo when box wrapping elements
10687     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>';
10688     /**
10689      * Visibility mode constant - Use visibility to hide element
10690      * @static
10691      * @type Number
10692      */
10693     El.VISIBILITY = 1;
10694     /**
10695      * Visibility mode constant - Use display to hide element
10696      * @static
10697      * @type Number
10698      */
10699     El.DISPLAY = 2;
10700
10701     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10702     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10703     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10704
10705
10706
10707     /**
10708      * @private
10709      */
10710     El.cache = {};
10711
10712     var docEl;
10713
10714     /**
10715      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10716      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10717      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10718      * @return {Element} The Element object
10719      * @static
10720      */
10721     El.get = function(el){
10722         var ex, elm, id;
10723         if(!el){ return null; }
10724         if(typeof el == "string"){ // element id
10725             if(!(elm = document.getElementById(el))){
10726                 return null;
10727             }
10728             if(ex = El.cache[el]){
10729                 ex.dom = elm;
10730             }else{
10731                 ex = El.cache[el] = new El(elm);
10732             }
10733             return ex;
10734         }else if(el.tagName){ // dom element
10735             if(!(id = el.id)){
10736                 id = Roo.id(el);
10737             }
10738             if(ex = El.cache[id]){
10739                 ex.dom = el;
10740             }else{
10741                 ex = El.cache[id] = new El(el);
10742             }
10743             return ex;
10744         }else if(el instanceof El){
10745             if(el != docEl){
10746                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10747                                                               // catch case where it hasn't been appended
10748                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10749             }
10750             return el;
10751         }else if(el.isComposite){
10752             return el;
10753         }else if(el instanceof Array){
10754             return El.select(el);
10755         }else if(el == document){
10756             // create a bogus element object representing the document object
10757             if(!docEl){
10758                 var f = function(){};
10759                 f.prototype = El.prototype;
10760                 docEl = new f();
10761                 docEl.dom = document;
10762             }
10763             return docEl;
10764         }
10765         return null;
10766     };
10767
10768     // private
10769     El.uncache = function(el){
10770         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10771             if(a[i]){
10772                 delete El.cache[a[i].id || a[i]];
10773             }
10774         }
10775     };
10776
10777     // private
10778     // Garbage collection - uncache elements/purge listeners on orphaned elements
10779     // so we don't hold a reference and cause the browser to retain them
10780     El.garbageCollect = function(){
10781         if(!Roo.enableGarbageCollector){
10782             clearInterval(El.collectorThread);
10783             return;
10784         }
10785         for(var eid in El.cache){
10786             var el = El.cache[eid], d = el.dom;
10787             // -------------------------------------------------------
10788             // Determining what is garbage:
10789             // -------------------------------------------------------
10790             // !d
10791             // dom node is null, definitely garbage
10792             // -------------------------------------------------------
10793             // !d.parentNode
10794             // no parentNode == direct orphan, definitely garbage
10795             // -------------------------------------------------------
10796             // !d.offsetParent && !document.getElementById(eid)
10797             // display none elements have no offsetParent so we will
10798             // also try to look it up by it's id. However, check
10799             // offsetParent first so we don't do unneeded lookups.
10800             // This enables collection of elements that are not orphans
10801             // directly, but somewhere up the line they have an orphan
10802             // parent.
10803             // -------------------------------------------------------
10804             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10805                 delete El.cache[eid];
10806                 if(d && Roo.enableListenerCollection){
10807                     E.purgeElement(d);
10808                 }
10809             }
10810         }
10811     }
10812     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10813
10814
10815     // dom is optional
10816     El.Flyweight = function(dom){
10817         this.dom = dom;
10818     };
10819     El.Flyweight.prototype = El.prototype;
10820
10821     El._flyweights = {};
10822     /**
10823      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10824      * the dom node can be overwritten by other code.
10825      * @param {String/HTMLElement} el The dom node or id
10826      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10827      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10828      * @static
10829      * @return {Element} The shared Element object
10830      */
10831     El.fly = function(el, named){
10832         named = named || '_global';
10833         el = Roo.getDom(el);
10834         if(!el){
10835             return null;
10836         }
10837         if(!El._flyweights[named]){
10838             El._flyweights[named] = new El.Flyweight();
10839         }
10840         El._flyweights[named].dom = el;
10841         return El._flyweights[named];
10842     };
10843
10844     /**
10845      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10846      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10847      * Shorthand of {@link Roo.Element#get}
10848      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10849      * @return {Element} The Element object
10850      * @member Roo
10851      * @method get
10852      */
10853     Roo.get = El.get;
10854     /**
10855      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10856      * the dom node can be overwritten by other code.
10857      * Shorthand of {@link Roo.Element#fly}
10858      * @param {String/HTMLElement} el The dom node or id
10859      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10860      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10861      * @static
10862      * @return {Element} The shared Element object
10863      * @member Roo
10864      * @method fly
10865      */
10866     Roo.fly = El.fly;
10867
10868     // speedy lookup for elements never to box adjust
10869     var noBoxAdjust = Roo.isStrict ? {
10870         select:1
10871     } : {
10872         input:1, select:1, textarea:1
10873     };
10874     if(Roo.isIE || Roo.isGecko){
10875         noBoxAdjust['button'] = 1;
10876     }
10877
10878
10879     Roo.EventManager.on(window, 'unload', function(){
10880         delete El.cache;
10881         delete El._flyweights;
10882     });
10883 })();
10884
10885
10886
10887
10888 if(Roo.DomQuery){
10889     Roo.Element.selectorFunction = Roo.DomQuery.select;
10890 }
10891
10892 Roo.Element.select = function(selector, unique, root){
10893     var els;
10894     if(typeof selector == "string"){
10895         els = Roo.Element.selectorFunction(selector, root);
10896     }else if(selector.length !== undefined){
10897         els = selector;
10898     }else{
10899         throw "Invalid selector";
10900     }
10901     if(unique === true){
10902         return new Roo.CompositeElement(els);
10903     }else{
10904         return new Roo.CompositeElementLite(els);
10905     }
10906 };
10907 /**
10908  * Selects elements based on the passed CSS selector to enable working on them as 1.
10909  * @param {String/Array} selector The CSS selector or an array of elements
10910  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10911  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10912  * @return {CompositeElementLite/CompositeElement}
10913  * @member Roo
10914  * @method select
10915  */
10916 Roo.select = Roo.Element.select;
10917
10918
10919
10920
10921
10922
10923
10924
10925
10926
10927
10928
10929
10930
10931 /*
10932  * Based on:
10933  * Ext JS Library 1.1.1
10934  * Copyright(c) 2006-2007, Ext JS, LLC.
10935  *
10936  * Originally Released Under LGPL - original licence link has changed is not relivant.
10937  *
10938  * Fork - LGPL
10939  * <script type="text/javascript">
10940  */
10941
10942
10943
10944 //Notifies Element that fx methods are available
10945 Roo.enableFx = true;
10946
10947 /**
10948  * @class Roo.Fx
10949  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10950  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10951  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10952  * Element effects to work.</p><br/>
10953  *
10954  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10955  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10956  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10957  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10958  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10959  * expected results and should be done with care.</p><br/>
10960  *
10961  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10962  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10963 <pre>
10964 Value  Description
10965 -----  -----------------------------
10966 tl     The top left corner
10967 t      The center of the top edge
10968 tr     The top right corner
10969 l      The center of the left edge
10970 r      The center of the right edge
10971 bl     The bottom left corner
10972 b      The center of the bottom edge
10973 br     The bottom right corner
10974 </pre>
10975  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10976  * below are common options that can be passed to any Fx method.</b>
10977  * @cfg {Function} callback A function called when the effect is finished
10978  * @cfg {Object} scope The scope of the effect function
10979  * @cfg {String} easing A valid Easing value for the effect
10980  * @cfg {String} afterCls A css class to apply after the effect
10981  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10982  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10983  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10984  * effects that end with the element being visually hidden, ignored otherwise)
10985  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10986  * a function which returns such a specification that will be applied to the Element after the effect finishes
10987  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10988  * @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
10989  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10990  */
10991 Roo.Fx = {
10992         /**
10993          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10994          * origin for the slide effect.  This function automatically handles wrapping the element with
10995          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10996          * Usage:
10997          *<pre><code>
10998 // default: slide the element in from the top
10999 el.slideIn();
11000
11001 // custom: slide the element in from the right with a 2-second duration
11002 el.slideIn('r', { duration: 2 });
11003
11004 // common config options shown with default values
11005 el.slideIn('t', {
11006     easing: 'easeOut',
11007     duration: .5
11008 });
11009 </code></pre>
11010          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11011          * @param {Object} options (optional) Object literal with any of the Fx config options
11012          * @return {Roo.Element} The Element
11013          */
11014     slideIn : function(anchor, o){
11015         var el = this.getFxEl();
11016         o = o || {};
11017
11018         el.queueFx(o, function(){
11019
11020             anchor = anchor || "t";
11021
11022             // fix display to visibility
11023             this.fixDisplay();
11024
11025             // restore values after effect
11026             var r = this.getFxRestore();
11027             var b = this.getBox();
11028             // fixed size for slide
11029             this.setSize(b);
11030
11031             // wrap if needed
11032             var wrap = this.fxWrap(r.pos, o, "hidden");
11033
11034             var st = this.dom.style;
11035             st.visibility = "visible";
11036             st.position = "absolute";
11037
11038             // clear out temp styles after slide and unwrap
11039             var after = function(){
11040                 el.fxUnwrap(wrap, r.pos, o);
11041                 st.width = r.width;
11042                 st.height = r.height;
11043                 el.afterFx(o);
11044             };
11045             // time to calc the positions
11046             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11047
11048             switch(anchor.toLowerCase()){
11049                 case "t":
11050                     wrap.setSize(b.width, 0);
11051                     st.left = st.bottom = "0";
11052                     a = {height: bh};
11053                 break;
11054                 case "l":
11055                     wrap.setSize(0, b.height);
11056                     st.right = st.top = "0";
11057                     a = {width: bw};
11058                 break;
11059                 case "r":
11060                     wrap.setSize(0, b.height);
11061                     wrap.setX(b.right);
11062                     st.left = st.top = "0";
11063                     a = {width: bw, points: pt};
11064                 break;
11065                 case "b":
11066                     wrap.setSize(b.width, 0);
11067                     wrap.setY(b.bottom);
11068                     st.left = st.top = "0";
11069                     a = {height: bh, points: pt};
11070                 break;
11071                 case "tl":
11072                     wrap.setSize(0, 0);
11073                     st.right = st.bottom = "0";
11074                     a = {width: bw, height: bh};
11075                 break;
11076                 case "bl":
11077                     wrap.setSize(0, 0);
11078                     wrap.setY(b.y+b.height);
11079                     st.right = st.top = "0";
11080                     a = {width: bw, height: bh, points: pt};
11081                 break;
11082                 case "br":
11083                     wrap.setSize(0, 0);
11084                     wrap.setXY([b.right, b.bottom]);
11085                     st.left = st.top = "0";
11086                     a = {width: bw, height: bh, points: pt};
11087                 break;
11088                 case "tr":
11089                     wrap.setSize(0, 0);
11090                     wrap.setX(b.x+b.width);
11091                     st.left = st.bottom = "0";
11092                     a = {width: bw, height: bh, points: pt};
11093                 break;
11094             }
11095             this.dom.style.visibility = "visible";
11096             wrap.show();
11097
11098             arguments.callee.anim = wrap.fxanim(a,
11099                 o,
11100                 'motion',
11101                 .5,
11102                 'easeOut', after);
11103         });
11104         return this;
11105     },
11106     
11107         /**
11108          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11109          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11110          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11111          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11112          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11113          * Usage:
11114          *<pre><code>
11115 // default: slide the element out to the top
11116 el.slideOut();
11117
11118 // custom: slide the element out to the right with a 2-second duration
11119 el.slideOut('r', { duration: 2 });
11120
11121 // common config options shown with default values
11122 el.slideOut('t', {
11123     easing: 'easeOut',
11124     duration: .5,
11125     remove: false,
11126     useDisplay: false
11127 });
11128 </code></pre>
11129          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11130          * @param {Object} options (optional) Object literal with any of the Fx config options
11131          * @return {Roo.Element} The Element
11132          */
11133     slideOut : function(anchor, o){
11134         var el = this.getFxEl();
11135         o = o || {};
11136
11137         el.queueFx(o, function(){
11138
11139             anchor = anchor || "t";
11140
11141             // restore values after effect
11142             var r = this.getFxRestore();
11143             
11144             var b = this.getBox();
11145             // fixed size for slide
11146             this.setSize(b);
11147
11148             // wrap if needed
11149             var wrap = this.fxWrap(r.pos, o, "visible");
11150
11151             var st = this.dom.style;
11152             st.visibility = "visible";
11153             st.position = "absolute";
11154
11155             wrap.setSize(b);
11156
11157             var after = function(){
11158                 if(o.useDisplay){
11159                     el.setDisplayed(false);
11160                 }else{
11161                     el.hide();
11162                 }
11163
11164                 el.fxUnwrap(wrap, r.pos, o);
11165
11166                 st.width = r.width;
11167                 st.height = r.height;
11168
11169                 el.afterFx(o);
11170             };
11171
11172             var a, zero = {to: 0};
11173             switch(anchor.toLowerCase()){
11174                 case "t":
11175                     st.left = st.bottom = "0";
11176                     a = {height: zero};
11177                 break;
11178                 case "l":
11179                     st.right = st.top = "0";
11180                     a = {width: zero};
11181                 break;
11182                 case "r":
11183                     st.left = st.top = "0";
11184                     a = {width: zero, points: {to:[b.right, b.y]}};
11185                 break;
11186                 case "b":
11187                     st.left = st.top = "0";
11188                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11189                 break;
11190                 case "tl":
11191                     st.right = st.bottom = "0";
11192                     a = {width: zero, height: zero};
11193                 break;
11194                 case "bl":
11195                     st.right = st.top = "0";
11196                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11197                 break;
11198                 case "br":
11199                     st.left = st.top = "0";
11200                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11201                 break;
11202                 case "tr":
11203                     st.left = st.bottom = "0";
11204                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11205                 break;
11206             }
11207
11208             arguments.callee.anim = wrap.fxanim(a,
11209                 o,
11210                 'motion',
11211                 .5,
11212                 "easeOut", after);
11213         });
11214         return this;
11215     },
11216
11217         /**
11218          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11219          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11220          * The element must be removed from the DOM using the 'remove' config option if desired.
11221          * Usage:
11222          *<pre><code>
11223 // default
11224 el.puff();
11225
11226 // common config options shown with default values
11227 el.puff({
11228     easing: 'easeOut',
11229     duration: .5,
11230     remove: false,
11231     useDisplay: false
11232 });
11233 </code></pre>
11234          * @param {Object} options (optional) Object literal with any of the Fx config options
11235          * @return {Roo.Element} The Element
11236          */
11237     puff : function(o){
11238         var el = this.getFxEl();
11239         o = o || {};
11240
11241         el.queueFx(o, function(){
11242             this.clearOpacity();
11243             this.show();
11244
11245             // restore values after effect
11246             var r = this.getFxRestore();
11247             var st = this.dom.style;
11248
11249             var after = function(){
11250                 if(o.useDisplay){
11251                     el.setDisplayed(false);
11252                 }else{
11253                     el.hide();
11254                 }
11255
11256                 el.clearOpacity();
11257
11258                 el.setPositioning(r.pos);
11259                 st.width = r.width;
11260                 st.height = r.height;
11261                 st.fontSize = '';
11262                 el.afterFx(o);
11263             };
11264
11265             var width = this.getWidth();
11266             var height = this.getHeight();
11267
11268             arguments.callee.anim = this.fxanim({
11269                     width : {to: this.adjustWidth(width * 2)},
11270                     height : {to: this.adjustHeight(height * 2)},
11271                     points : {by: [-(width * .5), -(height * .5)]},
11272                     opacity : {to: 0},
11273                     fontSize: {to:200, unit: "%"}
11274                 },
11275                 o,
11276                 'motion',
11277                 .5,
11278                 "easeOut", after);
11279         });
11280         return this;
11281     },
11282
11283         /**
11284          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11285          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11286          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11287          * Usage:
11288          *<pre><code>
11289 // default
11290 el.switchOff();
11291
11292 // all config options shown with default values
11293 el.switchOff({
11294     easing: 'easeIn',
11295     duration: .3,
11296     remove: false,
11297     useDisplay: false
11298 });
11299 </code></pre>
11300          * @param {Object} options (optional) Object literal with any of the Fx config options
11301          * @return {Roo.Element} The Element
11302          */
11303     switchOff : function(o){
11304         var el = this.getFxEl();
11305         o = o || {};
11306
11307         el.queueFx(o, function(){
11308             this.clearOpacity();
11309             this.clip();
11310
11311             // restore values after effect
11312             var r = this.getFxRestore();
11313             var st = this.dom.style;
11314
11315             var after = function(){
11316                 if(o.useDisplay){
11317                     el.setDisplayed(false);
11318                 }else{
11319                     el.hide();
11320                 }
11321
11322                 el.clearOpacity();
11323                 el.setPositioning(r.pos);
11324                 st.width = r.width;
11325                 st.height = r.height;
11326
11327                 el.afterFx(o);
11328             };
11329
11330             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11331                 this.clearOpacity();
11332                 (function(){
11333                     this.fxanim({
11334                         height:{to:1},
11335                         points:{by:[0, this.getHeight() * .5]}
11336                     }, o, 'motion', 0.3, 'easeIn', after);
11337                 }).defer(100, this);
11338             });
11339         });
11340         return this;
11341     },
11342
11343     /**
11344      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11345      * changed using the "attr" config option) and then fading back to the original color. If no original
11346      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11347      * Usage:
11348 <pre><code>
11349 // default: highlight background to yellow
11350 el.highlight();
11351
11352 // custom: highlight foreground text to blue for 2 seconds
11353 el.highlight("0000ff", { attr: 'color', duration: 2 });
11354
11355 // common config options shown with default values
11356 el.highlight("ffff9c", {
11357     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11358     endColor: (current color) or "ffffff",
11359     easing: 'easeIn',
11360     duration: 1
11361 });
11362 </code></pre>
11363      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11364      * @param {Object} options (optional) Object literal with any of the Fx config options
11365      * @return {Roo.Element} The Element
11366      */ 
11367     highlight : function(color, o){
11368         var el = this.getFxEl();
11369         o = o || {};
11370
11371         el.queueFx(o, function(){
11372             color = color || "ffff9c";
11373             attr = o.attr || "backgroundColor";
11374
11375             this.clearOpacity();
11376             this.show();
11377
11378             var origColor = this.getColor(attr);
11379             var restoreColor = this.dom.style[attr];
11380             endColor = (o.endColor || origColor) || "ffffff";
11381
11382             var after = function(){
11383                 el.dom.style[attr] = restoreColor;
11384                 el.afterFx(o);
11385             };
11386
11387             var a = {};
11388             a[attr] = {from: color, to: endColor};
11389             arguments.callee.anim = this.fxanim(a,
11390                 o,
11391                 'color',
11392                 1,
11393                 'easeIn', after);
11394         });
11395         return this;
11396     },
11397
11398    /**
11399     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11400     * Usage:
11401 <pre><code>
11402 // default: a single light blue ripple
11403 el.frame();
11404
11405 // custom: 3 red ripples lasting 3 seconds total
11406 el.frame("ff0000", 3, { duration: 3 });
11407
11408 // common config options shown with default values
11409 el.frame("C3DAF9", 1, {
11410     duration: 1 //duration of entire animation (not each individual ripple)
11411     // Note: Easing is not configurable and will be ignored if included
11412 });
11413 </code></pre>
11414     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11415     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11416     * @param {Object} options (optional) Object literal with any of the Fx config options
11417     * @return {Roo.Element} The Element
11418     */
11419     frame : function(color, count, o){
11420         var el = this.getFxEl();
11421         o = o || {};
11422
11423         el.queueFx(o, function(){
11424             color = color || "#C3DAF9";
11425             if(color.length == 6){
11426                 color = "#" + color;
11427             }
11428             count = count || 1;
11429             duration = o.duration || 1;
11430             this.show();
11431
11432             var b = this.getBox();
11433             var animFn = function(){
11434                 var proxy = this.createProxy({
11435
11436                      style:{
11437                         visbility:"hidden",
11438                         position:"absolute",
11439                         "z-index":"35000", // yee haw
11440                         border:"0px solid " + color
11441                      }
11442                   });
11443                 var scale = Roo.isBorderBox ? 2 : 1;
11444                 proxy.animate({
11445                     top:{from:b.y, to:b.y - 20},
11446                     left:{from:b.x, to:b.x - 20},
11447                     borderWidth:{from:0, to:10},
11448                     opacity:{from:1, to:0},
11449                     height:{from:b.height, to:(b.height + (20*scale))},
11450                     width:{from:b.width, to:(b.width + (20*scale))}
11451                 }, duration, function(){
11452                     proxy.remove();
11453                 });
11454                 if(--count > 0){
11455                      animFn.defer((duration/2)*1000, this);
11456                 }else{
11457                     el.afterFx(o);
11458                 }
11459             };
11460             animFn.call(this);
11461         });
11462         return this;
11463     },
11464
11465    /**
11466     * Creates a pause before any subsequent queued effects begin.  If there are
11467     * no effects queued after the pause it will have no effect.
11468     * Usage:
11469 <pre><code>
11470 el.pause(1);
11471 </code></pre>
11472     * @param {Number} seconds The length of time to pause (in seconds)
11473     * @return {Roo.Element} The Element
11474     */
11475     pause : function(seconds){
11476         var el = this.getFxEl();
11477         var o = {};
11478
11479         el.queueFx(o, function(){
11480             setTimeout(function(){
11481                 el.afterFx(o);
11482             }, seconds * 1000);
11483         });
11484         return this;
11485     },
11486
11487    /**
11488     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
11489     * using the "endOpacity" config option.
11490     * Usage:
11491 <pre><code>
11492 // default: fade in from opacity 0 to 100%
11493 el.fadeIn();
11494
11495 // custom: fade in from opacity 0 to 75% over 2 seconds
11496 el.fadeIn({ endOpacity: .75, duration: 2});
11497
11498 // common config options shown with default values
11499 el.fadeIn({
11500     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11501     easing: 'easeOut',
11502     duration: .5
11503 });
11504 </code></pre>
11505     * @param {Object} options (optional) Object literal with any of the Fx config options
11506     * @return {Roo.Element} The Element
11507     */
11508     fadeIn : function(o){
11509         var el = this.getFxEl();
11510         o = o || {};
11511         el.queueFx(o, function(){
11512             this.setOpacity(0);
11513             this.fixDisplay();
11514             this.dom.style.visibility = 'visible';
11515             var to = o.endOpacity || 1;
11516             arguments.callee.anim = this.fxanim({opacity:{to:to}},
11517                 o, null, .5, "easeOut", function(){
11518                 if(to == 1){
11519                     this.clearOpacity();
11520                 }
11521                 el.afterFx(o);
11522             });
11523         });
11524         return this;
11525     },
11526
11527    /**
11528     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
11529     * using the "endOpacity" config option.
11530     * Usage:
11531 <pre><code>
11532 // default: fade out from the element's current opacity to 0
11533 el.fadeOut();
11534
11535 // custom: fade out from the element's current opacity to 25% over 2 seconds
11536 el.fadeOut({ endOpacity: .25, duration: 2});
11537
11538 // common config options shown with default values
11539 el.fadeOut({
11540     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11541     easing: 'easeOut',
11542     duration: .5
11543     remove: false,
11544     useDisplay: false
11545 });
11546 </code></pre>
11547     * @param {Object} options (optional) Object literal with any of the Fx config options
11548     * @return {Roo.Element} The Element
11549     */
11550     fadeOut : function(o){
11551         var el = this.getFxEl();
11552         o = o || {};
11553         el.queueFx(o, function(){
11554             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11555                 o, null, .5, "easeOut", function(){
11556                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11557                      this.dom.style.display = "none";
11558                 }else{
11559                      this.dom.style.visibility = "hidden";
11560                 }
11561                 this.clearOpacity();
11562                 el.afterFx(o);
11563             });
11564         });
11565         return this;
11566     },
11567
11568    /**
11569     * Animates the transition of an element's dimensions from a starting height/width
11570     * to an ending height/width.
11571     * Usage:
11572 <pre><code>
11573 // change height and width to 100x100 pixels
11574 el.scale(100, 100);
11575
11576 // common config options shown with default values.  The height and width will default to
11577 // the element's existing values if passed as null.
11578 el.scale(
11579     [element's width],
11580     [element's height], {
11581     easing: 'easeOut',
11582     duration: .35
11583 });
11584 </code></pre>
11585     * @param {Number} width  The new width (pass undefined to keep the original width)
11586     * @param {Number} height  The new height (pass undefined to keep the original height)
11587     * @param {Object} options (optional) Object literal with any of the Fx config options
11588     * @return {Roo.Element} The Element
11589     */
11590     scale : function(w, h, o){
11591         this.shift(Roo.apply({}, o, {
11592             width: w,
11593             height: h
11594         }));
11595         return this;
11596     },
11597
11598    /**
11599     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11600     * Any of these properties not specified in the config object will not be changed.  This effect 
11601     * requires that at least one new dimension, position or opacity setting must be passed in on
11602     * the config object in order for the function to have any effect.
11603     * Usage:
11604 <pre><code>
11605 // slide the element horizontally to x position 200 while changing the height and opacity
11606 el.shift({ x: 200, height: 50, opacity: .8 });
11607
11608 // common config options shown with default values.
11609 el.shift({
11610     width: [element's width],
11611     height: [element's height],
11612     x: [element's x position],
11613     y: [element's y position],
11614     opacity: [element's opacity],
11615     easing: 'easeOut',
11616     duration: .35
11617 });
11618 </code></pre>
11619     * @param {Object} options  Object literal with any of the Fx config options
11620     * @return {Roo.Element} The Element
11621     */
11622     shift : function(o){
11623         var el = this.getFxEl();
11624         o = o || {};
11625         el.queueFx(o, function(){
11626             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
11627             if(w !== undefined){
11628                 a.width = {to: this.adjustWidth(w)};
11629             }
11630             if(h !== undefined){
11631                 a.height = {to: this.adjustHeight(h)};
11632             }
11633             if(x !== undefined || y !== undefined){
11634                 a.points = {to: [
11635                     x !== undefined ? x : this.getX(),
11636                     y !== undefined ? y : this.getY()
11637                 ]};
11638             }
11639             if(op !== undefined){
11640                 a.opacity = {to: op};
11641             }
11642             if(o.xy !== undefined){
11643                 a.points = {to: o.xy};
11644             }
11645             arguments.callee.anim = this.fxanim(a,
11646                 o, 'motion', .35, "easeOut", function(){
11647                 el.afterFx(o);
11648             });
11649         });
11650         return this;
11651     },
11652
11653         /**
11654          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
11655          * ending point of the effect.
11656          * Usage:
11657          *<pre><code>
11658 // default: slide the element downward while fading out
11659 el.ghost();
11660
11661 // custom: slide the element out to the right with a 2-second duration
11662 el.ghost('r', { duration: 2 });
11663
11664 // common config options shown with default values
11665 el.ghost('b', {
11666     easing: 'easeOut',
11667     duration: .5
11668     remove: false,
11669     useDisplay: false
11670 });
11671 </code></pre>
11672          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11673          * @param {Object} options (optional) Object literal with any of the Fx config options
11674          * @return {Roo.Element} The Element
11675          */
11676     ghost : function(anchor, o){
11677         var el = this.getFxEl();
11678         o = o || {};
11679
11680         el.queueFx(o, function(){
11681             anchor = anchor || "b";
11682
11683             // restore values after effect
11684             var r = this.getFxRestore();
11685             var w = this.getWidth(),
11686                 h = this.getHeight();
11687
11688             var st = this.dom.style;
11689
11690             var after = function(){
11691                 if(o.useDisplay){
11692                     el.setDisplayed(false);
11693                 }else{
11694                     el.hide();
11695                 }
11696
11697                 el.clearOpacity();
11698                 el.setPositioning(r.pos);
11699                 st.width = r.width;
11700                 st.height = r.height;
11701
11702                 el.afterFx(o);
11703             };
11704
11705             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11706             switch(anchor.toLowerCase()){
11707                 case "t":
11708                     pt.by = [0, -h];
11709                 break;
11710                 case "l":
11711                     pt.by = [-w, 0];
11712                 break;
11713                 case "r":
11714                     pt.by = [w, 0];
11715                 break;
11716                 case "b":
11717                     pt.by = [0, h];
11718                 break;
11719                 case "tl":
11720                     pt.by = [-w, -h];
11721                 break;
11722                 case "bl":
11723                     pt.by = [-w, h];
11724                 break;
11725                 case "br":
11726                     pt.by = [w, h];
11727                 break;
11728                 case "tr":
11729                     pt.by = [w, -h];
11730                 break;
11731             }
11732
11733             arguments.callee.anim = this.fxanim(a,
11734                 o,
11735                 'motion',
11736                 .5,
11737                 "easeOut", after);
11738         });
11739         return this;
11740     },
11741
11742         /**
11743          * Ensures that all effects queued after syncFx is called on the element are
11744          * run concurrently.  This is the opposite of {@link #sequenceFx}.
11745          * @return {Roo.Element} The Element
11746          */
11747     syncFx : function(){
11748         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11749             block : false,
11750             concurrent : true,
11751             stopFx : false
11752         });
11753         return this;
11754     },
11755
11756         /**
11757          * Ensures that all effects queued after sequenceFx is called on the element are
11758          * run in sequence.  This is the opposite of {@link #syncFx}.
11759          * @return {Roo.Element} The Element
11760          */
11761     sequenceFx : function(){
11762         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11763             block : false,
11764             concurrent : false,
11765             stopFx : false
11766         });
11767         return this;
11768     },
11769
11770         /* @private */
11771     nextFx : function(){
11772         var ef = this.fxQueue[0];
11773         if(ef){
11774             ef.call(this);
11775         }
11776     },
11777
11778         /**
11779          * Returns true if the element has any effects actively running or queued, else returns false.
11780          * @return {Boolean} True if element has active effects, else false
11781          */
11782     hasActiveFx : function(){
11783         return this.fxQueue && this.fxQueue[0];
11784     },
11785
11786         /**
11787          * Stops any running effects and clears the element's internal effects queue if it contains
11788          * any additional effects that haven't started yet.
11789          * @return {Roo.Element} The Element
11790          */
11791     stopFx : function(){
11792         if(this.hasActiveFx()){
11793             var cur = this.fxQueue[0];
11794             if(cur && cur.anim && cur.anim.isAnimated()){
11795                 this.fxQueue = [cur]; // clear out others
11796                 cur.anim.stop(true);
11797             }
11798         }
11799         return this;
11800     },
11801
11802         /* @private */
11803     beforeFx : function(o){
11804         if(this.hasActiveFx() && !o.concurrent){
11805            if(o.stopFx){
11806                this.stopFx();
11807                return true;
11808            }
11809            return false;
11810         }
11811         return true;
11812     },
11813
11814         /**
11815          * Returns true if the element is currently blocking so that no other effect can be queued
11816          * until this effect is finished, else returns false if blocking is not set.  This is commonly
11817          * used to ensure that an effect initiated by a user action runs to completion prior to the
11818          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11819          * @return {Boolean} True if blocking, else false
11820          */
11821     hasFxBlock : function(){
11822         var q = this.fxQueue;
11823         return q && q[0] && q[0].block;
11824     },
11825
11826         /* @private */
11827     queueFx : function(o, fn){
11828         if(!this.fxQueue){
11829             this.fxQueue = [];
11830         }
11831         if(!this.hasFxBlock()){
11832             Roo.applyIf(o, this.fxDefaults);
11833             if(!o.concurrent){
11834                 var run = this.beforeFx(o);
11835                 fn.block = o.block;
11836                 this.fxQueue.push(fn);
11837                 if(run){
11838                     this.nextFx();
11839                 }
11840             }else{
11841                 fn.call(this);
11842             }
11843         }
11844         return this;
11845     },
11846
11847         /* @private */
11848     fxWrap : function(pos, o, vis){
11849         var wrap;
11850         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11851             var wrapXY;
11852             if(o.fixPosition){
11853                 wrapXY = this.getXY();
11854             }
11855             var div = document.createElement("div");
11856             div.style.visibility = vis;
11857             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11858             wrap.setPositioning(pos);
11859             if(wrap.getStyle("position") == "static"){
11860                 wrap.position("relative");
11861             }
11862             this.clearPositioning('auto');
11863             wrap.clip();
11864             wrap.dom.appendChild(this.dom);
11865             if(wrapXY){
11866                 wrap.setXY(wrapXY);
11867             }
11868         }
11869         return wrap;
11870     },
11871
11872         /* @private */
11873     fxUnwrap : function(wrap, pos, o){
11874         this.clearPositioning();
11875         this.setPositioning(pos);
11876         if(!o.wrap){
11877             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11878             wrap.remove();
11879         }
11880     },
11881
11882         /* @private */
11883     getFxRestore : function(){
11884         var st = this.dom.style;
11885         return {pos: this.getPositioning(), width: st.width, height : st.height};
11886     },
11887
11888         /* @private */
11889     afterFx : function(o){
11890         if(o.afterStyle){
11891             this.applyStyles(o.afterStyle);
11892         }
11893         if(o.afterCls){
11894             this.addClass(o.afterCls);
11895         }
11896         if(o.remove === true){
11897             this.remove();
11898         }
11899         Roo.callback(o.callback, o.scope, [this]);
11900         if(!o.concurrent){
11901             this.fxQueue.shift();
11902             this.nextFx();
11903         }
11904     },
11905
11906         /* @private */
11907     getFxEl : function(){ // support for composite element fx
11908         return Roo.get(this.dom);
11909     },
11910
11911         /* @private */
11912     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11913         animType = animType || 'run';
11914         opt = opt || {};
11915         var anim = Roo.lib.Anim[animType](
11916             this.dom, args,
11917             (opt.duration || defaultDur) || .35,
11918             (opt.easing || defaultEase) || 'easeOut',
11919             function(){
11920                 Roo.callback(cb, this);
11921             },
11922             this
11923         );
11924         opt.anim = anim;
11925         return anim;
11926     }
11927 };
11928
11929 // backwords compat
11930 Roo.Fx.resize = Roo.Fx.scale;
11931
11932 //When included, Roo.Fx is automatically applied to Element so that all basic
11933 //effects are available directly via the Element API
11934 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11935  * Based on:
11936  * Ext JS Library 1.1.1
11937  * Copyright(c) 2006-2007, Ext JS, LLC.
11938  *
11939  * Originally Released Under LGPL - original licence link has changed is not relivant.
11940  *
11941  * Fork - LGPL
11942  * <script type="text/javascript">
11943  */
11944
11945
11946 /**
11947  * @class Roo.CompositeElement
11948  * Standard composite class. Creates a Roo.Element for every element in the collection.
11949  * <br><br>
11950  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11951  * actions will be performed on all the elements in this collection.</b>
11952  * <br><br>
11953  * All methods return <i>this</i> and can be chained.
11954  <pre><code>
11955  var els = Roo.select("#some-el div.some-class", true);
11956  // or select directly from an existing element
11957  var el = Roo.get('some-el');
11958  el.select('div.some-class', true);
11959
11960  els.setWidth(100); // all elements become 100 width
11961  els.hide(true); // all elements fade out and hide
11962  // or
11963  els.setWidth(100).hide(true);
11964  </code></pre>
11965  */
11966 Roo.CompositeElement = function(els){
11967     this.elements = [];
11968     this.addElements(els);
11969 };
11970 Roo.CompositeElement.prototype = {
11971     isComposite: true,
11972     addElements : function(els){
11973         if(!els) {
11974             return this;
11975         }
11976         if(typeof els == "string"){
11977             els = Roo.Element.selectorFunction(els);
11978         }
11979         var yels = this.elements;
11980         var index = yels.length-1;
11981         for(var i = 0, len = els.length; i < len; i++) {
11982                 yels[++index] = Roo.get(els[i]);
11983         }
11984         return this;
11985     },
11986
11987     /**
11988     * Clears this composite and adds the elements returned by the passed selector.
11989     * @param {String/Array} els A string CSS selector, an array of elements or an element
11990     * @return {CompositeElement} this
11991     */
11992     fill : function(els){
11993         this.elements = [];
11994         this.add(els);
11995         return this;
11996     },
11997
11998     /**
11999     * Filters this composite to only elements that match the passed selector.
12000     * @param {String} selector A string CSS selector
12001     * @param {Boolean} inverse return inverse filter (not matches)
12002     * @return {CompositeElement} this
12003     */
12004     filter : function(selector, inverse){
12005         var els = [];
12006         inverse = inverse || false;
12007         this.each(function(el){
12008             var match = inverse ? !el.is(selector) : el.is(selector);
12009             if(match){
12010                 els[els.length] = el.dom;
12011             }
12012         });
12013         this.fill(els);
12014         return this;
12015     },
12016
12017     invoke : function(fn, args){
12018         var els = this.elements;
12019         for(var i = 0, len = els.length; i < len; i++) {
12020                 Roo.Element.prototype[fn].apply(els[i], args);
12021         }
12022         return this;
12023     },
12024     /**
12025     * Adds elements to this composite.
12026     * @param {String/Array} els A string CSS selector, an array of elements or an element
12027     * @return {CompositeElement} this
12028     */
12029     add : function(els){
12030         if(typeof els == "string"){
12031             this.addElements(Roo.Element.selectorFunction(els));
12032         }else if(els.length !== undefined){
12033             this.addElements(els);
12034         }else{
12035             this.addElements([els]);
12036         }
12037         return this;
12038     },
12039     /**
12040     * Calls the passed function passing (el, this, index) for each element in this composite.
12041     * @param {Function} fn The function to call
12042     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12043     * @return {CompositeElement} this
12044     */
12045     each : function(fn, scope){
12046         var els = this.elements;
12047         for(var i = 0, len = els.length; i < len; i++){
12048             if(fn.call(scope || els[i], els[i], this, i) === false) {
12049                 break;
12050             }
12051         }
12052         return this;
12053     },
12054
12055     /**
12056      * Returns the Element object at the specified index
12057      * @param {Number} index
12058      * @return {Roo.Element}
12059      */
12060     item : function(index){
12061         return this.elements[index] || null;
12062     },
12063
12064     /**
12065      * Returns the first Element
12066      * @return {Roo.Element}
12067      */
12068     first : function(){
12069         return this.item(0);
12070     },
12071
12072     /**
12073      * Returns the last Element
12074      * @return {Roo.Element}
12075      */
12076     last : function(){
12077         return this.item(this.elements.length-1);
12078     },
12079
12080     /**
12081      * Returns the number of elements in this composite
12082      * @return Number
12083      */
12084     getCount : function(){
12085         return this.elements.length;
12086     },
12087
12088     /**
12089      * Returns true if this composite contains the passed element
12090      * @return Boolean
12091      */
12092     contains : function(el){
12093         return this.indexOf(el) !== -1;
12094     },
12095
12096     /**
12097      * Returns true if this composite contains the passed element
12098      * @return Boolean
12099      */
12100     indexOf : function(el){
12101         return this.elements.indexOf(Roo.get(el));
12102     },
12103
12104
12105     /**
12106     * Removes the specified element(s).
12107     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12108     * or an array of any of those.
12109     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12110     * @return {CompositeElement} this
12111     */
12112     removeElement : function(el, removeDom){
12113         if(el instanceof Array){
12114             for(var i = 0, len = el.length; i < len; i++){
12115                 this.removeElement(el[i]);
12116             }
12117             return this;
12118         }
12119         var index = typeof el == 'number' ? el : this.indexOf(el);
12120         if(index !== -1){
12121             if(removeDom){
12122                 var d = this.elements[index];
12123                 if(d.dom){
12124                     d.remove();
12125                 }else{
12126                     d.parentNode.removeChild(d);
12127                 }
12128             }
12129             this.elements.splice(index, 1);
12130         }
12131         return this;
12132     },
12133
12134     /**
12135     * Replaces the specified element with the passed element.
12136     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12137     * to replace.
12138     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12139     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12140     * @return {CompositeElement} this
12141     */
12142     replaceElement : function(el, replacement, domReplace){
12143         var index = typeof el == 'number' ? el : this.indexOf(el);
12144         if(index !== -1){
12145             if(domReplace){
12146                 this.elements[index].replaceWith(replacement);
12147             }else{
12148                 this.elements.splice(index, 1, Roo.get(replacement))
12149             }
12150         }
12151         return this;
12152     },
12153
12154     /**
12155      * Removes all elements.
12156      */
12157     clear : function(){
12158         this.elements = [];
12159     }
12160 };
12161 (function(){
12162     Roo.CompositeElement.createCall = function(proto, fnName){
12163         if(!proto[fnName]){
12164             proto[fnName] = function(){
12165                 return this.invoke(fnName, arguments);
12166             };
12167         }
12168     };
12169     for(var fnName in Roo.Element.prototype){
12170         if(typeof Roo.Element.prototype[fnName] == "function"){
12171             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12172         }
12173     };
12174 })();
12175 /*
12176  * Based on:
12177  * Ext JS Library 1.1.1
12178  * Copyright(c) 2006-2007, Ext JS, LLC.
12179  *
12180  * Originally Released Under LGPL - original licence link has changed is not relivant.
12181  *
12182  * Fork - LGPL
12183  * <script type="text/javascript">
12184  */
12185
12186 /**
12187  * @class Roo.CompositeElementLite
12188  * @extends Roo.CompositeElement
12189  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12190  <pre><code>
12191  var els = Roo.select("#some-el div.some-class");
12192  // or select directly from an existing element
12193  var el = Roo.get('some-el');
12194  el.select('div.some-class');
12195
12196  els.setWidth(100); // all elements become 100 width
12197  els.hide(true); // all elements fade out and hide
12198  // or
12199  els.setWidth(100).hide(true);
12200  </code></pre><br><br>
12201  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12202  * actions will be performed on all the elements in this collection.</b>
12203  */
12204 Roo.CompositeElementLite = function(els){
12205     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12206     this.el = new Roo.Element.Flyweight();
12207 };
12208 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12209     addElements : function(els){
12210         if(els){
12211             if(els instanceof Array){
12212                 this.elements = this.elements.concat(els);
12213             }else{
12214                 var yels = this.elements;
12215                 var index = yels.length-1;
12216                 for(var i = 0, len = els.length; i < len; i++) {
12217                     yels[++index] = els[i];
12218                 }
12219             }
12220         }
12221         return this;
12222     },
12223     invoke : function(fn, args){
12224         var els = this.elements;
12225         var el = this.el;
12226         for(var i = 0, len = els.length; i < len; i++) {
12227             el.dom = els[i];
12228                 Roo.Element.prototype[fn].apply(el, args);
12229         }
12230         return this;
12231     },
12232     /**
12233      * Returns a flyweight Element of the dom element object at the specified index
12234      * @param {Number} index
12235      * @return {Roo.Element}
12236      */
12237     item : function(index){
12238         if(!this.elements[index]){
12239             return null;
12240         }
12241         this.el.dom = this.elements[index];
12242         return this.el;
12243     },
12244
12245     // fixes scope with flyweight
12246     addListener : function(eventName, handler, scope, opt){
12247         var els = this.elements;
12248         for(var i = 0, len = els.length; i < len; i++) {
12249             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12250         }
12251         return this;
12252     },
12253
12254     /**
12255     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12256     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12257     * a reference to the dom node, use el.dom.</b>
12258     * @param {Function} fn The function to call
12259     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12260     * @return {CompositeElement} this
12261     */
12262     each : function(fn, scope){
12263         var els = this.elements;
12264         var el = this.el;
12265         for(var i = 0, len = els.length; i < len; i++){
12266             el.dom = els[i];
12267                 if(fn.call(scope || el, el, this, i) === false){
12268                 break;
12269             }
12270         }
12271         return this;
12272     },
12273
12274     indexOf : function(el){
12275         return this.elements.indexOf(Roo.getDom(el));
12276     },
12277
12278     replaceElement : function(el, replacement, domReplace){
12279         var index = typeof el == 'number' ? el : this.indexOf(el);
12280         if(index !== -1){
12281             replacement = Roo.getDom(replacement);
12282             if(domReplace){
12283                 var d = this.elements[index];
12284                 d.parentNode.insertBefore(replacement, d);
12285                 d.parentNode.removeChild(d);
12286             }
12287             this.elements.splice(index, 1, replacement);
12288         }
12289         return this;
12290     }
12291 });
12292 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12293
12294 /*
12295  * Based on:
12296  * Ext JS Library 1.1.1
12297  * Copyright(c) 2006-2007, Ext JS, LLC.
12298  *
12299  * Originally Released Under LGPL - original licence link has changed is not relivant.
12300  *
12301  * Fork - LGPL
12302  * <script type="text/javascript">
12303  */
12304
12305  
12306
12307 /**
12308  * @class Roo.data.Connection
12309  * @extends Roo.util.Observable
12310  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12311  * either to a configured URL, or to a URL specified at request time. 
12312  * 
12313  * Requests made by this class are asynchronous, and will return immediately. No data from
12314  * the server will be available to the statement immediately following the {@link #request} call.
12315  * To process returned data, use a callback in the request options object, or an event listener.
12316  * 
12317  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12318  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12319  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12320  * property and, if present, the IFRAME's XML document as the responseXML property.
12321  * 
12322  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12323  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12324  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12325  * standard DOM methods.
12326  * @constructor
12327  * @param {Object} config a configuration object.
12328  */
12329 Roo.data.Connection = function(config){
12330     Roo.apply(this, config);
12331     this.addEvents({
12332         /**
12333          * @event beforerequest
12334          * Fires before a network request is made to retrieve a data object.
12335          * @param {Connection} conn This Connection object.
12336          * @param {Object} options The options config object passed to the {@link #request} method.
12337          */
12338         "beforerequest" : true,
12339         /**
12340          * @event requestcomplete
12341          * Fires if the request was successfully completed.
12342          * @param {Connection} conn This Connection object.
12343          * @param {Object} response The XHR object containing the response data.
12344          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12345          * @param {Object} options The options config object passed to the {@link #request} method.
12346          */
12347         "requestcomplete" : true,
12348         /**
12349          * @event requestexception
12350          * Fires if an error HTTP status was returned from the server.
12351          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12352          * @param {Connection} conn This Connection object.
12353          * @param {Object} response The XHR object containing the response data.
12354          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12355          * @param {Object} options The options config object passed to the {@link #request} method.
12356          */
12357         "requestexception" : true
12358     });
12359     Roo.data.Connection.superclass.constructor.call(this);
12360 };
12361
12362 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12363     /**
12364      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12365      */
12366     /**
12367      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12368      * extra parameters to each request made by this object. (defaults to undefined)
12369      */
12370     /**
12371      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12372      *  to each request made by this object. (defaults to undefined)
12373      */
12374     /**
12375      * @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)
12376      */
12377     /**
12378      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12379      */
12380     timeout : 30000,
12381     /**
12382      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12383      * @type Boolean
12384      */
12385     autoAbort:false,
12386
12387     /**
12388      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12389      * @type Boolean
12390      */
12391     disableCaching: true,
12392
12393     /**
12394      * Sends an HTTP request to a remote server.
12395      * @param {Object} options An object which may contain the following properties:<ul>
12396      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12397      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12398      * request, a url encoded string or a function to call to get either.</li>
12399      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12400      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12401      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12402      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12403      * <li>options {Object} The parameter to the request call.</li>
12404      * <li>success {Boolean} True if the request succeeded.</li>
12405      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12406      * </ul></li>
12407      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12408      * The callback is passed the following parameters:<ul>
12409      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12410      * <li>options {Object} The parameter to the request call.</li>
12411      * </ul></li>
12412      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12413      * The callback is passed the following parameters:<ul>
12414      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12415      * <li>options {Object} The parameter to the request call.</li>
12416      * </ul></li>
12417      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12418      * for the callback function. Defaults to the browser window.</li>
12419      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12420      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12421      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12422      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12423      * params for the post data. Any params will be appended to the URL.</li>
12424      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12425      * </ul>
12426      * @return {Number} transactionId
12427      */
12428     request : function(o){
12429         if(this.fireEvent("beforerequest", this, o) !== false){
12430             var p = o.params;
12431
12432             if(typeof p == "function"){
12433                 p = p.call(o.scope||window, o);
12434             }
12435             if(typeof p == "object"){
12436                 p = Roo.urlEncode(o.params);
12437             }
12438             if(this.extraParams){
12439                 var extras = Roo.urlEncode(this.extraParams);
12440                 p = p ? (p + '&' + extras) : extras;
12441             }
12442
12443             var url = o.url || this.url;
12444             if(typeof url == 'function'){
12445                 url = url.call(o.scope||window, o);
12446             }
12447
12448             if(o.form){
12449                 var form = Roo.getDom(o.form);
12450                 url = url || form.action;
12451
12452                 var enctype = form.getAttribute("enctype");
12453                 
12454                 if (o.formData) {
12455                     return this.doFormDataUpload(o, url);
12456                 }
12457                 
12458                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12459                     return this.doFormUpload(o, p, url);
12460                 }
12461                 var f = Roo.lib.Ajax.serializeForm(form);
12462                 p = p ? (p + '&' + f) : f;
12463             }
12464             
12465             if (!o.form && o.formData) {
12466                 o.formData = o.formData === true ? new FormData() : o.formData;
12467                 for (var k in o.params) {
12468                     o.formData.append(k,o.params[k]);
12469                 }
12470                     
12471                 return this.doFormDataUpload(o, url);
12472             }
12473             
12474
12475             var hs = o.headers;
12476             if(this.defaultHeaders){
12477                 hs = Roo.apply(hs || {}, this.defaultHeaders);
12478                 if(!o.headers){
12479                     o.headers = hs;
12480                 }
12481             }
12482
12483             var cb = {
12484                 success: this.handleResponse,
12485                 failure: this.handleFailure,
12486                 scope: this,
12487                 argument: {options: o},
12488                 timeout : o.timeout || this.timeout
12489             };
12490
12491             var method = o.method||this.method||(p ? "POST" : "GET");
12492
12493             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12494                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12495             }
12496
12497             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12498                 if(o.autoAbort){
12499                     this.abort();
12500                 }
12501             }else if(this.autoAbort !== false){
12502                 this.abort();
12503             }
12504
12505             if((method == 'GET' && p) || o.xmlData){
12506                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12507                 p = '';
12508             }
12509             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12510             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12511             Roo.lib.Ajax.useDefaultHeader == true;
12512             return this.transId;
12513         }else{
12514             Roo.callback(o.callback, o.scope, [o, null, null]);
12515             return null;
12516         }
12517     },
12518
12519     /**
12520      * Determine whether this object has a request outstanding.
12521      * @param {Number} transactionId (Optional) defaults to the last transaction
12522      * @return {Boolean} True if there is an outstanding request.
12523      */
12524     isLoading : function(transId){
12525         if(transId){
12526             return Roo.lib.Ajax.isCallInProgress(transId);
12527         }else{
12528             return this.transId ? true : false;
12529         }
12530     },
12531
12532     /**
12533      * Aborts any outstanding request.
12534      * @param {Number} transactionId (Optional) defaults to the last transaction
12535      */
12536     abort : function(transId){
12537         if(transId || this.isLoading()){
12538             Roo.lib.Ajax.abort(transId || this.transId);
12539         }
12540     },
12541
12542     // private
12543     handleResponse : function(response){
12544         this.transId = false;
12545         var options = response.argument.options;
12546         response.argument = options ? options.argument : null;
12547         this.fireEvent("requestcomplete", this, response, options);
12548         Roo.callback(options.success, options.scope, [response, options]);
12549         Roo.callback(options.callback, options.scope, [options, true, response]);
12550     },
12551
12552     // private
12553     handleFailure : function(response, e){
12554         this.transId = false;
12555         var options = response.argument.options;
12556         response.argument = options ? options.argument : null;
12557         this.fireEvent("requestexception", this, response, options, e);
12558         Roo.callback(options.failure, options.scope, [response, options]);
12559         Roo.callback(options.callback, options.scope, [options, false, response]);
12560     },
12561
12562     // private
12563     doFormUpload : function(o, ps, url){
12564         var id = Roo.id();
12565         var frame = document.createElement('iframe');
12566         frame.id = id;
12567         frame.name = id;
12568         frame.className = 'x-hidden';
12569         if(Roo.isIE){
12570             frame.src = Roo.SSL_SECURE_URL;
12571         }
12572         document.body.appendChild(frame);
12573
12574         if(Roo.isIE){
12575            document.frames[id].name = id;
12576         }
12577
12578         var form = Roo.getDom(o.form);
12579         form.target = id;
12580         form.method = 'POST';
12581         form.enctype = form.encoding = 'multipart/form-data';
12582         if(url){
12583             form.action = url;
12584         }
12585
12586         var hiddens, hd;
12587         if(ps){ // add dynamic params
12588             hiddens = [];
12589             ps = Roo.urlDecode(ps, false);
12590             for(var k in ps){
12591                 if(ps.hasOwnProperty(k)){
12592                     hd = document.createElement('input');
12593                     hd.type = 'hidden';
12594                     hd.name = k;
12595                     hd.value = ps[k];
12596                     form.appendChild(hd);
12597                     hiddens.push(hd);
12598                 }
12599             }
12600         }
12601
12602         function cb(){
12603             var r = {  // bogus response object
12604                 responseText : '',
12605                 responseXML : null
12606             };
12607
12608             r.argument = o ? o.argument : null;
12609
12610             try { //
12611                 var doc;
12612                 if(Roo.isIE){
12613                     doc = frame.contentWindow.document;
12614                 }else {
12615                     doc = (frame.contentDocument || window.frames[id].document);
12616                 }
12617                 if(doc && doc.body){
12618                     r.responseText = doc.body.innerHTML;
12619                 }
12620                 if(doc && doc.XMLDocument){
12621                     r.responseXML = doc.XMLDocument;
12622                 }else {
12623                     r.responseXML = doc;
12624                 }
12625             }
12626             catch(e) {
12627                 // ignore
12628             }
12629
12630             Roo.EventManager.removeListener(frame, 'load', cb, this);
12631
12632             this.fireEvent("requestcomplete", this, r, o);
12633             Roo.callback(o.success, o.scope, [r, o]);
12634             Roo.callback(o.callback, o.scope, [o, true, r]);
12635
12636             setTimeout(function(){document.body.removeChild(frame);}, 100);
12637         }
12638
12639         Roo.EventManager.on(frame, 'load', cb, this);
12640         form.submit();
12641
12642         if(hiddens){ // remove dynamic params
12643             for(var i = 0, len = hiddens.length; i < len; i++){
12644                 form.removeChild(hiddens[i]);
12645             }
12646         }
12647     },
12648     // this is a 'formdata version???'
12649     
12650     
12651     doFormDataUpload : function(o,  url)
12652     {
12653         var formData;
12654         if (o.form) {
12655             var form =  Roo.getDom(o.form);
12656             form.enctype = form.encoding = 'multipart/form-data';
12657             formData = o.formData === true ? new FormData(form) : o.formData;
12658         } else {
12659             formData = o.formData === true ? new FormData() : o.formData;
12660         }
12661         
12662       
12663         var cb = {
12664             success: this.handleResponse,
12665             failure: this.handleFailure,
12666             scope: this,
12667             argument: {options: o},
12668             timeout : o.timeout || this.timeout
12669         };
12670  
12671         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12672             if(o.autoAbort){
12673                 this.abort();
12674             }
12675         }else if(this.autoAbort !== false){
12676             this.abort();
12677         }
12678
12679         //Roo.lib.Ajax.defaultPostHeader = null;
12680         Roo.lib.Ajax.useDefaultHeader = false;
12681         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
12682         Roo.lib.Ajax.useDefaultHeader = true;
12683  
12684          
12685     }
12686     
12687 });
12688 /*
12689  * Based on:
12690  * Ext JS Library 1.1.1
12691  * Copyright(c) 2006-2007, Ext JS, LLC.
12692  *
12693  * Originally Released Under LGPL - original licence link has changed is not relivant.
12694  *
12695  * Fork - LGPL
12696  * <script type="text/javascript">
12697  */
12698  
12699 /**
12700  * Global Ajax request class.
12701  * 
12702  * @class Roo.Ajax
12703  * @extends Roo.data.Connection
12704  * @static
12705  * 
12706  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
12707  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12708  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
12709  * @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)
12710  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12711  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12712  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
12713  */
12714 Roo.Ajax = new Roo.data.Connection({
12715     // fix up the docs
12716     /**
12717      * @scope Roo.Ajax
12718      * @type {Boolear} 
12719      */
12720     autoAbort : false,
12721
12722     /**
12723      * Serialize the passed form into a url encoded string
12724      * @scope Roo.Ajax
12725      * @param {String/HTMLElement} form
12726      * @return {String}
12727      */
12728     serializeForm : function(form){
12729         return Roo.lib.Ajax.serializeForm(form);
12730     }
12731 });/*
12732  * Based on:
12733  * Ext JS Library 1.1.1
12734  * Copyright(c) 2006-2007, Ext JS, LLC.
12735  *
12736  * Originally Released Under LGPL - original licence link has changed is not relivant.
12737  *
12738  * Fork - LGPL
12739  * <script type="text/javascript">
12740  */
12741
12742  
12743 /**
12744  * @class Roo.UpdateManager
12745  * @extends Roo.util.Observable
12746  * Provides AJAX-style update for Element object.<br><br>
12747  * Usage:<br>
12748  * <pre><code>
12749  * // Get it from a Roo.Element object
12750  * var el = Roo.get("foo");
12751  * var mgr = el.getUpdateManager();
12752  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
12753  * ...
12754  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12755  * <br>
12756  * // or directly (returns the same UpdateManager instance)
12757  * var mgr = new Roo.UpdateManager("myElementId");
12758  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12759  * mgr.on("update", myFcnNeedsToKnow);
12760  * <br>
12761    // short handed call directly from the element object
12762    Roo.get("foo").load({
12763         url: "bar.php",
12764         scripts:true,
12765         params: "for=bar",
12766         text: "Loading Foo..."
12767    });
12768  * </code></pre>
12769  * @constructor
12770  * Create new UpdateManager directly.
12771  * @param {String/HTMLElement/Roo.Element} el The element to update
12772  * @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).
12773  */
12774 Roo.UpdateManager = function(el, forceNew){
12775     el = Roo.get(el);
12776     if(!forceNew && el.updateManager){
12777         return el.updateManager;
12778     }
12779     /**
12780      * The Element object
12781      * @type Roo.Element
12782      */
12783     this.el = el;
12784     /**
12785      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12786      * @type String
12787      */
12788     this.defaultUrl = null;
12789
12790     this.addEvents({
12791         /**
12792          * @event beforeupdate
12793          * Fired before an update is made, return false from your handler and the update is cancelled.
12794          * @param {Roo.Element} el
12795          * @param {String/Object/Function} url
12796          * @param {String/Object} params
12797          */
12798         "beforeupdate": true,
12799         /**
12800          * @event update
12801          * Fired after successful update is made.
12802          * @param {Roo.Element} el
12803          * @param {Object} oResponseObject The response Object
12804          */
12805         "update": true,
12806         /**
12807          * @event failure
12808          * Fired on update failure.
12809          * @param {Roo.Element} el
12810          * @param {Object} oResponseObject The response Object
12811          */
12812         "failure": true
12813     });
12814     var d = Roo.UpdateManager.defaults;
12815     /**
12816      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12817      * @type String
12818      */
12819     this.sslBlankUrl = d.sslBlankUrl;
12820     /**
12821      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12822      * @type Boolean
12823      */
12824     this.disableCaching = d.disableCaching;
12825     /**
12826      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12827      * @type String
12828      */
12829     this.indicatorText = d.indicatorText;
12830     /**
12831      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12832      * @type String
12833      */
12834     this.showLoadIndicator = d.showLoadIndicator;
12835     /**
12836      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12837      * @type Number
12838      */
12839     this.timeout = d.timeout;
12840
12841     /**
12842      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12843      * @type Boolean
12844      */
12845     this.loadScripts = d.loadScripts;
12846
12847     /**
12848      * Transaction object of current executing transaction
12849      */
12850     this.transaction = null;
12851
12852     /**
12853      * @private
12854      */
12855     this.autoRefreshProcId = null;
12856     /**
12857      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12858      * @type Function
12859      */
12860     this.refreshDelegate = this.refresh.createDelegate(this);
12861     /**
12862      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12863      * @type Function
12864      */
12865     this.updateDelegate = this.update.createDelegate(this);
12866     /**
12867      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12868      * @type Function
12869      */
12870     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12871     /**
12872      * @private
12873      */
12874     this.successDelegate = this.processSuccess.createDelegate(this);
12875     /**
12876      * @private
12877      */
12878     this.failureDelegate = this.processFailure.createDelegate(this);
12879
12880     if(!this.renderer){
12881      /**
12882       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12883       */
12884     this.renderer = new Roo.UpdateManager.BasicRenderer();
12885     }
12886     
12887     Roo.UpdateManager.superclass.constructor.call(this);
12888 };
12889
12890 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12891     /**
12892      * Get the Element this UpdateManager is bound to
12893      * @return {Roo.Element} The element
12894      */
12895     getEl : function(){
12896         return this.el;
12897     },
12898     /**
12899      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12900      * @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:
12901 <pre><code>
12902 um.update({<br/>
12903     url: "your-url.php",<br/>
12904     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12905     callback: yourFunction,<br/>
12906     scope: yourObject, //(optional scope)  <br/>
12907     discardUrl: false, <br/>
12908     nocache: false,<br/>
12909     text: "Loading...",<br/>
12910     timeout: 30,<br/>
12911     scripts: false<br/>
12912 });
12913 </code></pre>
12914      * The only required property is url. The optional properties nocache, text and scripts
12915      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12916      * @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}
12917      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12918      * @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.
12919      */
12920     update : function(url, params, callback, discardUrl){
12921         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12922             var method = this.method,
12923                 cfg;
12924             if(typeof url == "object"){ // must be config object
12925                 cfg = url;
12926                 url = cfg.url;
12927                 params = params || cfg.params;
12928                 callback = callback || cfg.callback;
12929                 discardUrl = discardUrl || cfg.discardUrl;
12930                 if(callback && cfg.scope){
12931                     callback = callback.createDelegate(cfg.scope);
12932                 }
12933                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12934                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12935                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12936                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12937                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12938             }
12939             this.showLoading();
12940             if(!discardUrl){
12941                 this.defaultUrl = url;
12942             }
12943             if(typeof url == "function"){
12944                 url = url.call(this);
12945             }
12946
12947             method = method || (params ? "POST" : "GET");
12948             if(method == "GET"){
12949                 url = this.prepareUrl(url);
12950             }
12951
12952             var o = Roo.apply(cfg ||{}, {
12953                 url : url,
12954                 params: params,
12955                 success: this.successDelegate,
12956                 failure: this.failureDelegate,
12957                 callback: undefined,
12958                 timeout: (this.timeout*1000),
12959                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12960             });
12961             Roo.log("updated manager called with timeout of " + o.timeout);
12962             this.transaction = Roo.Ajax.request(o);
12963         }
12964     },
12965
12966     /**
12967      * 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.
12968      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12969      * @param {String/HTMLElement} form The form Id or form element
12970      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12971      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12972      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12973      */
12974     formUpdate : function(form, url, reset, callback){
12975         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12976             if(typeof url == "function"){
12977                 url = url.call(this);
12978             }
12979             form = Roo.getDom(form);
12980             this.transaction = Roo.Ajax.request({
12981                 form: form,
12982                 url:url,
12983                 success: this.successDelegate,
12984                 failure: this.failureDelegate,
12985                 timeout: (this.timeout*1000),
12986                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12987             });
12988             this.showLoading.defer(1, this);
12989         }
12990     },
12991
12992     /**
12993      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12994      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12995      */
12996     refresh : function(callback){
12997         if(this.defaultUrl == null){
12998             return;
12999         }
13000         this.update(this.defaultUrl, null, callback, true);
13001     },
13002
13003     /**
13004      * Set this element to auto refresh.
13005      * @param {Number} interval How often to update (in seconds).
13006      * @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)
13007      * @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}
13008      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13009      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13010      */
13011     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13012         if(refreshNow){
13013             this.update(url || this.defaultUrl, params, callback, true);
13014         }
13015         if(this.autoRefreshProcId){
13016             clearInterval(this.autoRefreshProcId);
13017         }
13018         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13019     },
13020
13021     /**
13022      * Stop auto refresh on this element.
13023      */
13024      stopAutoRefresh : function(){
13025         if(this.autoRefreshProcId){
13026             clearInterval(this.autoRefreshProcId);
13027             delete this.autoRefreshProcId;
13028         }
13029     },
13030
13031     isAutoRefreshing : function(){
13032        return this.autoRefreshProcId ? true : false;
13033     },
13034     /**
13035      * Called to update the element to "Loading" state. Override to perform custom action.
13036      */
13037     showLoading : function(){
13038         if(this.showLoadIndicator){
13039             this.el.update(this.indicatorText);
13040         }
13041     },
13042
13043     /**
13044      * Adds unique parameter to query string if disableCaching = true
13045      * @private
13046      */
13047     prepareUrl : function(url){
13048         if(this.disableCaching){
13049             var append = "_dc=" + (new Date().getTime());
13050             if(url.indexOf("?") !== -1){
13051                 url += "&" + append;
13052             }else{
13053                 url += "?" + append;
13054             }
13055         }
13056         return url;
13057     },
13058
13059     /**
13060      * @private
13061      */
13062     processSuccess : function(response){
13063         this.transaction = null;
13064         if(response.argument.form && response.argument.reset){
13065             try{ // put in try/catch since some older FF releases had problems with this
13066                 response.argument.form.reset();
13067             }catch(e){}
13068         }
13069         if(this.loadScripts){
13070             this.renderer.render(this.el, response, this,
13071                 this.updateComplete.createDelegate(this, [response]));
13072         }else{
13073             this.renderer.render(this.el, response, this);
13074             this.updateComplete(response);
13075         }
13076     },
13077
13078     updateComplete : function(response){
13079         this.fireEvent("update", this.el, response);
13080         if(typeof response.argument.callback == "function"){
13081             response.argument.callback(this.el, true, response);
13082         }
13083     },
13084
13085     /**
13086      * @private
13087      */
13088     processFailure : function(response){
13089         this.transaction = null;
13090         this.fireEvent("failure", this.el, response);
13091         if(typeof response.argument.callback == "function"){
13092             response.argument.callback(this.el, false, response);
13093         }
13094     },
13095
13096     /**
13097      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13098      * @param {Object} renderer The object implementing the render() method
13099      */
13100     setRenderer : function(renderer){
13101         this.renderer = renderer;
13102     },
13103
13104     getRenderer : function(){
13105        return this.renderer;
13106     },
13107
13108     /**
13109      * Set the defaultUrl used for updates
13110      * @param {String/Function} defaultUrl The url or a function to call to get the url
13111      */
13112     setDefaultUrl : function(defaultUrl){
13113         this.defaultUrl = defaultUrl;
13114     },
13115
13116     /**
13117      * Aborts the executing transaction
13118      */
13119     abort : function(){
13120         if(this.transaction){
13121             Roo.Ajax.abort(this.transaction);
13122         }
13123     },
13124
13125     /**
13126      * Returns true if an update is in progress
13127      * @return {Boolean}
13128      */
13129     isUpdating : function(){
13130         if(this.transaction){
13131             return Roo.Ajax.isLoading(this.transaction);
13132         }
13133         return false;
13134     }
13135 });
13136
13137 /**
13138  * @class Roo.UpdateManager.defaults
13139  * @static (not really - but it helps the doc tool)
13140  * The defaults collection enables customizing the default properties of UpdateManager
13141  */
13142    Roo.UpdateManager.defaults = {
13143        /**
13144          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13145          * @type Number
13146          */
13147          timeout : 30,
13148
13149          /**
13150          * True to process scripts by default (Defaults to false).
13151          * @type Boolean
13152          */
13153         loadScripts : false,
13154
13155         /**
13156         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13157         * @type String
13158         */
13159         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13160         /**
13161          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13162          * @type Boolean
13163          */
13164         disableCaching : false,
13165         /**
13166          * Whether to show indicatorText when loading (Defaults to true).
13167          * @type Boolean
13168          */
13169         showLoadIndicator : true,
13170         /**
13171          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13172          * @type String
13173          */
13174         indicatorText : '<div class="loading-indicator">Loading...</div>'
13175    };
13176
13177 /**
13178  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13179  *Usage:
13180  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13181  * @param {String/HTMLElement/Roo.Element} el The element to update
13182  * @param {String} url The url
13183  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13184  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13185  * @static
13186  * @deprecated
13187  * @member Roo.UpdateManager
13188  */
13189 Roo.UpdateManager.updateElement = function(el, url, params, options){
13190     var um = Roo.get(el, true).getUpdateManager();
13191     Roo.apply(um, options);
13192     um.update(url, params, options ? options.callback : null);
13193 };
13194 // alias for backwards compat
13195 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13196 /**
13197  * @class Roo.UpdateManager.BasicRenderer
13198  * Default Content renderer. Updates the elements innerHTML with the responseText.
13199  */
13200 Roo.UpdateManager.BasicRenderer = function(){};
13201
13202 Roo.UpdateManager.BasicRenderer.prototype = {
13203     /**
13204      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13205      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13206      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13207      * @param {Roo.Element} el The element being rendered
13208      * @param {Object} response The YUI Connect response object
13209      * @param {UpdateManager} updateManager The calling update manager
13210      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13211      */
13212      render : function(el, response, updateManager, callback){
13213         el.update(response.responseText, updateManager.loadScripts, callback);
13214     }
13215 };
13216 /*
13217  * Based on:
13218  * Roo JS
13219  * (c)) Alan Knowles
13220  * Licence : LGPL
13221  */
13222
13223
13224 /**
13225  * @class Roo.DomTemplate
13226  * @extends Roo.Template
13227  * An effort at a dom based template engine..
13228  *
13229  * Similar to XTemplate, except it uses dom parsing to create the template..
13230  *
13231  * Supported features:
13232  *
13233  *  Tags:
13234
13235 <pre><code>
13236       {a_variable} - output encoded.
13237       {a_variable.format:("Y-m-d")} - call a method on the variable
13238       {a_variable:raw} - unencoded output
13239       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13240       {a_variable:this.method_on_template(...)} - call a method on the template object.
13241  
13242 </code></pre>
13243  *  The tpl tag:
13244 <pre><code>
13245         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13246         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13247         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13248         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13249   
13250 </code></pre>
13251  *      
13252  */
13253 Roo.DomTemplate = function()
13254 {
13255      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13256      if (this.html) {
13257         this.compile();
13258      }
13259 };
13260
13261
13262 Roo.extend(Roo.DomTemplate, Roo.Template, {
13263     /**
13264      * id counter for sub templates.
13265      */
13266     id : 0,
13267     /**
13268      * flag to indicate if dom parser is inside a pre,
13269      * it will strip whitespace if not.
13270      */
13271     inPre : false,
13272     
13273     /**
13274      * The various sub templates
13275      */
13276     tpls : false,
13277     
13278     
13279     
13280     /**
13281      *
13282      * basic tag replacing syntax
13283      * WORD:WORD()
13284      *
13285      * // you can fake an object call by doing this
13286      *  x.t:(test,tesT) 
13287      * 
13288      */
13289     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13290     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13291     
13292     iterChild : function (node, method) {
13293         
13294         var oldPre = this.inPre;
13295         if (node.tagName == 'PRE') {
13296             this.inPre = true;
13297         }
13298         for( var i = 0; i < node.childNodes.length; i++) {
13299             method.call(this, node.childNodes[i]);
13300         }
13301         this.inPre = oldPre;
13302     },
13303     
13304     
13305     
13306     /**
13307      * compile the template
13308      *
13309      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13310      *
13311      */
13312     compile: function()
13313     {
13314         var s = this.html;
13315         
13316         // covert the html into DOM...
13317         var doc = false;
13318         var div =false;
13319         try {
13320             doc = document.implementation.createHTMLDocument("");
13321             doc.documentElement.innerHTML =   this.html  ;
13322             div = doc.documentElement;
13323         } catch (e) {
13324             // old IE... - nasty -- it causes all sorts of issues.. with
13325             // images getting pulled from server..
13326             div = document.createElement('div');
13327             div.innerHTML = this.html;
13328         }
13329         //doc.documentElement.innerHTML = htmlBody
13330          
13331         
13332         
13333         this.tpls = [];
13334         var _t = this;
13335         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13336         
13337         var tpls = this.tpls;
13338         
13339         // create a top level template from the snippet..
13340         
13341         //Roo.log(div.innerHTML);
13342         
13343         var tpl = {
13344             uid : 'master',
13345             id : this.id++,
13346             attr : false,
13347             value : false,
13348             body : div.innerHTML,
13349             
13350             forCall : false,
13351             execCall : false,
13352             dom : div,
13353             isTop : true
13354             
13355         };
13356         tpls.unshift(tpl);
13357         
13358         
13359         // compile them...
13360         this.tpls = [];
13361         Roo.each(tpls, function(tp){
13362             this.compileTpl(tp);
13363             this.tpls[tp.id] = tp;
13364         }, this);
13365         
13366         this.master = tpls[0];
13367         return this;
13368         
13369         
13370     },
13371     
13372     compileNode : function(node, istop) {
13373         // test for
13374         //Roo.log(node);
13375         
13376         
13377         // skip anything not a tag..
13378         if (node.nodeType != 1) {
13379             if (node.nodeType == 3 && !this.inPre) {
13380                 // reduce white space..
13381                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13382                 
13383             }
13384             return;
13385         }
13386         
13387         var tpl = {
13388             uid : false,
13389             id : false,
13390             attr : false,
13391             value : false,
13392             body : '',
13393             
13394             forCall : false,
13395             execCall : false,
13396             dom : false,
13397             isTop : istop
13398             
13399             
13400         };
13401         
13402         
13403         switch(true) {
13404             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13405             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13406             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13407             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13408             // no default..
13409         }
13410         
13411         
13412         if (!tpl.attr) {
13413             // just itterate children..
13414             this.iterChild(node,this.compileNode);
13415             return;
13416         }
13417         tpl.uid = this.id++;
13418         tpl.value = node.getAttribute('roo-' +  tpl.attr);
13419         node.removeAttribute('roo-'+ tpl.attr);
13420         if (tpl.attr != 'name') {
13421             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13422             node.parentNode.replaceChild(placeholder,  node);
13423         } else {
13424             
13425             var placeholder =  document.createElement('span');
13426             placeholder.className = 'roo-tpl-' + tpl.value;
13427             node.parentNode.replaceChild(placeholder,  node);
13428         }
13429         
13430         // parent now sees '{domtplXXXX}
13431         this.iterChild(node,this.compileNode);
13432         
13433         // we should now have node body...
13434         var div = document.createElement('div');
13435         div.appendChild(node);
13436         tpl.dom = node;
13437         // this has the unfortunate side effect of converting tagged attributes
13438         // eg. href="{...}" into %7C...%7D
13439         // this has been fixed by searching for those combo's although it's a bit hacky..
13440         
13441         
13442         tpl.body = div.innerHTML;
13443         
13444         
13445          
13446         tpl.id = tpl.uid;
13447         switch(tpl.attr) {
13448             case 'for' :
13449                 switch (tpl.value) {
13450                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13451                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13452                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13453                 }
13454                 break;
13455             
13456             case 'exec':
13457                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13458                 break;
13459             
13460             case 'if':     
13461                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13462                 break;
13463             
13464             case 'name':
13465                 tpl.id  = tpl.value; // replace non characters???
13466                 break;
13467             
13468         }
13469         
13470         
13471         this.tpls.push(tpl);
13472         
13473         
13474         
13475     },
13476     
13477     
13478     
13479     
13480     /**
13481      * Compile a segment of the template into a 'sub-template'
13482      *
13483      * 
13484      * 
13485      *
13486      */
13487     compileTpl : function(tpl)
13488     {
13489         var fm = Roo.util.Format;
13490         var useF = this.disableFormats !== true;
13491         
13492         var sep = Roo.isGecko ? "+\n" : ",\n";
13493         
13494         var undef = function(str) {
13495             Roo.debug && Roo.log("Property not found :"  + str);
13496             return '';
13497         };
13498           
13499         //Roo.log(tpl.body);
13500         
13501         
13502         
13503         var fn = function(m, lbrace, name, format, args)
13504         {
13505             //Roo.log("ARGS");
13506             //Roo.log(arguments);
13507             args = args ? args.replace(/\\'/g,"'") : args;
13508             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13509             if (typeof(format) == 'undefined') {
13510                 format =  'htmlEncode'; 
13511             }
13512             if (format == 'raw' ) {
13513                 format = false;
13514             }
13515             
13516             if(name.substr(0, 6) == 'domtpl'){
13517                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13518             }
13519             
13520             // build an array of options to determine if value is undefined..
13521             
13522             // basically get 'xxxx.yyyy' then do
13523             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13524             //    (function () { Roo.log("Property not found"); return ''; })() :
13525             //    ......
13526             
13527             var udef_ar = [];
13528             var lookfor = '';
13529             Roo.each(name.split('.'), function(st) {
13530                 lookfor += (lookfor.length ? '.': '') + st;
13531                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
13532             });
13533             
13534             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13535             
13536             
13537             if(format && useF){
13538                 
13539                 args = args ? ',' + args : "";
13540                  
13541                 if(format.substr(0, 5) != "this."){
13542                     format = "fm." + format + '(';
13543                 }else{
13544                     format = 'this.call("'+ format.substr(5) + '", ';
13545                     args = ", values";
13546                 }
13547                 
13548                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
13549             }
13550              
13551             if (args && args.length) {
13552                 // called with xxyx.yuu:(test,test)
13553                 // change to ()
13554                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
13555             }
13556             // raw.. - :raw modifier..
13557             return "'"+ sep + udef_st  + name + ")"+sep+"'";
13558             
13559         };
13560         var body;
13561         // branched to use + in gecko and [].join() in others
13562         if(Roo.isGecko){
13563             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
13564                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13565                     "';};};";
13566         }else{
13567             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
13568             body.push(tpl.body.replace(/(\r\n|\n)/g,
13569                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13570             body.push("'].join('');};};");
13571             body = body.join('');
13572         }
13573         
13574         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13575        
13576         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
13577         eval(body);
13578         
13579         return this;
13580     },
13581      
13582     /**
13583      * same as applyTemplate, except it's done to one of the subTemplates
13584      * when using named templates, you can do:
13585      *
13586      * var str = pl.applySubTemplate('your-name', values);
13587      *
13588      * 
13589      * @param {Number} id of the template
13590      * @param {Object} values to apply to template
13591      * @param {Object} parent (normaly the instance of this object)
13592      */
13593     applySubTemplate : function(id, values, parent)
13594     {
13595         
13596         
13597         var t = this.tpls[id];
13598         
13599         
13600         try { 
13601             if(t.ifCall && !t.ifCall.call(this, values, parent)){
13602                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13603                 return '';
13604             }
13605         } catch(e) {
13606             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13607             Roo.log(values);
13608           
13609             return '';
13610         }
13611         try { 
13612             
13613             if(t.execCall && t.execCall.call(this, values, parent)){
13614                 return '';
13615             }
13616         } catch(e) {
13617             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13618             Roo.log(values);
13619             return '';
13620         }
13621         
13622         try {
13623             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13624             parent = t.target ? values : parent;
13625             if(t.forCall && vs instanceof Array){
13626                 var buf = [];
13627                 for(var i = 0, len = vs.length; i < len; i++){
13628                     try {
13629                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
13630                     } catch (e) {
13631                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13632                         Roo.log(e.body);
13633                         //Roo.log(t.compiled);
13634                         Roo.log(vs[i]);
13635                     }   
13636                 }
13637                 return buf.join('');
13638             }
13639         } catch (e) {
13640             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13641             Roo.log(values);
13642             return '';
13643         }
13644         try {
13645             return t.compiled.call(this, vs, parent);
13646         } catch (e) {
13647             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13648             Roo.log(e.body);
13649             //Roo.log(t.compiled);
13650             Roo.log(values);
13651             return '';
13652         }
13653     },
13654
13655    
13656
13657     applyTemplate : function(values){
13658         return this.master.compiled.call(this, values, {});
13659         //var s = this.subs;
13660     },
13661
13662     apply : function(){
13663         return this.applyTemplate.apply(this, arguments);
13664     }
13665
13666  });
13667
13668 Roo.DomTemplate.from = function(el){
13669     el = Roo.getDom(el);
13670     return new Roo.Domtemplate(el.value || el.innerHTML);
13671 };/*
13672  * Based on:
13673  * Ext JS Library 1.1.1
13674  * Copyright(c) 2006-2007, Ext JS, LLC.
13675  *
13676  * Originally Released Under LGPL - original licence link has changed is not relivant.
13677  *
13678  * Fork - LGPL
13679  * <script type="text/javascript">
13680  */
13681
13682 /**
13683  * @class Roo.util.DelayedTask
13684  * Provides a convenient method of performing setTimeout where a new
13685  * timeout cancels the old timeout. An example would be performing validation on a keypress.
13686  * You can use this class to buffer
13687  * the keypress events for a certain number of milliseconds, and perform only if they stop
13688  * for that amount of time.
13689  * @constructor The parameters to this constructor serve as defaults and are not required.
13690  * @param {Function} fn (optional) The default function to timeout
13691  * @param {Object} scope (optional) The default scope of that timeout
13692  * @param {Array} args (optional) The default Array of arguments
13693  */
13694 Roo.util.DelayedTask = function(fn, scope, args){
13695     var id = null, d, t;
13696
13697     var call = function(){
13698         var now = new Date().getTime();
13699         if(now - t >= d){
13700             clearInterval(id);
13701             id = null;
13702             fn.apply(scope, args || []);
13703         }
13704     };
13705     /**
13706      * Cancels any pending timeout and queues a new one
13707      * @param {Number} delay The milliseconds to delay
13708      * @param {Function} newFn (optional) Overrides function passed to constructor
13709      * @param {Object} newScope (optional) Overrides scope passed to constructor
13710      * @param {Array} newArgs (optional) Overrides args passed to constructor
13711      */
13712     this.delay = function(delay, newFn, newScope, newArgs){
13713         if(id && delay != d){
13714             this.cancel();
13715         }
13716         d = delay;
13717         t = new Date().getTime();
13718         fn = newFn || fn;
13719         scope = newScope || scope;
13720         args = newArgs || args;
13721         if(!id){
13722             id = setInterval(call, d);
13723         }
13724     };
13725
13726     /**
13727      * Cancel the last queued timeout
13728      */
13729     this.cancel = function(){
13730         if(id){
13731             clearInterval(id);
13732             id = null;
13733         }
13734     };
13735 };/*
13736  * Based on:
13737  * Ext JS Library 1.1.1
13738  * Copyright(c) 2006-2007, Ext JS, LLC.
13739  *
13740  * Originally Released Under LGPL - original licence link has changed is not relivant.
13741  *
13742  * Fork - LGPL
13743  * <script type="text/javascript">
13744  */
13745 /**
13746  * @class Roo.util.TaskRunner
13747  * Manage background tasks - not sure why this is better that setInterval?
13748  * @static
13749  *
13750  */
13751  
13752 Roo.util.TaskRunner = function(interval){
13753     interval = interval || 10;
13754     var tasks = [], removeQueue = [];
13755     var id = 0;
13756     var running = false;
13757
13758     var stopThread = function(){
13759         running = false;
13760         clearInterval(id);
13761         id = 0;
13762     };
13763
13764     var startThread = function(){
13765         if(!running){
13766             running = true;
13767             id = setInterval(runTasks, interval);
13768         }
13769     };
13770
13771     var removeTask = function(task){
13772         removeQueue.push(task);
13773         if(task.onStop){
13774             task.onStop();
13775         }
13776     };
13777
13778     var runTasks = function(){
13779         if(removeQueue.length > 0){
13780             for(var i = 0, len = removeQueue.length; i < len; i++){
13781                 tasks.remove(removeQueue[i]);
13782             }
13783             removeQueue = [];
13784             if(tasks.length < 1){
13785                 stopThread();
13786                 return;
13787             }
13788         }
13789         var now = new Date().getTime();
13790         for(var i = 0, len = tasks.length; i < len; ++i){
13791             var t = tasks[i];
13792             var itime = now - t.taskRunTime;
13793             if(t.interval <= itime){
13794                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13795                 t.taskRunTime = now;
13796                 if(rt === false || t.taskRunCount === t.repeat){
13797                     removeTask(t);
13798                     return;
13799                 }
13800             }
13801             if(t.duration && t.duration <= (now - t.taskStartTime)){
13802                 removeTask(t);
13803             }
13804         }
13805     };
13806
13807     /**
13808      * Queues a new task.
13809      * @param {Object} task
13810      *
13811      * Task property : interval = how frequent to run.
13812      * Task object should implement
13813      * function run()
13814      * Task object may implement
13815      * function onStop()
13816      */
13817     this.start = function(task){
13818         tasks.push(task);
13819         task.taskStartTime = new Date().getTime();
13820         task.taskRunTime = 0;
13821         task.taskRunCount = 0;
13822         startThread();
13823         return task;
13824     };
13825     /**
13826      * Stop  new task.
13827      * @param {Object} task
13828      */
13829     this.stop = function(task){
13830         removeTask(task);
13831         return task;
13832     };
13833     /**
13834      * Stop all Tasks
13835      */
13836     this.stopAll = function(){
13837         stopThread();
13838         for(var i = 0, len = tasks.length; i < len; i++){
13839             if(tasks[i].onStop){
13840                 tasks[i].onStop();
13841             }
13842         }
13843         tasks = [];
13844         removeQueue = [];
13845     };
13846 };
13847
13848 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13849  * Based on:
13850  * Ext JS Library 1.1.1
13851  * Copyright(c) 2006-2007, Ext JS, LLC.
13852  *
13853  * Originally Released Under LGPL - original licence link has changed is not relivant.
13854  *
13855  * Fork - LGPL
13856  * <script type="text/javascript">
13857  */
13858
13859  
13860 /**
13861  * @class Roo.util.MixedCollection
13862  * @extends Roo.util.Observable
13863  * A Collection class that maintains both numeric indexes and keys and exposes events.
13864  * @constructor
13865  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13866  * collection (defaults to false)
13867  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13868  * and return the key value for that item.  This is used when available to look up the key on items that
13869  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
13870  * equivalent to providing an implementation for the {@link #getKey} method.
13871  */
13872 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13873     this.items = [];
13874     this.map = {};
13875     this.keys = [];
13876     this.length = 0;
13877     this.addEvents({
13878         /**
13879          * @event clear
13880          * Fires when the collection is cleared.
13881          */
13882         "clear" : true,
13883         /**
13884          * @event add
13885          * Fires when an item is added to the collection.
13886          * @param {Number} index The index at which the item was added.
13887          * @param {Object} o The item added.
13888          * @param {String} key The key associated with the added item.
13889          */
13890         "add" : true,
13891         /**
13892          * @event replace
13893          * Fires when an item is replaced in the collection.
13894          * @param {String} key he key associated with the new added.
13895          * @param {Object} old The item being replaced.
13896          * @param {Object} new The new item.
13897          */
13898         "replace" : true,
13899         /**
13900          * @event remove
13901          * Fires when an item is removed from the collection.
13902          * @param {Object} o The item being removed.
13903          * @param {String} key (optional) The key associated with the removed item.
13904          */
13905         "remove" : true,
13906         "sort" : true
13907     });
13908     this.allowFunctions = allowFunctions === true;
13909     if(keyFn){
13910         this.getKey = keyFn;
13911     }
13912     Roo.util.MixedCollection.superclass.constructor.call(this);
13913 };
13914
13915 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13916     allowFunctions : false,
13917     
13918 /**
13919  * Adds an item to the collection.
13920  * @param {String} key The key to associate with the item
13921  * @param {Object} o The item to add.
13922  * @return {Object} The item added.
13923  */
13924     add : function(key, o){
13925         if(arguments.length == 1){
13926             o = arguments[0];
13927             key = this.getKey(o);
13928         }
13929         if(typeof key == "undefined" || key === null){
13930             this.length++;
13931             this.items.push(o);
13932             this.keys.push(null);
13933         }else{
13934             var old = this.map[key];
13935             if(old){
13936                 return this.replace(key, o);
13937             }
13938             this.length++;
13939             this.items.push(o);
13940             this.map[key] = o;
13941             this.keys.push(key);
13942         }
13943         this.fireEvent("add", this.length-1, o, key);
13944         return o;
13945     },
13946        
13947 /**
13948   * MixedCollection has a generic way to fetch keys if you implement getKey.
13949 <pre><code>
13950 // normal way
13951 var mc = new Roo.util.MixedCollection();
13952 mc.add(someEl.dom.id, someEl);
13953 mc.add(otherEl.dom.id, otherEl);
13954 //and so on
13955
13956 // using getKey
13957 var mc = new Roo.util.MixedCollection();
13958 mc.getKey = function(el){
13959    return el.dom.id;
13960 };
13961 mc.add(someEl);
13962 mc.add(otherEl);
13963
13964 // or via the constructor
13965 var mc = new Roo.util.MixedCollection(false, function(el){
13966    return el.dom.id;
13967 });
13968 mc.add(someEl);
13969 mc.add(otherEl);
13970 </code></pre>
13971  * @param o {Object} The item for which to find the key.
13972  * @return {Object} The key for the passed item.
13973  */
13974     getKey : function(o){
13975          return o.id; 
13976     },
13977    
13978 /**
13979  * Replaces an item in the collection.
13980  * @param {String} key The key associated with the item to replace, or the item to replace.
13981  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13982  * @return {Object}  The new item.
13983  */
13984     replace : function(key, o){
13985         if(arguments.length == 1){
13986             o = arguments[0];
13987             key = this.getKey(o);
13988         }
13989         var old = this.item(key);
13990         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13991              return this.add(key, o);
13992         }
13993         var index = this.indexOfKey(key);
13994         this.items[index] = o;
13995         this.map[key] = o;
13996         this.fireEvent("replace", key, old, o);
13997         return o;
13998     },
13999    
14000 /**
14001  * Adds all elements of an Array or an Object to the collection.
14002  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14003  * an Array of values, each of which are added to the collection.
14004  */
14005     addAll : function(objs){
14006         if(arguments.length > 1 || objs instanceof Array){
14007             var args = arguments.length > 1 ? arguments : objs;
14008             for(var i = 0, len = args.length; i < len; i++){
14009                 this.add(args[i]);
14010             }
14011         }else{
14012             for(var key in objs){
14013                 if(this.allowFunctions || typeof objs[key] != "function"){
14014                     this.add(key, objs[key]);
14015                 }
14016             }
14017         }
14018     },
14019    
14020 /**
14021  * Executes the specified function once for every item in the collection, passing each
14022  * item as the first and only parameter. returning false from the function will stop the iteration.
14023  * @param {Function} fn The function to execute for each item.
14024  * @param {Object} scope (optional) The scope in which to execute the function.
14025  */
14026     each : function(fn, scope){
14027         var items = [].concat(this.items); // each safe for removal
14028         for(var i = 0, len = items.length; i < len; i++){
14029             if(fn.call(scope || items[i], items[i], i, len) === false){
14030                 break;
14031             }
14032         }
14033     },
14034    
14035 /**
14036  * Executes the specified function once for every key in the collection, passing each
14037  * key, and its associated item as the first two parameters.
14038  * @param {Function} fn The function to execute for each item.
14039  * @param {Object} scope (optional) The scope in which to execute the function.
14040  */
14041     eachKey : function(fn, scope){
14042         for(var i = 0, len = this.keys.length; i < len; i++){
14043             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14044         }
14045     },
14046    
14047 /**
14048  * Returns the first item in the collection which elicits a true return value from the
14049  * passed selection function.
14050  * @param {Function} fn The selection function to execute for each item.
14051  * @param {Object} scope (optional) The scope in which to execute the function.
14052  * @return {Object} The first item in the collection which returned true from the selection function.
14053  */
14054     find : function(fn, scope){
14055         for(var i = 0, len = this.items.length; i < len; i++){
14056             if(fn.call(scope || window, this.items[i], this.keys[i])){
14057                 return this.items[i];
14058             }
14059         }
14060         return null;
14061     },
14062    
14063 /**
14064  * Inserts an item at the specified index in the collection.
14065  * @param {Number} index The index to insert the item at.
14066  * @param {String} key The key to associate with the new item, or the item itself.
14067  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14068  * @return {Object} The item inserted.
14069  */
14070     insert : function(index, key, o){
14071         if(arguments.length == 2){
14072             o = arguments[1];
14073             key = this.getKey(o);
14074         }
14075         if(index >= this.length){
14076             return this.add(key, o);
14077         }
14078         this.length++;
14079         this.items.splice(index, 0, o);
14080         if(typeof key != "undefined" && key != null){
14081             this.map[key] = o;
14082         }
14083         this.keys.splice(index, 0, key);
14084         this.fireEvent("add", index, o, key);
14085         return o;
14086     },
14087    
14088 /**
14089  * Removed an item from the collection.
14090  * @param {Object} o The item to remove.
14091  * @return {Object} The item removed.
14092  */
14093     remove : function(o){
14094         return this.removeAt(this.indexOf(o));
14095     },
14096    
14097 /**
14098  * Remove an item from a specified index in the collection.
14099  * @param {Number} index The index within the collection of the item to remove.
14100  */
14101     removeAt : function(index){
14102         if(index < this.length && index >= 0){
14103             this.length--;
14104             var o = this.items[index];
14105             this.items.splice(index, 1);
14106             var key = this.keys[index];
14107             if(typeof key != "undefined"){
14108                 delete this.map[key];
14109             }
14110             this.keys.splice(index, 1);
14111             this.fireEvent("remove", o, key);
14112         }
14113     },
14114    
14115 /**
14116  * Removed an item associated with the passed key fom the collection.
14117  * @param {String} key The key of the item to remove.
14118  */
14119     removeKey : function(key){
14120         return this.removeAt(this.indexOfKey(key));
14121     },
14122    
14123 /**
14124  * Returns the number of items in the collection.
14125  * @return {Number} the number of items in the collection.
14126  */
14127     getCount : function(){
14128         return this.length; 
14129     },
14130    
14131 /**
14132  * Returns index within the collection of the passed Object.
14133  * @param {Object} o The item to find the index of.
14134  * @return {Number} index of the item.
14135  */
14136     indexOf : function(o){
14137         if(!this.items.indexOf){
14138             for(var i = 0, len = this.items.length; i < len; i++){
14139                 if(this.items[i] == o) {
14140                     return i;
14141                 }
14142             }
14143             return -1;
14144         }else{
14145             return this.items.indexOf(o);
14146         }
14147     },
14148    
14149 /**
14150  * Returns index within the collection of the passed key.
14151  * @param {String} key The key to find the index of.
14152  * @return {Number} index of the key.
14153  */
14154     indexOfKey : function(key){
14155         if(!this.keys.indexOf){
14156             for(var i = 0, len = this.keys.length; i < len; i++){
14157                 if(this.keys[i] == key) {
14158                     return i;
14159                 }
14160             }
14161             return -1;
14162         }else{
14163             return this.keys.indexOf(key);
14164         }
14165     },
14166    
14167 /**
14168  * Returns the item associated with the passed key OR index. Key has priority over index.
14169  * @param {String/Number} key The key or index of the item.
14170  * @return {Object} The item associated with the passed key.
14171  */
14172     item : function(key){
14173         if (key === 'length') {
14174             return null;
14175         }
14176         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14177         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14178     },
14179     
14180 /**
14181  * Returns the item at the specified index.
14182  * @param {Number} index The index of the item.
14183  * @return {Object}
14184  */
14185     itemAt : function(index){
14186         return this.items[index];
14187     },
14188     
14189 /**
14190  * Returns the item associated with the passed key.
14191  * @param {String/Number} key The key of the item.
14192  * @return {Object} The item associated with the passed key.
14193  */
14194     key : function(key){
14195         return this.map[key];
14196     },
14197    
14198 /**
14199  * Returns true if the collection contains the passed Object as an item.
14200  * @param {Object} o  The Object to look for in the collection.
14201  * @return {Boolean} True if the collection contains the Object as an item.
14202  */
14203     contains : function(o){
14204         return this.indexOf(o) != -1;
14205     },
14206    
14207 /**
14208  * Returns true if the collection contains the passed Object as a key.
14209  * @param {String} key The key to look for in the collection.
14210  * @return {Boolean} True if the collection contains the Object as a key.
14211  */
14212     containsKey : function(key){
14213         return typeof this.map[key] != "undefined";
14214     },
14215    
14216 /**
14217  * Removes all items from the collection.
14218  */
14219     clear : function(){
14220         this.length = 0;
14221         this.items = [];
14222         this.keys = [];
14223         this.map = {};
14224         this.fireEvent("clear");
14225     },
14226    
14227 /**
14228  * Returns the first item in the collection.
14229  * @return {Object} the first item in the collection..
14230  */
14231     first : function(){
14232         return this.items[0]; 
14233     },
14234    
14235 /**
14236  * Returns the last item in the collection.
14237  * @return {Object} the last item in the collection..
14238  */
14239     last : function(){
14240         return this.items[this.length-1];   
14241     },
14242     
14243     _sort : function(property, dir, fn){
14244         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14245         fn = fn || function(a, b){
14246             return a-b;
14247         };
14248         var c = [], k = this.keys, items = this.items;
14249         for(var i = 0, len = items.length; i < len; i++){
14250             c[c.length] = {key: k[i], value: items[i], index: i};
14251         }
14252         c.sort(function(a, b){
14253             var v = fn(a[property], b[property]) * dsc;
14254             if(v == 0){
14255                 v = (a.index < b.index ? -1 : 1);
14256             }
14257             return v;
14258         });
14259         for(var i = 0, len = c.length; i < len; i++){
14260             items[i] = c[i].value;
14261             k[i] = c[i].key;
14262         }
14263         this.fireEvent("sort", this);
14264     },
14265     
14266     /**
14267      * Sorts this collection with the passed comparison function
14268      * @param {String} direction (optional) "ASC" or "DESC"
14269      * @param {Function} fn (optional) comparison function
14270      */
14271     sort : function(dir, fn){
14272         this._sort("value", dir, fn);
14273     },
14274     
14275     /**
14276      * Sorts this collection by keys
14277      * @param {String} direction (optional) "ASC" or "DESC"
14278      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14279      */
14280     keySort : function(dir, fn){
14281         this._sort("key", dir, fn || function(a, b){
14282             return String(a).toUpperCase()-String(b).toUpperCase();
14283         });
14284     },
14285     
14286     /**
14287      * Returns a range of items in this collection
14288      * @param {Number} startIndex (optional) defaults to 0
14289      * @param {Number} endIndex (optional) default to the last item
14290      * @return {Array} An array of items
14291      */
14292     getRange : function(start, end){
14293         var items = this.items;
14294         if(items.length < 1){
14295             return [];
14296         }
14297         start = start || 0;
14298         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14299         var r = [];
14300         if(start <= end){
14301             for(var i = start; i <= end; i++) {
14302                     r[r.length] = items[i];
14303             }
14304         }else{
14305             for(var i = start; i >= end; i--) {
14306                     r[r.length] = items[i];
14307             }
14308         }
14309         return r;
14310     },
14311         
14312     /**
14313      * Filter the <i>objects</i> in this collection by a specific property. 
14314      * Returns a new collection that has been filtered.
14315      * @param {String} property A property on your objects
14316      * @param {String/RegExp} value Either string that the property values 
14317      * should start with or a RegExp to test against the property
14318      * @return {MixedCollection} The new filtered collection
14319      */
14320     filter : function(property, value){
14321         if(!value.exec){ // not a regex
14322             value = String(value);
14323             if(value.length == 0){
14324                 return this.clone();
14325             }
14326             value = new RegExp("^" + Roo.escapeRe(value), "i");
14327         }
14328         return this.filterBy(function(o){
14329             return o && value.test(o[property]);
14330         });
14331         },
14332     
14333     /**
14334      * Filter by a function. * Returns a new collection that has been filtered.
14335      * The passed function will be called with each 
14336      * object in the collection. If the function returns true, the value is included 
14337      * otherwise it is filtered.
14338      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14339      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14340      * @return {MixedCollection} The new filtered collection
14341      */
14342     filterBy : function(fn, scope){
14343         var r = new Roo.util.MixedCollection();
14344         r.getKey = this.getKey;
14345         var k = this.keys, it = this.items;
14346         for(var i = 0, len = it.length; i < len; i++){
14347             if(fn.call(scope||this, it[i], k[i])){
14348                                 r.add(k[i], it[i]);
14349                         }
14350         }
14351         return r;
14352     },
14353     
14354     /**
14355      * Creates a duplicate of this collection
14356      * @return {MixedCollection}
14357      */
14358     clone : function(){
14359         var r = new Roo.util.MixedCollection();
14360         var k = this.keys, it = this.items;
14361         for(var i = 0, len = it.length; i < len; i++){
14362             r.add(k[i], it[i]);
14363         }
14364         r.getKey = this.getKey;
14365         return r;
14366     }
14367 });
14368 /**
14369  * Returns the item associated with the passed key or index.
14370  * @method
14371  * @param {String/Number} key The key or index of the item.
14372  * @return {Object} The item associated with the passed key.
14373  */
14374 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14375  * Based on:
14376  * Ext JS Library 1.1.1
14377  * Copyright(c) 2006-2007, Ext JS, LLC.
14378  *
14379  * Originally Released Under LGPL - original licence link has changed is not relivant.
14380  *
14381  * Fork - LGPL
14382  * <script type="text/javascript">
14383  */
14384 /**
14385  * @class Roo.util.JSON
14386  * Modified version of Douglas Crockford"s json.js that doesn"t
14387  * mess with the Object prototype 
14388  * http://www.json.org/js.html
14389  * @static
14390  */
14391 Roo.util.JSON = new (function(){
14392     var useHasOwn = {}.hasOwnProperty ? true : false;
14393     
14394     // crashes Safari in some instances
14395     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14396     
14397     var pad = function(n) {
14398         return n < 10 ? "0" + n : n;
14399     };
14400     
14401     var m = {
14402         "\b": '\\b',
14403         "\t": '\\t',
14404         "\n": '\\n',
14405         "\f": '\\f',
14406         "\r": '\\r',
14407         '"' : '\\"',
14408         "\\": '\\\\'
14409     };
14410
14411     var encodeString = function(s){
14412         if (/["\\\x00-\x1f]/.test(s)) {
14413             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14414                 var c = m[b];
14415                 if(c){
14416                     return c;
14417                 }
14418                 c = b.charCodeAt();
14419                 return "\\u00" +
14420                     Math.floor(c / 16).toString(16) +
14421                     (c % 16).toString(16);
14422             }) + '"';
14423         }
14424         return '"' + s + '"';
14425     };
14426     
14427     var encodeArray = function(o){
14428         var a = ["["], b, i, l = o.length, v;
14429             for (i = 0; i < l; i += 1) {
14430                 v = o[i];
14431                 switch (typeof v) {
14432                     case "undefined":
14433                     case "function":
14434                     case "unknown":
14435                         break;
14436                     default:
14437                         if (b) {
14438                             a.push(',');
14439                         }
14440                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14441                         b = true;
14442                 }
14443             }
14444             a.push("]");
14445             return a.join("");
14446     };
14447     
14448     var encodeDate = function(o){
14449         return '"' + o.getFullYear() + "-" +
14450                 pad(o.getMonth() + 1) + "-" +
14451                 pad(o.getDate()) + "T" +
14452                 pad(o.getHours()) + ":" +
14453                 pad(o.getMinutes()) + ":" +
14454                 pad(o.getSeconds()) + '"';
14455     };
14456     
14457     /**
14458      * Encodes an Object, Array or other value
14459      * @param {Mixed} o The variable to encode
14460      * @return {String} The JSON string
14461      */
14462     this.encode = function(o)
14463     {
14464         // should this be extended to fully wrap stringify..
14465         
14466         if(typeof o == "undefined" || o === null){
14467             return "null";
14468         }else if(o instanceof Array){
14469             return encodeArray(o);
14470         }else if(o instanceof Date){
14471             return encodeDate(o);
14472         }else if(typeof o == "string"){
14473             return encodeString(o);
14474         }else if(typeof o == "number"){
14475             return isFinite(o) ? String(o) : "null";
14476         }else if(typeof o == "boolean"){
14477             return String(o);
14478         }else {
14479             var a = ["{"], b, i, v;
14480             for (i in o) {
14481                 if(!useHasOwn || o.hasOwnProperty(i)) {
14482                     v = o[i];
14483                     switch (typeof v) {
14484                     case "undefined":
14485                     case "function":
14486                     case "unknown":
14487                         break;
14488                     default:
14489                         if(b){
14490                             a.push(',');
14491                         }
14492                         a.push(this.encode(i), ":",
14493                                 v === null ? "null" : this.encode(v));
14494                         b = true;
14495                     }
14496                 }
14497             }
14498             a.push("}");
14499             return a.join("");
14500         }
14501     };
14502     
14503     /**
14504      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14505      * @param {String} json The JSON string
14506      * @return {Object} The resulting object
14507      */
14508     this.decode = function(json){
14509         
14510         return  /** eval:var:json */ eval("(" + json + ')');
14511     };
14512 })();
14513 /** 
14514  * Shorthand for {@link Roo.util.JSON#encode}
14515  * @member Roo encode 
14516  * @method */
14517 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14518 /** 
14519  * Shorthand for {@link Roo.util.JSON#decode}
14520  * @member Roo decode 
14521  * @method */
14522 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14523 /*
14524  * Based on:
14525  * Ext JS Library 1.1.1
14526  * Copyright(c) 2006-2007, Ext JS, LLC.
14527  *
14528  * Originally Released Under LGPL - original licence link has changed is not relivant.
14529  *
14530  * Fork - LGPL
14531  * <script type="text/javascript">
14532  */
14533  
14534 /**
14535  * @class Roo.util.Format
14536  * Reusable data formatting functions
14537  * @static
14538  */
14539 Roo.util.Format = function(){
14540     var trimRe = /^\s+|\s+$/g;
14541     return {
14542         /**
14543          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14544          * @param {String} value The string to truncate
14545          * @param {Number} length The maximum length to allow before truncating
14546          * @return {String} The converted text
14547          */
14548         ellipsis : function(value, len){
14549             if(value && value.length > len){
14550                 return value.substr(0, len-3)+"...";
14551             }
14552             return value;
14553         },
14554
14555         /**
14556          * Checks a reference and converts it to empty string if it is undefined
14557          * @param {Mixed} value Reference to check
14558          * @return {Mixed} Empty string if converted, otherwise the original value
14559          */
14560         undef : function(value){
14561             return typeof value != "undefined" ? value : "";
14562         },
14563
14564         /**
14565          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14566          * @param {String} value The string to encode
14567          * @return {String} The encoded text
14568          */
14569         htmlEncode : function(value){
14570             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
14571         },
14572
14573         /**
14574          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14575          * @param {String} value The string to decode
14576          * @return {String} The decoded text
14577          */
14578         htmlDecode : function(value){
14579             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
14580         },
14581
14582         /**
14583          * Trims any whitespace from either side of a string
14584          * @param {String} value The text to trim
14585          * @return {String} The trimmed text
14586          */
14587         trim : function(value){
14588             return String(value).replace(trimRe, "");
14589         },
14590
14591         /**
14592          * Returns a substring from within an original string
14593          * @param {String} value The original text
14594          * @param {Number} start The start index of the substring
14595          * @param {Number} length The length of the substring
14596          * @return {String} The substring
14597          */
14598         substr : function(value, start, length){
14599             return String(value).substr(start, length);
14600         },
14601
14602         /**
14603          * Converts a string to all lower case letters
14604          * @param {String} value The text to convert
14605          * @return {String} The converted text
14606          */
14607         lowercase : function(value){
14608             return String(value).toLowerCase();
14609         },
14610
14611         /**
14612          * Converts a string to all upper case letters
14613          * @param {String} value The text to convert
14614          * @return {String} The converted text
14615          */
14616         uppercase : function(value){
14617             return String(value).toUpperCase();
14618         },
14619
14620         /**
14621          * Converts the first character only of a string to upper case
14622          * @param {String} value The text to convert
14623          * @return {String} The converted text
14624          */
14625         capitalize : function(value){
14626             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14627         },
14628
14629         // private
14630         call : function(value, fn){
14631             if(arguments.length > 2){
14632                 var args = Array.prototype.slice.call(arguments, 2);
14633                 args.unshift(value);
14634                  
14635                 return /** eval:var:value */  eval(fn).apply(window, args);
14636             }else{
14637                 /** eval:var:value */
14638                 return /** eval:var:value */ eval(fn).call(window, value);
14639             }
14640         },
14641
14642        
14643         /**
14644          * safer version of Math.toFixed..??/
14645          * @param {Number/String} value The numeric value to format
14646          * @param {Number/String} value Decimal places 
14647          * @return {String} The formatted currency string
14648          */
14649         toFixed : function(v, n)
14650         {
14651             // why not use to fixed - precision is buggered???
14652             if (!n) {
14653                 return Math.round(v-0);
14654             }
14655             var fact = Math.pow(10,n+1);
14656             v = (Math.round((v-0)*fact))/fact;
14657             var z = (''+fact).substring(2);
14658             if (v == Math.floor(v)) {
14659                 return Math.floor(v) + '.' + z;
14660             }
14661             
14662             // now just padd decimals..
14663             var ps = String(v).split('.');
14664             var fd = (ps[1] + z);
14665             var r = fd.substring(0,n); 
14666             var rm = fd.substring(n); 
14667             if (rm < 5) {
14668                 return ps[0] + '.' + r;
14669             }
14670             r*=1; // turn it into a number;
14671             r++;
14672             if (String(r).length != n) {
14673                 ps[0]*=1;
14674                 ps[0]++;
14675                 r = String(r).substring(1); // chop the end off.
14676             }
14677             
14678             return ps[0] + '.' + r;
14679              
14680         },
14681         
14682         /**
14683          * Format a number as US currency
14684          * @param {Number/String} value The numeric value to format
14685          * @return {String} The formatted currency string
14686          */
14687         usMoney : function(v){
14688             return '$' + Roo.util.Format.number(v);
14689         },
14690         
14691         /**
14692          * Format a number
14693          * eventually this should probably emulate php's number_format
14694          * @param {Number/String} value The numeric value to format
14695          * @param {Number} decimals number of decimal places
14696          * @param {String} delimiter for thousands (default comma)
14697          * @return {String} The formatted currency string
14698          */
14699         number : function(v, decimals, thousandsDelimiter)
14700         {
14701             // multiply and round.
14702             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14703             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14704             
14705             var mul = Math.pow(10, decimals);
14706             var zero = String(mul).substring(1);
14707             v = (Math.round((v-0)*mul))/mul;
14708             
14709             // if it's '0' number.. then
14710             
14711             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14712             v = String(v);
14713             var ps = v.split('.');
14714             var whole = ps[0];
14715             
14716             var r = /(\d+)(\d{3})/;
14717             // add comma's
14718             
14719             if(thousandsDelimiter.length != 0) {
14720                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14721             } 
14722             
14723             var sub = ps[1] ?
14724                     // has decimals..
14725                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14726                     // does not have decimals
14727                     (decimals ? ('.' + zero) : '');
14728             
14729             
14730             return whole + sub ;
14731         },
14732         
14733         /**
14734          * Parse a value into a formatted date using the specified format pattern.
14735          * @param {Mixed} value The value to format
14736          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14737          * @return {String} The formatted date string
14738          */
14739         date : function(v, format){
14740             if(!v){
14741                 return "";
14742             }
14743             if(!(v instanceof Date)){
14744                 v = new Date(Date.parse(v));
14745             }
14746             return v.dateFormat(format || Roo.util.Format.defaults.date);
14747         },
14748
14749         /**
14750          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14751          * @param {String} format Any valid date format string
14752          * @return {Function} The date formatting function
14753          */
14754         dateRenderer : function(format){
14755             return function(v){
14756                 return Roo.util.Format.date(v, format);  
14757             };
14758         },
14759
14760         // private
14761         stripTagsRE : /<\/?[^>]+>/gi,
14762         
14763         /**
14764          * Strips all HTML tags
14765          * @param {Mixed} value The text from which to strip tags
14766          * @return {String} The stripped text
14767          */
14768         stripTags : function(v){
14769             return !v ? v : String(v).replace(this.stripTagsRE, "");
14770         },
14771         
14772         /**
14773          * Size in Mb,Gb etc.
14774          * @param {Number} value The number to be formated
14775          * @param {number} decimals how many decimal places
14776          * @return {String} the formated string
14777          */
14778         size : function(value, decimals)
14779         {
14780             var sizes = ['b', 'k', 'M', 'G', 'T'];
14781             if (value == 0) {
14782                 return 0;
14783             }
14784             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14785             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
14786         }
14787         
14788         
14789         
14790     };
14791 }();
14792 Roo.util.Format.defaults = {
14793     date : 'd/M/Y'
14794 };/*
14795  * Based on:
14796  * Ext JS Library 1.1.1
14797  * Copyright(c) 2006-2007, Ext JS, LLC.
14798  *
14799  * Originally Released Under LGPL - original licence link has changed is not relivant.
14800  *
14801  * Fork - LGPL
14802  * <script type="text/javascript">
14803  */
14804
14805
14806  
14807
14808 /**
14809  * @class Roo.MasterTemplate
14810  * @extends Roo.Template
14811  * Provides a template that can have child templates. The syntax is:
14812 <pre><code>
14813 var t = new Roo.MasterTemplate(
14814         '&lt;select name="{name}"&gt;',
14815                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
14816         '&lt;/select&gt;'
14817 );
14818 t.add('options', {value: 'foo', text: 'bar'});
14819 // or you can add multiple child elements in one shot
14820 t.addAll('options', [
14821     {value: 'foo', text: 'bar'},
14822     {value: 'foo2', text: 'bar2'},
14823     {value: 'foo3', text: 'bar3'}
14824 ]);
14825 // then append, applying the master template values
14826 t.append('my-form', {name: 'my-select'});
14827 </code></pre>
14828 * A name attribute for the child template is not required if you have only one child
14829 * template or you want to refer to them by index.
14830  */
14831 Roo.MasterTemplate = function(){
14832     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14833     this.originalHtml = this.html;
14834     var st = {};
14835     var m, re = this.subTemplateRe;
14836     re.lastIndex = 0;
14837     var subIndex = 0;
14838     while(m = re.exec(this.html)){
14839         var name = m[1], content = m[2];
14840         st[subIndex] = {
14841             name: name,
14842             index: subIndex,
14843             buffer: [],
14844             tpl : new Roo.Template(content)
14845         };
14846         if(name){
14847             st[name] = st[subIndex];
14848         }
14849         st[subIndex].tpl.compile();
14850         st[subIndex].tpl.call = this.call.createDelegate(this);
14851         subIndex++;
14852     }
14853     this.subCount = subIndex;
14854     this.subs = st;
14855 };
14856 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14857     /**
14858     * The regular expression used to match sub templates
14859     * @type RegExp
14860     * @property
14861     */
14862     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14863
14864     /**
14865      * Applies the passed values to a child template.
14866      * @param {String/Number} name (optional) The name or index of the child template
14867      * @param {Array/Object} values The values to be applied to the template
14868      * @return {MasterTemplate} this
14869      */
14870      add : function(name, values){
14871         if(arguments.length == 1){
14872             values = arguments[0];
14873             name = 0;
14874         }
14875         var s = this.subs[name];
14876         s.buffer[s.buffer.length] = s.tpl.apply(values);
14877         return this;
14878     },
14879
14880     /**
14881      * Applies all the passed values to a child template.
14882      * @param {String/Number} name (optional) The name or index of the child template
14883      * @param {Array} values The values to be applied to the template, this should be an array of objects.
14884      * @param {Boolean} reset (optional) True to reset the template first
14885      * @return {MasterTemplate} this
14886      */
14887     fill : function(name, values, reset){
14888         var a = arguments;
14889         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14890             values = a[0];
14891             name = 0;
14892             reset = a[1];
14893         }
14894         if(reset){
14895             this.reset();
14896         }
14897         for(var i = 0, len = values.length; i < len; i++){
14898             this.add(name, values[i]);
14899         }
14900         return this;
14901     },
14902
14903     /**
14904      * Resets the template for reuse
14905      * @return {MasterTemplate} this
14906      */
14907      reset : function(){
14908         var s = this.subs;
14909         for(var i = 0; i < this.subCount; i++){
14910             s[i].buffer = [];
14911         }
14912         return this;
14913     },
14914
14915     applyTemplate : function(values){
14916         var s = this.subs;
14917         var replaceIndex = -1;
14918         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14919             return s[++replaceIndex].buffer.join("");
14920         });
14921         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14922     },
14923
14924     apply : function(){
14925         return this.applyTemplate.apply(this, arguments);
14926     },
14927
14928     compile : function(){return this;}
14929 });
14930
14931 /**
14932  * Alias for fill().
14933  * @method
14934  */
14935 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14936  /**
14937  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14938  * var tpl = Roo.MasterTemplate.from('element-id');
14939  * @param {String/HTMLElement} el
14940  * @param {Object} config
14941  * @static
14942  */
14943 Roo.MasterTemplate.from = function(el, config){
14944     el = Roo.getDom(el);
14945     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14946 };/*
14947  * Based on:
14948  * Ext JS Library 1.1.1
14949  * Copyright(c) 2006-2007, Ext JS, LLC.
14950  *
14951  * Originally Released Under LGPL - original licence link has changed is not relivant.
14952  *
14953  * Fork - LGPL
14954  * <script type="text/javascript">
14955  */
14956
14957  
14958 /**
14959  * @class Roo.util.CSS
14960  * Utility class for manipulating CSS rules
14961  * @static
14962
14963  */
14964 Roo.util.CSS = function(){
14965         var rules = null;
14966         var doc = document;
14967
14968     var camelRe = /(-[a-z])/gi;
14969     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14970
14971    return {
14972    /**
14973     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14974     * tag and appended to the HEAD of the document.
14975     * @param {String|Object} cssText The text containing the css rules
14976     * @param {String} id An id to add to the stylesheet for later removal
14977     * @return {StyleSheet}
14978     */
14979     createStyleSheet : function(cssText, id){
14980         var ss;
14981         var head = doc.getElementsByTagName("head")[0];
14982         var nrules = doc.createElement("style");
14983         nrules.setAttribute("type", "text/css");
14984         if(id){
14985             nrules.setAttribute("id", id);
14986         }
14987         if (typeof(cssText) != 'string') {
14988             // support object maps..
14989             // not sure if this a good idea.. 
14990             // perhaps it should be merged with the general css handling
14991             // and handle js style props.
14992             var cssTextNew = [];
14993             for(var n in cssText) {
14994                 var citems = [];
14995                 for(var k in cssText[n]) {
14996                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14997                 }
14998                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14999                 
15000             }
15001             cssText = cssTextNew.join("\n");
15002             
15003         }
15004        
15005        
15006        if(Roo.isIE){
15007            head.appendChild(nrules);
15008            ss = nrules.styleSheet;
15009            ss.cssText = cssText;
15010        }else{
15011            try{
15012                 nrules.appendChild(doc.createTextNode(cssText));
15013            }catch(e){
15014                nrules.cssText = cssText; 
15015            }
15016            head.appendChild(nrules);
15017            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15018        }
15019        this.cacheStyleSheet(ss);
15020        return ss;
15021    },
15022
15023    /**
15024     * Removes a style or link tag by id
15025     * @param {String} id The id of the tag
15026     */
15027    removeStyleSheet : function(id){
15028        var existing = doc.getElementById(id);
15029        if(existing){
15030            existing.parentNode.removeChild(existing);
15031        }
15032    },
15033
15034    /**
15035     * Dynamically swaps an existing stylesheet reference for a new one
15036     * @param {String} id The id of an existing link tag to remove
15037     * @param {String} url The href of the new stylesheet to include
15038     */
15039    swapStyleSheet : function(id, url){
15040        this.removeStyleSheet(id);
15041        var ss = doc.createElement("link");
15042        ss.setAttribute("rel", "stylesheet");
15043        ss.setAttribute("type", "text/css");
15044        ss.setAttribute("id", id);
15045        ss.setAttribute("href", url);
15046        doc.getElementsByTagName("head")[0].appendChild(ss);
15047    },
15048    
15049    /**
15050     * Refresh the rule cache if you have dynamically added stylesheets
15051     * @return {Object} An object (hash) of rules indexed by selector
15052     */
15053    refreshCache : function(){
15054        return this.getRules(true);
15055    },
15056
15057    // private
15058    cacheStyleSheet : function(stylesheet){
15059        if(!rules){
15060            rules = {};
15061        }
15062        try{// try catch for cross domain access issue
15063            var ssRules = stylesheet.cssRules || stylesheet.rules;
15064            for(var j = ssRules.length-1; j >= 0; --j){
15065                rules[ssRules[j].selectorText] = ssRules[j];
15066            }
15067        }catch(e){}
15068    },
15069    
15070    /**
15071     * Gets all css rules for the document
15072     * @param {Boolean} refreshCache true to refresh the internal cache
15073     * @return {Object} An object (hash) of rules indexed by selector
15074     */
15075    getRules : function(refreshCache){
15076                 if(rules == null || refreshCache){
15077                         rules = {};
15078                         var ds = doc.styleSheets;
15079                         for(var i =0, len = ds.length; i < len; i++){
15080                             try{
15081                         this.cacheStyleSheet(ds[i]);
15082                     }catch(e){} 
15083                 }
15084                 }
15085                 return rules;
15086         },
15087         
15088         /**
15089     * Gets an an individual CSS rule by selector(s)
15090     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15091     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15092     * @return {CSSRule} The CSS rule or null if one is not found
15093     */
15094    getRule : function(selector, refreshCache){
15095                 var rs = this.getRules(refreshCache);
15096                 if(!(selector instanceof Array)){
15097                     return rs[selector];
15098                 }
15099                 for(var i = 0; i < selector.length; i++){
15100                         if(rs[selector[i]]){
15101                                 return rs[selector[i]];
15102                         }
15103                 }
15104                 return null;
15105         },
15106         
15107         
15108         /**
15109     * Updates a rule property
15110     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15111     * @param {String} property The css property
15112     * @param {String} value The new value for the property
15113     * @return {Boolean} true If a rule was found and updated
15114     */
15115    updateRule : function(selector, property, value){
15116                 if(!(selector instanceof Array)){
15117                         var rule = this.getRule(selector);
15118                         if(rule){
15119                                 rule.style[property.replace(camelRe, camelFn)] = value;
15120                                 return true;
15121                         }
15122                 }else{
15123                         for(var i = 0; i < selector.length; i++){
15124                                 if(this.updateRule(selector[i], property, value)){
15125                                         return true;
15126                                 }
15127                         }
15128                 }
15129                 return false;
15130         }
15131    };   
15132 }();/*
15133  * Based on:
15134  * Ext JS Library 1.1.1
15135  * Copyright(c) 2006-2007, Ext JS, LLC.
15136  *
15137  * Originally Released Under LGPL - original licence link has changed is not relivant.
15138  *
15139  * Fork - LGPL
15140  * <script type="text/javascript">
15141  */
15142
15143  
15144
15145 /**
15146  * @class Roo.util.ClickRepeater
15147  * @extends Roo.util.Observable
15148  * 
15149  * A wrapper class which can be applied to any element. Fires a "click" event while the
15150  * mouse is pressed. The interval between firings may be specified in the config but
15151  * defaults to 10 milliseconds.
15152  * 
15153  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15154  * 
15155  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15156  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15157  * Similar to an autorepeat key delay.
15158  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15159  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15160  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15161  *           "interval" and "delay" are ignored. "immediate" is honored.
15162  * @cfg {Boolean} preventDefault True to prevent the default click event
15163  * @cfg {Boolean} stopDefault True to stop the default click event
15164  * 
15165  * @history
15166  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15167  *     2007-02-02 jvs Renamed to ClickRepeater
15168  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15169  *
15170  *  @constructor
15171  * @param {String/HTMLElement/Element} el The element to listen on
15172  * @param {Object} config
15173  **/
15174 Roo.util.ClickRepeater = function(el, config)
15175 {
15176     this.el = Roo.get(el);
15177     this.el.unselectable();
15178
15179     Roo.apply(this, config);
15180
15181     this.addEvents({
15182     /**
15183      * @event mousedown
15184      * Fires when the mouse button is depressed.
15185      * @param {Roo.util.ClickRepeater} this
15186      */
15187         "mousedown" : true,
15188     /**
15189      * @event click
15190      * Fires on a specified interval during the time the element is pressed.
15191      * @param {Roo.util.ClickRepeater} this
15192      */
15193         "click" : true,
15194     /**
15195      * @event mouseup
15196      * Fires when the mouse key is released.
15197      * @param {Roo.util.ClickRepeater} this
15198      */
15199         "mouseup" : true
15200     });
15201
15202     this.el.on("mousedown", this.handleMouseDown, this);
15203     if(this.preventDefault || this.stopDefault){
15204         this.el.on("click", function(e){
15205             if(this.preventDefault){
15206                 e.preventDefault();
15207             }
15208             if(this.stopDefault){
15209                 e.stopEvent();
15210             }
15211         }, this);
15212     }
15213
15214     // allow inline handler
15215     if(this.handler){
15216         this.on("click", this.handler,  this.scope || this);
15217     }
15218
15219     Roo.util.ClickRepeater.superclass.constructor.call(this);
15220 };
15221
15222 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15223     interval : 20,
15224     delay: 250,
15225     preventDefault : true,
15226     stopDefault : false,
15227     timer : 0,
15228
15229     // private
15230     handleMouseDown : function(){
15231         clearTimeout(this.timer);
15232         this.el.blur();
15233         if(this.pressClass){
15234             this.el.addClass(this.pressClass);
15235         }
15236         this.mousedownTime = new Date();
15237
15238         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15239         this.el.on("mouseout", this.handleMouseOut, this);
15240
15241         this.fireEvent("mousedown", this);
15242         this.fireEvent("click", this);
15243         
15244         this.timer = this.click.defer(this.delay || this.interval, this);
15245     },
15246
15247     // private
15248     click : function(){
15249         this.fireEvent("click", this);
15250         this.timer = this.click.defer(this.getInterval(), this);
15251     },
15252
15253     // private
15254     getInterval: function(){
15255         if(!this.accelerate){
15256             return this.interval;
15257         }
15258         var pressTime = this.mousedownTime.getElapsed();
15259         if(pressTime < 500){
15260             return 400;
15261         }else if(pressTime < 1700){
15262             return 320;
15263         }else if(pressTime < 2600){
15264             return 250;
15265         }else if(pressTime < 3500){
15266             return 180;
15267         }else if(pressTime < 4400){
15268             return 140;
15269         }else if(pressTime < 5300){
15270             return 80;
15271         }else if(pressTime < 6200){
15272             return 50;
15273         }else{
15274             return 10;
15275         }
15276     },
15277
15278     // private
15279     handleMouseOut : function(){
15280         clearTimeout(this.timer);
15281         if(this.pressClass){
15282             this.el.removeClass(this.pressClass);
15283         }
15284         this.el.on("mouseover", this.handleMouseReturn, this);
15285     },
15286
15287     // private
15288     handleMouseReturn : function(){
15289         this.el.un("mouseover", this.handleMouseReturn);
15290         if(this.pressClass){
15291             this.el.addClass(this.pressClass);
15292         }
15293         this.click();
15294     },
15295
15296     // private
15297     handleMouseUp : function(){
15298         clearTimeout(this.timer);
15299         this.el.un("mouseover", this.handleMouseReturn);
15300         this.el.un("mouseout", this.handleMouseOut);
15301         Roo.get(document).un("mouseup", this.handleMouseUp);
15302         this.el.removeClass(this.pressClass);
15303         this.fireEvent("mouseup", this);
15304     }
15305 });/**
15306  * @class Roo.util.Clipboard
15307  * @static
15308  * 
15309  * Clipboard UTILS
15310  * 
15311  **/
15312 Roo.util.Clipboard = {
15313     /**
15314      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15315      * @param {String} text to copy to clipboard
15316      */
15317     write : function(text) {
15318         // navigator clipboard api needs a secure context (https)
15319         if (navigator.clipboard && window.isSecureContext) {
15320             // navigator clipboard api method'
15321             navigator.clipboard.writeText(text);
15322             return ;
15323         } 
15324         // text area method
15325         var ta = document.createElement("textarea");
15326         ta.value = text;
15327         // make the textarea out of viewport
15328         ta.style.position = "fixed";
15329         ta.style.left = "-999999px";
15330         ta.style.top = "-999999px";
15331         document.body.appendChild(ta);
15332         ta.focus();
15333         ta.select();
15334         document.execCommand('copy');
15335         (function() {
15336             ta.remove();
15337         }).defer(100);
15338         
15339     }
15340         
15341 }
15342     /*
15343  * Based on:
15344  * Ext JS Library 1.1.1
15345  * Copyright(c) 2006-2007, Ext JS, LLC.
15346  *
15347  * Originally Released Under LGPL - original licence link has changed is not relivant.
15348  *
15349  * Fork - LGPL
15350  * <script type="text/javascript">
15351  */
15352
15353  
15354 /**
15355  * @class Roo.KeyNav
15356  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15357  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15358  * way to implement custom navigation schemes for any UI component.</p>
15359  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15360  * pageUp, pageDown, del, home, end.  Usage:</p>
15361  <pre><code>
15362 var nav = new Roo.KeyNav("my-element", {
15363     "left" : function(e){
15364         this.moveLeft(e.ctrlKey);
15365     },
15366     "right" : function(e){
15367         this.moveRight(e.ctrlKey);
15368     },
15369     "enter" : function(e){
15370         this.save();
15371     },
15372     scope : this
15373 });
15374 </code></pre>
15375  * @constructor
15376  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15377  * @param {Object} config The config
15378  */
15379 Roo.KeyNav = function(el, config){
15380     this.el = Roo.get(el);
15381     Roo.apply(this, config);
15382     if(!this.disabled){
15383         this.disabled = true;
15384         this.enable();
15385     }
15386 };
15387
15388 Roo.KeyNav.prototype = {
15389     /**
15390      * @cfg {Boolean} disabled
15391      * True to disable this KeyNav instance (defaults to false)
15392      */
15393     disabled : false,
15394     /**
15395      * @cfg {String} defaultEventAction
15396      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15397      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15398      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15399      */
15400     defaultEventAction: "stopEvent",
15401     /**
15402      * @cfg {Boolean} forceKeyDown
15403      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
15404      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15405      * handle keydown instead of keypress.
15406      */
15407     forceKeyDown : false,
15408
15409     // private
15410     prepareEvent : function(e){
15411         var k = e.getKey();
15412         var h = this.keyToHandler[k];
15413         //if(h && this[h]){
15414         //    e.stopPropagation();
15415         //}
15416         if(Roo.isSafari && h && k >= 37 && k <= 40){
15417             e.stopEvent();
15418         }
15419     },
15420
15421     // private
15422     relay : function(e){
15423         var k = e.getKey();
15424         var h = this.keyToHandler[k];
15425         if(h && this[h]){
15426             if(this.doRelay(e, this[h], h) !== true){
15427                 e[this.defaultEventAction]();
15428             }
15429         }
15430     },
15431
15432     // private
15433     doRelay : function(e, h, hname){
15434         return h.call(this.scope || this, e);
15435     },
15436
15437     // possible handlers
15438     enter : false,
15439     left : false,
15440     right : false,
15441     up : false,
15442     down : false,
15443     tab : false,
15444     esc : false,
15445     pageUp : false,
15446     pageDown : false,
15447     del : false,
15448     home : false,
15449     end : false,
15450
15451     // quick lookup hash
15452     keyToHandler : {
15453         37 : "left",
15454         39 : "right",
15455         38 : "up",
15456         40 : "down",
15457         33 : "pageUp",
15458         34 : "pageDown",
15459         46 : "del",
15460         36 : "home",
15461         35 : "end",
15462         13 : "enter",
15463         27 : "esc",
15464         9  : "tab"
15465     },
15466
15467         /**
15468          * Enable this KeyNav
15469          */
15470         enable: function(){
15471                 if(this.disabled){
15472             // ie won't do special keys on keypress, no one else will repeat keys with keydown
15473             // the EventObject will normalize Safari automatically
15474             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15475                 this.el.on("keydown", this.relay,  this);
15476             }else{
15477                 this.el.on("keydown", this.prepareEvent,  this);
15478                 this.el.on("keypress", this.relay,  this);
15479             }
15480                     this.disabled = false;
15481                 }
15482         },
15483
15484         /**
15485          * Disable this KeyNav
15486          */
15487         disable: function(){
15488                 if(!this.disabled){
15489                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15490                 this.el.un("keydown", this.relay);
15491             }else{
15492                 this.el.un("keydown", this.prepareEvent);
15493                 this.el.un("keypress", this.relay);
15494             }
15495                     this.disabled = true;
15496                 }
15497         }
15498 };/*
15499  * Based on:
15500  * Ext JS Library 1.1.1
15501  * Copyright(c) 2006-2007, Ext JS, LLC.
15502  *
15503  * Originally Released Under LGPL - original licence link has changed is not relivant.
15504  *
15505  * Fork - LGPL
15506  * <script type="text/javascript">
15507  */
15508
15509  
15510 /**
15511  * @class Roo.KeyMap
15512  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15513  * The constructor accepts the same config object as defined by {@link #addBinding}.
15514  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15515  * combination it will call the function with this signature (if the match is a multi-key
15516  * combination the callback will still be called only once): (String key, Roo.EventObject e)
15517  * A KeyMap can also handle a string representation of keys.<br />
15518  * Usage:
15519  <pre><code>
15520 // map one key by key code
15521 var map = new Roo.KeyMap("my-element", {
15522     key: 13, // or Roo.EventObject.ENTER
15523     fn: myHandler,
15524     scope: myObject
15525 });
15526
15527 // map multiple keys to one action by string
15528 var map = new Roo.KeyMap("my-element", {
15529     key: "a\r\n\t",
15530     fn: myHandler,
15531     scope: myObject
15532 });
15533
15534 // map multiple keys to multiple actions by strings and array of codes
15535 var map = new Roo.KeyMap("my-element", [
15536     {
15537         key: [10,13],
15538         fn: function(){ alert("Return was pressed"); }
15539     }, {
15540         key: "abc",
15541         fn: function(){ alert('a, b or c was pressed'); }
15542     }, {
15543         key: "\t",
15544         ctrl:true,
15545         shift:true,
15546         fn: function(){ alert('Control + shift + tab was pressed.'); }
15547     }
15548 ]);
15549 </code></pre>
15550  * <b>Note: A KeyMap starts enabled</b>
15551  * @constructor
15552  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15553  * @param {Object} config The config (see {@link #addBinding})
15554  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15555  */
15556 Roo.KeyMap = function(el, config, eventName){
15557     this.el  = Roo.get(el);
15558     this.eventName = eventName || "keydown";
15559     this.bindings = [];
15560     if(config){
15561         this.addBinding(config);
15562     }
15563     this.enable();
15564 };
15565
15566 Roo.KeyMap.prototype = {
15567     /**
15568      * True to stop the event from bubbling and prevent the default browser action if the
15569      * key was handled by the KeyMap (defaults to false)
15570      * @type Boolean
15571      */
15572     stopEvent : false,
15573
15574     /**
15575      * Add a new binding to this KeyMap. The following config object properties are supported:
15576      * <pre>
15577 Property    Type             Description
15578 ----------  ---------------  ----------------------------------------------------------------------
15579 key         String/Array     A single keycode or an array of keycodes to handle
15580 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
15581 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
15582 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
15583 fn          Function         The function to call when KeyMap finds the expected key combination
15584 scope       Object           The scope of the callback function
15585 </pre>
15586      *
15587      * Usage:
15588      * <pre><code>
15589 // Create a KeyMap
15590 var map = new Roo.KeyMap(document, {
15591     key: Roo.EventObject.ENTER,
15592     fn: handleKey,
15593     scope: this
15594 });
15595
15596 //Add a new binding to the existing KeyMap later
15597 map.addBinding({
15598     key: 'abc',
15599     shift: true,
15600     fn: handleKey,
15601     scope: this
15602 });
15603 </code></pre>
15604      * @param {Object/Array} config A single KeyMap config or an array of configs
15605      */
15606         addBinding : function(config){
15607         if(config instanceof Array){
15608             for(var i = 0, len = config.length; i < len; i++){
15609                 this.addBinding(config[i]);
15610             }
15611             return;
15612         }
15613         var keyCode = config.key,
15614             shift = config.shift, 
15615             ctrl = config.ctrl, 
15616             alt = config.alt,
15617             fn = config.fn,
15618             scope = config.scope;
15619         if(typeof keyCode == "string"){
15620             var ks = [];
15621             var keyString = keyCode.toUpperCase();
15622             for(var j = 0, len = keyString.length; j < len; j++){
15623                 ks.push(keyString.charCodeAt(j));
15624             }
15625             keyCode = ks;
15626         }
15627         var keyArray = keyCode instanceof Array;
15628         var handler = function(e){
15629             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
15630                 var k = e.getKey();
15631                 if(keyArray){
15632                     for(var i = 0, len = keyCode.length; i < len; i++){
15633                         if(keyCode[i] == k){
15634                           if(this.stopEvent){
15635                               e.stopEvent();
15636                           }
15637                           fn.call(scope || window, k, e);
15638                           return;
15639                         }
15640                     }
15641                 }else{
15642                     if(k == keyCode){
15643                         if(this.stopEvent){
15644                            e.stopEvent();
15645                         }
15646                         fn.call(scope || window, k, e);
15647                     }
15648                 }
15649             }
15650         };
15651         this.bindings.push(handler);  
15652         },
15653
15654     /**
15655      * Shorthand for adding a single key listener
15656      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15657      * following options:
15658      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15659      * @param {Function} fn The function to call
15660      * @param {Object} scope (optional) The scope of the function
15661      */
15662     on : function(key, fn, scope){
15663         var keyCode, shift, ctrl, alt;
15664         if(typeof key == "object" && !(key instanceof Array)){
15665             keyCode = key.key;
15666             shift = key.shift;
15667             ctrl = key.ctrl;
15668             alt = key.alt;
15669         }else{
15670             keyCode = key;
15671         }
15672         this.addBinding({
15673             key: keyCode,
15674             shift: shift,
15675             ctrl: ctrl,
15676             alt: alt,
15677             fn: fn,
15678             scope: scope
15679         })
15680     },
15681
15682     // private
15683     handleKeyDown : function(e){
15684             if(this.enabled){ //just in case
15685             var b = this.bindings;
15686             for(var i = 0, len = b.length; i < len; i++){
15687                 b[i].call(this, e);
15688             }
15689             }
15690         },
15691         
15692         /**
15693          * Returns true if this KeyMap is enabled
15694          * @return {Boolean} 
15695          */
15696         isEnabled : function(){
15697             return this.enabled;  
15698         },
15699         
15700         /**
15701          * Enables this KeyMap
15702          */
15703         enable: function(){
15704                 if(!this.enabled){
15705                     this.el.on(this.eventName, this.handleKeyDown, this);
15706                     this.enabled = true;
15707                 }
15708         },
15709
15710         /**
15711          * Disable this KeyMap
15712          */
15713         disable: function(){
15714                 if(this.enabled){
15715                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
15716                     this.enabled = false;
15717                 }
15718         }
15719 };/*
15720  * Based on:
15721  * Ext JS Library 1.1.1
15722  * Copyright(c) 2006-2007, Ext JS, LLC.
15723  *
15724  * Originally Released Under LGPL - original licence link has changed is not relivant.
15725  *
15726  * Fork - LGPL
15727  * <script type="text/javascript">
15728  */
15729
15730  
15731 /**
15732  * @class Roo.util.TextMetrics
15733  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15734  * wide, in pixels, a given block of text will be.
15735  * @static
15736  */
15737 Roo.util.TextMetrics = function(){
15738     var shared;
15739     return {
15740         /**
15741          * Measures the size of the specified text
15742          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15743          * that can affect the size of the rendered text
15744          * @param {String} text The text to measure
15745          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15746          * in order to accurately measure the text height
15747          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15748          */
15749         measure : function(el, text, fixedWidth){
15750             if(!shared){
15751                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15752             }
15753             shared.bind(el);
15754             shared.setFixedWidth(fixedWidth || 'auto');
15755             return shared.getSize(text);
15756         },
15757
15758         /**
15759          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
15760          * the overhead of multiple calls to initialize the style properties on each measurement.
15761          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15762          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15763          * in order to accurately measure the text height
15764          * @return {Roo.util.TextMetrics.Instance} instance The new instance
15765          */
15766         createInstance : function(el, fixedWidth){
15767             return Roo.util.TextMetrics.Instance(el, fixedWidth);
15768         }
15769     };
15770 }();
15771
15772 /**
15773  * @class Roo.util.TextMetrics.Instance
15774  * Instance of  TextMetrics Calcuation
15775  * @constructor
15776  * Create a new TextMetrics Instance
15777  * @param {Object} bindto
15778  * @param {Boolean} fixedWidth
15779  */
15780
15781 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
15782 {
15783     var ml = new Roo.Element(document.createElement('div'));
15784     document.body.appendChild(ml.dom);
15785     ml.position('absolute');
15786     ml.setLeftTop(-1000, -1000);
15787     ml.hide();
15788
15789     if(fixedWidth){
15790         ml.setWidth(fixedWidth);
15791     }
15792      
15793     var instance = {
15794         /**
15795          * Returns the size of the specified text based on the internal element's style and width properties
15796          * @param {String} text The text to measure
15797          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15798          */
15799         getSize : function(text){
15800             ml.update(text);
15801             var s = ml.getSize();
15802             ml.update('');
15803             return s;
15804         },
15805
15806         /**
15807          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15808          * that can affect the size of the rendered text
15809          * @param {String/HTMLElement} el The element, dom node or id
15810          */
15811         bind : function(el){
15812             ml.setStyle(
15813                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15814             );
15815         },
15816
15817         /**
15818          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
15819          * to set a fixed width in order to accurately measure the text height.
15820          * @param {Number} width The width to set on the element
15821          */
15822         setFixedWidth : function(width){
15823             ml.setWidth(width);
15824         },
15825
15826         /**
15827          * Returns the measured width of the specified text
15828          * @param {String} text The text to measure
15829          * @return {Number} width The width in pixels
15830          */
15831         getWidth : function(text){
15832             ml.dom.style.width = 'auto';
15833             return this.getSize(text).width;
15834         },
15835
15836         /**
15837          * Returns the measured height of the specified text.  For multiline text, be sure to call
15838          * {@link #setFixedWidth} if necessary.
15839          * @param {String} text The text to measure
15840          * @return {Number} height The height in pixels
15841          */
15842         getHeight : function(text){
15843             return this.getSize(text).height;
15844         }
15845     };
15846
15847     instance.bind(bindTo);
15848
15849     return instance;
15850 };
15851
15852 // backwards compat
15853 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15854  * Based on:
15855  * Ext JS Library 1.1.1
15856  * Copyright(c) 2006-2007, Ext JS, LLC.
15857  *
15858  * Originally Released Under LGPL - original licence link has changed is not relivant.
15859  *
15860  * Fork - LGPL
15861  * <script type="text/javascript">
15862  */
15863
15864 /**
15865  * @class Roo.state.Provider
15866  * Abstract base class for state provider implementations. This class provides methods
15867  * for encoding and decoding <b>typed</b> variables including dates and defines the 
15868  * Provider interface.
15869  */
15870 Roo.state.Provider = function(){
15871     /**
15872      * @event statechange
15873      * Fires when a state change occurs.
15874      * @param {Provider} this This state provider
15875      * @param {String} key The state key which was changed
15876      * @param {String} value The encoded value for the state
15877      */
15878     this.addEvents({
15879         "statechange": true
15880     });
15881     this.state = {};
15882     Roo.state.Provider.superclass.constructor.call(this);
15883 };
15884 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15885     /**
15886      * Returns the current value for a key
15887      * @param {String} name The key name
15888      * @param {Mixed} defaultValue A default value to return if the key's value is not found
15889      * @return {Mixed} The state data
15890      */
15891     get : function(name, defaultValue){
15892         return typeof this.state[name] == "undefined" ?
15893             defaultValue : this.state[name];
15894     },
15895     
15896     /**
15897      * Clears a value from the state
15898      * @param {String} name The key name
15899      */
15900     clear : function(name){
15901         delete this.state[name];
15902         this.fireEvent("statechange", this, name, null);
15903     },
15904     
15905     /**
15906      * Sets the value for a key
15907      * @param {String} name The key name
15908      * @param {Mixed} value The value to set
15909      */
15910     set : function(name, value){
15911         this.state[name] = value;
15912         this.fireEvent("statechange", this, name, value);
15913     },
15914     
15915     /**
15916      * Decodes a string previously encoded with {@link #encodeValue}.
15917      * @param {String} value The value to decode
15918      * @return {Mixed} The decoded value
15919      */
15920     decodeValue : function(cookie){
15921         var re = /^(a|n|d|b|s|o)\:(.*)$/;
15922         var matches = re.exec(unescape(cookie));
15923         if(!matches || !matches[1]) {
15924             return; // non state cookie
15925         }
15926         var type = matches[1];
15927         var v = matches[2];
15928         switch(type){
15929             case "n":
15930                 return parseFloat(v);
15931             case "d":
15932                 return new Date(Date.parse(v));
15933             case "b":
15934                 return (v == "1");
15935             case "a":
15936                 var all = [];
15937                 var values = v.split("^");
15938                 for(var i = 0, len = values.length; i < len; i++){
15939                     all.push(this.decodeValue(values[i]));
15940                 }
15941                 return all;
15942            case "o":
15943                 var all = {};
15944                 var values = v.split("^");
15945                 for(var i = 0, len = values.length; i < len; i++){
15946                     var kv = values[i].split("=");
15947                     all[kv[0]] = this.decodeValue(kv[1]);
15948                 }
15949                 return all;
15950            default:
15951                 return v;
15952         }
15953     },
15954     
15955     /**
15956      * Encodes a value including type information.  Decode with {@link #decodeValue}.
15957      * @param {Mixed} value The value to encode
15958      * @return {String} The encoded value
15959      */
15960     encodeValue : function(v){
15961         var enc;
15962         if(typeof v == "number"){
15963             enc = "n:" + v;
15964         }else if(typeof v == "boolean"){
15965             enc = "b:" + (v ? "1" : "0");
15966         }else if(v instanceof Date){
15967             enc = "d:" + v.toGMTString();
15968         }else if(v instanceof Array){
15969             var flat = "";
15970             for(var i = 0, len = v.length; i < len; i++){
15971                 flat += this.encodeValue(v[i]);
15972                 if(i != len-1) {
15973                     flat += "^";
15974                 }
15975             }
15976             enc = "a:" + flat;
15977         }else if(typeof v == "object"){
15978             var flat = "";
15979             for(var key in v){
15980                 if(typeof v[key] != "function"){
15981                     flat += key + "=" + this.encodeValue(v[key]) + "^";
15982                 }
15983             }
15984             enc = "o:" + flat.substring(0, flat.length-1);
15985         }else{
15986             enc = "s:" + v;
15987         }
15988         return escape(enc);        
15989     }
15990 });
15991
15992 /*
15993  * Based on:
15994  * Ext JS Library 1.1.1
15995  * Copyright(c) 2006-2007, Ext JS, LLC.
15996  *
15997  * Originally Released Under LGPL - original licence link has changed is not relivant.
15998  *
15999  * Fork - LGPL
16000  * <script type="text/javascript">
16001  */
16002 /**
16003  * @class Roo.state.Manager
16004  * This is the global state manager. By default all components that are "state aware" check this class
16005  * for state information if you don't pass them a custom state provider. In order for this class
16006  * to be useful, it must be initialized with a provider when your application initializes.
16007  <pre><code>
16008 // in your initialization function
16009 init : function(){
16010    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16011    ...
16012    // supposed you have a {@link Roo.BorderLayout}
16013    var layout = new Roo.BorderLayout(...);
16014    layout.restoreState();
16015    // or a {Roo.BasicDialog}
16016    var dialog = new Roo.BasicDialog(...);
16017    dialog.restoreState();
16018  </code></pre>
16019  * @static
16020  */
16021 Roo.state.Manager = function(){
16022     var provider = new Roo.state.Provider();
16023     
16024     return {
16025         /**
16026          * Configures the default state provider for your application
16027          * @param {Provider} stateProvider The state provider to set
16028          */
16029         setProvider : function(stateProvider){
16030             provider = stateProvider;
16031         },
16032         
16033         /**
16034          * Returns the current value for a key
16035          * @param {String} name The key name
16036          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16037          * @return {Mixed} The state data
16038          */
16039         get : function(key, defaultValue){
16040             return provider.get(key, defaultValue);
16041         },
16042         
16043         /**
16044          * Sets the value for a key
16045          * @param {String} name The key name
16046          * @param {Mixed} value The state data
16047          */
16048          set : function(key, value){
16049             provider.set(key, value);
16050         },
16051         
16052         /**
16053          * Clears a value from the state
16054          * @param {String} name The key name
16055          */
16056         clear : function(key){
16057             provider.clear(key);
16058         },
16059         
16060         /**
16061          * Gets the currently configured state provider
16062          * @return {Provider} The state provider
16063          */
16064         getProvider : function(){
16065             return provider;
16066         }
16067     };
16068 }();
16069 /*
16070  * Based on:
16071  * Ext JS Library 1.1.1
16072  * Copyright(c) 2006-2007, Ext JS, LLC.
16073  *
16074  * Originally Released Under LGPL - original licence link has changed is not relivant.
16075  *
16076  * Fork - LGPL
16077  * <script type="text/javascript">
16078  */
16079 /**
16080  * @class Roo.state.CookieProvider
16081  * @extends Roo.state.Provider
16082  * The default Provider implementation which saves state via cookies.
16083  * <br />Usage:
16084  <pre><code>
16085    var cp = new Roo.state.CookieProvider({
16086        path: "/cgi-bin/",
16087        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16088        domain: "roojs.com"
16089    })
16090    Roo.state.Manager.setProvider(cp);
16091  </code></pre>
16092  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16093  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16094  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16095  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16096  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16097  * domain the page is running on including the 'www' like 'www.roojs.com')
16098  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16099  * @constructor
16100  * Create a new CookieProvider
16101  * @param {Object} config The configuration object
16102  */
16103 Roo.state.CookieProvider = function(config){
16104     Roo.state.CookieProvider.superclass.constructor.call(this);
16105     this.path = "/";
16106     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16107     this.domain = null;
16108     this.secure = false;
16109     Roo.apply(this, config);
16110     this.state = this.readCookies();
16111 };
16112
16113 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16114     // private
16115     set : function(name, value){
16116         if(typeof value == "undefined" || value === null){
16117             this.clear(name);
16118             return;
16119         }
16120         this.setCookie(name, value);
16121         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16122     },
16123
16124     // private
16125     clear : function(name){
16126         this.clearCookie(name);
16127         Roo.state.CookieProvider.superclass.clear.call(this, name);
16128     },
16129
16130     // private
16131     readCookies : function(){
16132         var cookies = {};
16133         var c = document.cookie + ";";
16134         var re = /\s?(.*?)=(.*?);/g;
16135         var matches;
16136         while((matches = re.exec(c)) != null){
16137             var name = matches[1];
16138             var value = matches[2];
16139             if(name && name.substring(0,3) == "ys-"){
16140                 cookies[name.substr(3)] = this.decodeValue(value);
16141             }
16142         }
16143         return cookies;
16144     },
16145
16146     // private
16147     setCookie : function(name, value){
16148         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16149            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16150            ((this.path == null) ? "" : ("; path=" + this.path)) +
16151            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16152            ((this.secure == true) ? "; secure" : "");
16153     },
16154
16155     // private
16156     clearCookie : function(name){
16157         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16158            ((this.path == null) ? "" : ("; path=" + this.path)) +
16159            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16160            ((this.secure == true) ? "; secure" : "");
16161     }
16162 });/*
16163  * Based on:
16164  * Ext JS Library 1.1.1
16165  * Copyright(c) 2006-2007, Ext JS, LLC.
16166  *
16167  * Originally Released Under LGPL - original licence link has changed is not relivant.
16168  *
16169  * Fork - LGPL
16170  * <script type="text/javascript">
16171  */
16172  
16173
16174 /**
16175  * @class Roo.ComponentMgr
16176  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16177  * @static
16178  */
16179 Roo.ComponentMgr = function(){
16180     var all = new Roo.util.MixedCollection();
16181
16182     return {
16183         /**
16184          * Registers a component.
16185          * @param {Roo.Component} c The component
16186          */
16187         register : function(c){
16188             all.add(c);
16189         },
16190
16191         /**
16192          * Unregisters a component.
16193          * @param {Roo.Component} c The component
16194          */
16195         unregister : function(c){
16196             all.remove(c);
16197         },
16198
16199         /**
16200          * Returns a component by id
16201          * @param {String} id The component id
16202          */
16203         get : function(id){
16204             return all.get(id);
16205         },
16206
16207         /**
16208          * Registers a function that will be called when a specified component is added to ComponentMgr
16209          * @param {String} id The component id
16210          * @param {Funtction} fn The callback function
16211          * @param {Object} scope The scope of the callback
16212          */
16213         onAvailable : function(id, fn, scope){
16214             all.on("add", function(index, o){
16215                 if(o.id == id){
16216                     fn.call(scope || o, o);
16217                     all.un("add", fn, scope);
16218                 }
16219             });
16220         }
16221     };
16222 }();/*
16223  * Based on:
16224  * Ext JS Library 1.1.1
16225  * Copyright(c) 2006-2007, Ext JS, LLC.
16226  *
16227  * Originally Released Under LGPL - original licence link has changed is not relivant.
16228  *
16229  * Fork - LGPL
16230  * <script type="text/javascript">
16231  */
16232  
16233 /**
16234  * @class Roo.Component
16235  * @extends Roo.util.Observable
16236  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16237  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16238  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16239  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16240  * All visual components (widgets) that require rendering into a layout should subclass Component.
16241  * @constructor
16242  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16243  * 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
16244  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16245  */
16246 Roo.Component = function(config){
16247     config = config || {};
16248     if(config.tagName || config.dom || typeof config == "string"){ // element object
16249         config = {el: config, id: config.id || config};
16250     }
16251     this.initialConfig = config;
16252
16253     Roo.apply(this, config);
16254     this.addEvents({
16255         /**
16256          * @event disable
16257          * Fires after the component is disabled.
16258              * @param {Roo.Component} this
16259              */
16260         disable : true,
16261         /**
16262          * @event enable
16263          * Fires after the component is enabled.
16264              * @param {Roo.Component} this
16265              */
16266         enable : true,
16267         /**
16268          * @event beforeshow
16269          * Fires before the component is shown.  Return false to stop the show.
16270              * @param {Roo.Component} this
16271              */
16272         beforeshow : true,
16273         /**
16274          * @event show
16275          * Fires after the component is shown.
16276              * @param {Roo.Component} this
16277              */
16278         show : true,
16279         /**
16280          * @event beforehide
16281          * Fires before the component is hidden. Return false to stop the hide.
16282              * @param {Roo.Component} this
16283              */
16284         beforehide : true,
16285         /**
16286          * @event hide
16287          * Fires after the component is hidden.
16288              * @param {Roo.Component} this
16289              */
16290         hide : true,
16291         /**
16292          * @event beforerender
16293          * Fires before the component is rendered. Return false to stop the render.
16294              * @param {Roo.Component} this
16295              */
16296         beforerender : true,
16297         /**
16298          * @event render
16299          * Fires after the component is rendered.
16300              * @param {Roo.Component} this
16301              */
16302         render : true,
16303         /**
16304          * @event beforedestroy
16305          * Fires before the component is destroyed. Return false to stop the destroy.
16306              * @param {Roo.Component} this
16307              */
16308         beforedestroy : true,
16309         /**
16310          * @event destroy
16311          * Fires after the component is destroyed.
16312              * @param {Roo.Component} this
16313              */
16314         destroy : true
16315     });
16316     if(!this.id){
16317         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16318     }
16319     Roo.ComponentMgr.register(this);
16320     Roo.Component.superclass.constructor.call(this);
16321     this.initComponent();
16322     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16323         this.render(this.renderTo);
16324         delete this.renderTo;
16325     }
16326 };
16327
16328 /** @private */
16329 Roo.Component.AUTO_ID = 1000;
16330
16331 Roo.extend(Roo.Component, Roo.util.Observable, {
16332     /**
16333      * @scope Roo.Component.prototype
16334      * @type {Boolean}
16335      * true if this component is hidden. Read-only.
16336      */
16337     hidden : false,
16338     /**
16339      * @type {Boolean}
16340      * true if this component is disabled. Read-only.
16341      */
16342     disabled : false,
16343     /**
16344      * @type {Boolean}
16345      * true if this component has been rendered. Read-only.
16346      */
16347     rendered : false,
16348     
16349     /** @cfg {String} disableClass
16350      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16351      */
16352     disabledClass : "x-item-disabled",
16353         /** @cfg {Boolean} allowDomMove
16354          * Whether the component can move the Dom node when rendering (defaults to true).
16355          */
16356     allowDomMove : true,
16357     /** @cfg {String} hideMode (display|visibility)
16358      * How this component should hidden. Supported values are
16359      * "visibility" (css visibility), "offsets" (negative offset position) and
16360      * "display" (css display) - defaults to "display".
16361      */
16362     hideMode: 'display',
16363
16364     /** @private */
16365     ctype : "Roo.Component",
16366
16367     /**
16368      * @cfg {String} actionMode 
16369      * which property holds the element that used for  hide() / show() / disable() / enable()
16370      * default is 'el' for forms you probably want to set this to fieldEl 
16371      */
16372     actionMode : "el",
16373
16374     /** @private */
16375     getActionEl : function(){
16376         return this[this.actionMode];
16377     },
16378
16379     initComponent : Roo.emptyFn,
16380     /**
16381      * If this is a lazy rendering component, render it to its container element.
16382      * @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.
16383      */
16384     render : function(container, position){
16385         
16386         if(this.rendered){
16387             return this;
16388         }
16389         
16390         if(this.fireEvent("beforerender", this) === false){
16391             return false;
16392         }
16393         
16394         if(!container && this.el){
16395             this.el = Roo.get(this.el);
16396             container = this.el.dom.parentNode;
16397             this.allowDomMove = false;
16398         }
16399         this.container = Roo.get(container);
16400         this.rendered = true;
16401         if(position !== undefined){
16402             if(typeof position == 'number'){
16403                 position = this.container.dom.childNodes[position];
16404             }else{
16405                 position = Roo.getDom(position);
16406             }
16407         }
16408         this.onRender(this.container, position || null);
16409         if(this.cls){
16410             this.el.addClass(this.cls);
16411             delete this.cls;
16412         }
16413         if(this.style){
16414             this.el.applyStyles(this.style);
16415             delete this.style;
16416         }
16417         this.fireEvent("render", this);
16418         this.afterRender(this.container);
16419         if(this.hidden){
16420             this.hide();
16421         }
16422         if(this.disabled){
16423             this.disable();
16424         }
16425
16426         return this;
16427         
16428     },
16429
16430     /** @private */
16431     // default function is not really useful
16432     onRender : function(ct, position){
16433         if(this.el){
16434             this.el = Roo.get(this.el);
16435             if(this.allowDomMove !== false){
16436                 ct.dom.insertBefore(this.el.dom, position);
16437             }
16438         }
16439     },
16440
16441     /** @private */
16442     getAutoCreate : function(){
16443         var cfg = typeof this.autoCreate == "object" ?
16444                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16445         if(this.id && !cfg.id){
16446             cfg.id = this.id;
16447         }
16448         return cfg;
16449     },
16450
16451     /** @private */
16452     afterRender : Roo.emptyFn,
16453
16454     /**
16455      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16456      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16457      */
16458     destroy : function(){
16459         if(this.fireEvent("beforedestroy", this) !== false){
16460             this.purgeListeners();
16461             this.beforeDestroy();
16462             if(this.rendered){
16463                 this.el.removeAllListeners();
16464                 this.el.remove();
16465                 if(this.actionMode == "container"){
16466                     this.container.remove();
16467                 }
16468             }
16469             this.onDestroy();
16470             Roo.ComponentMgr.unregister(this);
16471             this.fireEvent("destroy", this);
16472         }
16473     },
16474
16475         /** @private */
16476     beforeDestroy : function(){
16477
16478     },
16479
16480         /** @private */
16481         onDestroy : function(){
16482
16483     },
16484
16485     /**
16486      * Returns the underlying {@link Roo.Element}.
16487      * @return {Roo.Element} The element
16488      */
16489     getEl : function(){
16490         return this.el;
16491     },
16492
16493     /**
16494      * Returns the id of this component.
16495      * @return {String}
16496      */
16497     getId : function(){
16498         return this.id;
16499     },
16500
16501     /**
16502      * Try to focus this component.
16503      * @param {Boolean} selectText True to also select the text in this component (if applicable)
16504      * @return {Roo.Component} this
16505      */
16506     focus : function(selectText){
16507         if(this.rendered){
16508             this.el.focus();
16509             if(selectText === true){
16510                 this.el.dom.select();
16511             }
16512         }
16513         return this;
16514     },
16515
16516     /** @private */
16517     blur : function(){
16518         if(this.rendered){
16519             this.el.blur();
16520         }
16521         return this;
16522     },
16523
16524     /**
16525      * Disable this component.
16526      * @return {Roo.Component} this
16527      */
16528     disable : function(){
16529         if(this.rendered){
16530             this.onDisable();
16531         }
16532         this.disabled = true;
16533         this.fireEvent("disable", this);
16534         return this;
16535     },
16536
16537         // private
16538     onDisable : function(){
16539         this.getActionEl().addClass(this.disabledClass);
16540         this.el.dom.disabled = true;
16541     },
16542
16543     /**
16544      * Enable this component.
16545      * @return {Roo.Component} this
16546      */
16547     enable : function(){
16548         if(this.rendered){
16549             this.onEnable();
16550         }
16551         this.disabled = false;
16552         this.fireEvent("enable", this);
16553         return this;
16554     },
16555
16556         // private
16557     onEnable : function(){
16558         this.getActionEl().removeClass(this.disabledClass);
16559         this.el.dom.disabled = false;
16560     },
16561
16562     /**
16563      * Convenience function for setting disabled/enabled by boolean.
16564      * @param {Boolean} disabled
16565      */
16566     setDisabled : function(disabled){
16567         this[disabled ? "disable" : "enable"]();
16568     },
16569
16570     /**
16571      * Show this component.
16572      * @return {Roo.Component} this
16573      */
16574     show: function(){
16575         if(this.fireEvent("beforeshow", this) !== false){
16576             this.hidden = false;
16577             if(this.rendered){
16578                 this.onShow();
16579             }
16580             this.fireEvent("show", this);
16581         }
16582         return this;
16583     },
16584
16585     // private
16586     onShow : function(){
16587         var ae = this.getActionEl();
16588         if(this.hideMode == 'visibility'){
16589             ae.dom.style.visibility = "visible";
16590         }else if(this.hideMode == 'offsets'){
16591             ae.removeClass('x-hidden');
16592         }else{
16593             ae.dom.style.display = "";
16594         }
16595     },
16596
16597     /**
16598      * Hide this component.
16599      * @return {Roo.Component} this
16600      */
16601     hide: function(){
16602         if(this.fireEvent("beforehide", this) !== false){
16603             this.hidden = true;
16604             if(this.rendered){
16605                 this.onHide();
16606             }
16607             this.fireEvent("hide", this);
16608         }
16609         return this;
16610     },
16611
16612     // private
16613     onHide : function(){
16614         var ae = this.getActionEl();
16615         if(this.hideMode == 'visibility'){
16616             ae.dom.style.visibility = "hidden";
16617         }else if(this.hideMode == 'offsets'){
16618             ae.addClass('x-hidden');
16619         }else{
16620             ae.dom.style.display = "none";
16621         }
16622     },
16623
16624     /**
16625      * Convenience function to hide or show this component by boolean.
16626      * @param {Boolean} visible True to show, false to hide
16627      * @return {Roo.Component} this
16628      */
16629     setVisible: function(visible){
16630         if(visible) {
16631             this.show();
16632         }else{
16633             this.hide();
16634         }
16635         return this;
16636     },
16637
16638     /**
16639      * Returns true if this component is visible.
16640      */
16641     isVisible : function(){
16642         return this.getActionEl().isVisible();
16643     },
16644
16645     cloneConfig : function(overrides){
16646         overrides = overrides || {};
16647         var id = overrides.id || Roo.id();
16648         var cfg = Roo.applyIf(overrides, this.initialConfig);
16649         cfg.id = id; // prevent dup id
16650         return new this.constructor(cfg);
16651     }
16652 });/*
16653  * Based on:
16654  * Ext JS Library 1.1.1
16655  * Copyright(c) 2006-2007, Ext JS, LLC.
16656  *
16657  * Originally Released Under LGPL - original licence link has changed is not relivant.
16658  *
16659  * Fork - LGPL
16660  * <script type="text/javascript">
16661  */
16662
16663 /**
16664  * @class Roo.BoxComponent
16665  * @extends Roo.Component
16666  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
16667  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
16668  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16669  * layout containers.
16670  * @constructor
16671  * @param {Roo.Element/String/Object} config The configuration options.
16672  */
16673 Roo.BoxComponent = function(config){
16674     Roo.Component.call(this, config);
16675     this.addEvents({
16676         /**
16677          * @event resize
16678          * Fires after the component is resized.
16679              * @param {Roo.Component} this
16680              * @param {Number} adjWidth The box-adjusted width that was set
16681              * @param {Number} adjHeight The box-adjusted height that was set
16682              * @param {Number} rawWidth The width that was originally specified
16683              * @param {Number} rawHeight The height that was originally specified
16684              */
16685         resize : true,
16686         /**
16687          * @event move
16688          * Fires after the component is moved.
16689              * @param {Roo.Component} this
16690              * @param {Number} x The new x position
16691              * @param {Number} y The new y position
16692              */
16693         move : true
16694     });
16695 };
16696
16697 Roo.extend(Roo.BoxComponent, Roo.Component, {
16698     // private, set in afterRender to signify that the component has been rendered
16699     boxReady : false,
16700     // private, used to defer height settings to subclasses
16701     deferHeight: false,
16702     /** @cfg {Number} width
16703      * width (optional) size of component
16704      */
16705      /** @cfg {Number} height
16706      * height (optional) size of component
16707      */
16708      
16709     /**
16710      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
16711      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16712      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16713      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16714      * @return {Roo.BoxComponent} this
16715      */
16716     setSize : function(w, h){
16717         // support for standard size objects
16718         if(typeof w == 'object'){
16719             h = w.height;
16720             w = w.width;
16721         }
16722         // not rendered
16723         if(!this.boxReady){
16724             this.width = w;
16725             this.height = h;
16726             return this;
16727         }
16728
16729         // prevent recalcs when not needed
16730         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16731             return this;
16732         }
16733         this.lastSize = {width: w, height: h};
16734
16735         var adj = this.adjustSize(w, h);
16736         var aw = adj.width, ah = adj.height;
16737         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16738             var rz = this.getResizeEl();
16739             if(!this.deferHeight && aw !== undefined && ah !== undefined){
16740                 rz.setSize(aw, ah);
16741             }else if(!this.deferHeight && ah !== undefined){
16742                 rz.setHeight(ah);
16743             }else if(aw !== undefined){
16744                 rz.setWidth(aw);
16745             }
16746             this.onResize(aw, ah, w, h);
16747             this.fireEvent('resize', this, aw, ah, w, h);
16748         }
16749         return this;
16750     },
16751
16752     /**
16753      * Gets the current size of the component's underlying element.
16754      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16755      */
16756     getSize : function(){
16757         return this.el.getSize();
16758     },
16759
16760     /**
16761      * Gets the current XY position of the component's underlying element.
16762      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16763      * @return {Array} The XY position of the element (e.g., [100, 200])
16764      */
16765     getPosition : function(local){
16766         if(local === true){
16767             return [this.el.getLeft(true), this.el.getTop(true)];
16768         }
16769         return this.xy || this.el.getXY();
16770     },
16771
16772     /**
16773      * Gets the current box measurements of the component's underlying element.
16774      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16775      * @returns {Object} box An object in the format {x, y, width, height}
16776      */
16777     getBox : function(local){
16778         var s = this.el.getSize();
16779         if(local){
16780             s.x = this.el.getLeft(true);
16781             s.y = this.el.getTop(true);
16782         }else{
16783             var xy = this.xy || this.el.getXY();
16784             s.x = xy[0];
16785             s.y = xy[1];
16786         }
16787         return s;
16788     },
16789
16790     /**
16791      * Sets the current box measurements of the component's underlying element.
16792      * @param {Object} box An object in the format {x, y, width, height}
16793      * @returns {Roo.BoxComponent} this
16794      */
16795     updateBox : function(box){
16796         this.setSize(box.width, box.height);
16797         this.setPagePosition(box.x, box.y);
16798         return this;
16799     },
16800
16801     // protected
16802     getResizeEl : function(){
16803         return this.resizeEl || this.el;
16804     },
16805
16806     // protected
16807     getPositionEl : function(){
16808         return this.positionEl || this.el;
16809     },
16810
16811     /**
16812      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
16813      * This method fires the move event.
16814      * @param {Number} left The new left
16815      * @param {Number} top The new top
16816      * @returns {Roo.BoxComponent} this
16817      */
16818     setPosition : function(x, y){
16819         this.x = x;
16820         this.y = y;
16821         if(!this.boxReady){
16822             return this;
16823         }
16824         var adj = this.adjustPosition(x, y);
16825         var ax = adj.x, ay = adj.y;
16826
16827         var el = this.getPositionEl();
16828         if(ax !== undefined || ay !== undefined){
16829             if(ax !== undefined && ay !== undefined){
16830                 el.setLeftTop(ax, ay);
16831             }else if(ax !== undefined){
16832                 el.setLeft(ax);
16833             }else if(ay !== undefined){
16834                 el.setTop(ay);
16835             }
16836             this.onPosition(ax, ay);
16837             this.fireEvent('move', this, ax, ay);
16838         }
16839         return this;
16840     },
16841
16842     /**
16843      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
16844      * This method fires the move event.
16845      * @param {Number} x The new x position
16846      * @param {Number} y The new y position
16847      * @returns {Roo.BoxComponent} this
16848      */
16849     setPagePosition : function(x, y){
16850         this.pageX = x;
16851         this.pageY = y;
16852         if(!this.boxReady){
16853             return;
16854         }
16855         if(x === undefined || y === undefined){ // cannot translate undefined points
16856             return;
16857         }
16858         var p = this.el.translatePoints(x, y);
16859         this.setPosition(p.left, p.top);
16860         return this;
16861     },
16862
16863     // private
16864     onRender : function(ct, position){
16865         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16866         if(this.resizeEl){
16867             this.resizeEl = Roo.get(this.resizeEl);
16868         }
16869         if(this.positionEl){
16870             this.positionEl = Roo.get(this.positionEl);
16871         }
16872     },
16873
16874     // private
16875     afterRender : function(){
16876         Roo.BoxComponent.superclass.afterRender.call(this);
16877         this.boxReady = true;
16878         this.setSize(this.width, this.height);
16879         if(this.x || this.y){
16880             this.setPosition(this.x, this.y);
16881         }
16882         if(this.pageX || this.pageY){
16883             this.setPagePosition(this.pageX, this.pageY);
16884         }
16885     },
16886
16887     /**
16888      * Force the component's size to recalculate based on the underlying element's current height and width.
16889      * @returns {Roo.BoxComponent} this
16890      */
16891     syncSize : function(){
16892         delete this.lastSize;
16893         this.setSize(this.el.getWidth(), this.el.getHeight());
16894         return this;
16895     },
16896
16897     /**
16898      * Called after the component is resized, this method is empty by default but can be implemented by any
16899      * subclass that needs to perform custom logic after a resize occurs.
16900      * @param {Number} adjWidth The box-adjusted width that was set
16901      * @param {Number} adjHeight The box-adjusted height that was set
16902      * @param {Number} rawWidth The width that was originally specified
16903      * @param {Number} rawHeight The height that was originally specified
16904      */
16905     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16906
16907     },
16908
16909     /**
16910      * Called after the component is moved, this method is empty by default but can be implemented by any
16911      * subclass that needs to perform custom logic after a move occurs.
16912      * @param {Number} x The new x position
16913      * @param {Number} y The new y position
16914      */
16915     onPosition : function(x, y){
16916
16917     },
16918
16919     // private
16920     adjustSize : function(w, h){
16921         if(this.autoWidth){
16922             w = 'auto';
16923         }
16924         if(this.autoHeight){
16925             h = 'auto';
16926         }
16927         return {width : w, height: h};
16928     },
16929
16930     // private
16931     adjustPosition : function(x, y){
16932         return {x : x, y: y};
16933     }
16934 });/*
16935  * Based on:
16936  * Ext JS Library 1.1.1
16937  * Copyright(c) 2006-2007, Ext JS, LLC.
16938  *
16939  * Originally Released Under LGPL - original licence link has changed is not relivant.
16940  *
16941  * Fork - LGPL
16942  * <script type="text/javascript">
16943  */
16944  (function(){ 
16945 /**
16946  * @class Roo.Layer
16947  * @extends Roo.Element
16948  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16949  * automatic maintaining of shadow/shim positions.
16950  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16951  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16952  * you can pass a string with a CSS class name. False turns off the shadow.
16953  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16954  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16955  * @cfg {String} cls CSS class to add to the element
16956  * @cfg {Number} zindex Starting z-index (defaults to 11000)
16957  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16958  * @constructor
16959  * @param {Object} config An object with config options.
16960  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16961  */
16962
16963 Roo.Layer = function(config, existingEl){
16964     config = config || {};
16965     var dh = Roo.DomHelper;
16966     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16967     if(existingEl){
16968         this.dom = Roo.getDom(existingEl);
16969     }
16970     if(!this.dom){
16971         var o = config.dh || {tag: "div", cls: "x-layer"};
16972         this.dom = dh.append(pel, o);
16973     }
16974     if(config.cls){
16975         this.addClass(config.cls);
16976     }
16977     this.constrain = config.constrain !== false;
16978     this.visibilityMode = Roo.Element.VISIBILITY;
16979     if(config.id){
16980         this.id = this.dom.id = config.id;
16981     }else{
16982         this.id = Roo.id(this.dom);
16983     }
16984     this.zindex = config.zindex || this.getZIndex();
16985     this.position("absolute", this.zindex);
16986     if(config.shadow){
16987         this.shadowOffset = config.shadowOffset || 4;
16988         this.shadow = new Roo.Shadow({
16989             offset : this.shadowOffset,
16990             mode : config.shadow
16991         });
16992     }else{
16993         this.shadowOffset = 0;
16994     }
16995     this.useShim = config.shim !== false && Roo.useShims;
16996     this.useDisplay = config.useDisplay;
16997     this.hide();
16998 };
16999
17000 var supr = Roo.Element.prototype;
17001
17002 // shims are shared among layer to keep from having 100 iframes
17003 var shims = [];
17004
17005 Roo.extend(Roo.Layer, Roo.Element, {
17006
17007     getZIndex : function(){
17008         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17009     },
17010
17011     getShim : function(){
17012         if(!this.useShim){
17013             return null;
17014         }
17015         if(this.shim){
17016             return this.shim;
17017         }
17018         var shim = shims.shift();
17019         if(!shim){
17020             shim = this.createShim();
17021             shim.enableDisplayMode('block');
17022             shim.dom.style.display = 'none';
17023             shim.dom.style.visibility = 'visible';
17024         }
17025         var pn = this.dom.parentNode;
17026         if(shim.dom.parentNode != pn){
17027             pn.insertBefore(shim.dom, this.dom);
17028         }
17029         shim.setStyle('z-index', this.getZIndex()-2);
17030         this.shim = shim;
17031         return shim;
17032     },
17033
17034     hideShim : function(){
17035         if(this.shim){
17036             this.shim.setDisplayed(false);
17037             shims.push(this.shim);
17038             delete this.shim;
17039         }
17040     },
17041
17042     disableShadow : function(){
17043         if(this.shadow){
17044             this.shadowDisabled = true;
17045             this.shadow.hide();
17046             this.lastShadowOffset = this.shadowOffset;
17047             this.shadowOffset = 0;
17048         }
17049     },
17050
17051     enableShadow : function(show){
17052         if(this.shadow){
17053             this.shadowDisabled = false;
17054             this.shadowOffset = this.lastShadowOffset;
17055             delete this.lastShadowOffset;
17056             if(show){
17057                 this.sync(true);
17058             }
17059         }
17060     },
17061
17062     // private
17063     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17064     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17065     sync : function(doShow){
17066         var sw = this.shadow;
17067         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17068             var sh = this.getShim();
17069
17070             var w = this.getWidth(),
17071                 h = this.getHeight();
17072
17073             var l = this.getLeft(true),
17074                 t = this.getTop(true);
17075
17076             if(sw && !this.shadowDisabled){
17077                 if(doShow && !sw.isVisible()){
17078                     sw.show(this);
17079                 }else{
17080                     sw.realign(l, t, w, h);
17081                 }
17082                 if(sh){
17083                     if(doShow){
17084                        sh.show();
17085                     }
17086                     // fit the shim behind the shadow, so it is shimmed too
17087                     var a = sw.adjusts, s = sh.dom.style;
17088                     s.left = (Math.min(l, l+a.l))+"px";
17089                     s.top = (Math.min(t, t+a.t))+"px";
17090                     s.width = (w+a.w)+"px";
17091                     s.height = (h+a.h)+"px";
17092                 }
17093             }else if(sh){
17094                 if(doShow){
17095                    sh.show();
17096                 }
17097                 sh.setSize(w, h);
17098                 sh.setLeftTop(l, t);
17099             }
17100             
17101         }
17102     },
17103
17104     // private
17105     destroy : function(){
17106         this.hideShim();
17107         if(this.shadow){
17108             this.shadow.hide();
17109         }
17110         this.removeAllListeners();
17111         var pn = this.dom.parentNode;
17112         if(pn){
17113             pn.removeChild(this.dom);
17114         }
17115         Roo.Element.uncache(this.id);
17116     },
17117
17118     remove : function(){
17119         this.destroy();
17120     },
17121
17122     // private
17123     beginUpdate : function(){
17124         this.updating = true;
17125     },
17126
17127     // private
17128     endUpdate : function(){
17129         this.updating = false;
17130         this.sync(true);
17131     },
17132
17133     // private
17134     hideUnders : function(negOffset){
17135         if(this.shadow){
17136             this.shadow.hide();
17137         }
17138         this.hideShim();
17139     },
17140
17141     // private
17142     constrainXY : function(){
17143         if(this.constrain){
17144             var vw = Roo.lib.Dom.getViewWidth(),
17145                 vh = Roo.lib.Dom.getViewHeight();
17146             var s = Roo.get(document).getScroll();
17147
17148             var xy = this.getXY();
17149             var x = xy[0], y = xy[1];   
17150             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17151             // only move it if it needs it
17152             var moved = false;
17153             // first validate right/bottom
17154             if((x + w) > vw+s.left){
17155                 x = vw - w - this.shadowOffset;
17156                 moved = true;
17157             }
17158             if((y + h) > vh+s.top){
17159                 y = vh - h - this.shadowOffset;
17160                 moved = true;
17161             }
17162             // then make sure top/left isn't negative
17163             if(x < s.left){
17164                 x = s.left;
17165                 moved = true;
17166             }
17167             if(y < s.top){
17168                 y = s.top;
17169                 moved = true;
17170             }
17171             if(moved){
17172                 if(this.avoidY){
17173                     var ay = this.avoidY;
17174                     if(y <= ay && (y+h) >= ay){
17175                         y = ay-h-5;   
17176                     }
17177                 }
17178                 xy = [x, y];
17179                 this.storeXY(xy);
17180                 supr.setXY.call(this, xy);
17181                 this.sync();
17182             }
17183         }
17184     },
17185
17186     isVisible : function(){
17187         return this.visible;    
17188     },
17189
17190     // private
17191     showAction : function(){
17192         this.visible = true; // track visibility to prevent getStyle calls
17193         if(this.useDisplay === true){
17194             this.setDisplayed("");
17195         }else if(this.lastXY){
17196             supr.setXY.call(this, this.lastXY);
17197         }else if(this.lastLT){
17198             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17199         }
17200     },
17201
17202     // private
17203     hideAction : function(){
17204         this.visible = false;
17205         if(this.useDisplay === true){
17206             this.setDisplayed(false);
17207         }else{
17208             this.setLeftTop(-10000,-10000);
17209         }
17210     },
17211
17212     // overridden Element method
17213     setVisible : function(v, a, d, c, e){
17214         if(v){
17215             this.showAction();
17216         }
17217         if(a && v){
17218             var cb = function(){
17219                 this.sync(true);
17220                 if(c){
17221                     c();
17222                 }
17223             }.createDelegate(this);
17224             supr.setVisible.call(this, true, true, d, cb, e);
17225         }else{
17226             if(!v){
17227                 this.hideUnders(true);
17228             }
17229             var cb = c;
17230             if(a){
17231                 cb = function(){
17232                     this.hideAction();
17233                     if(c){
17234                         c();
17235                     }
17236                 }.createDelegate(this);
17237             }
17238             supr.setVisible.call(this, v, a, d, cb, e);
17239             if(v){
17240                 this.sync(true);
17241             }else if(!a){
17242                 this.hideAction();
17243             }
17244         }
17245     },
17246
17247     storeXY : function(xy){
17248         delete this.lastLT;
17249         this.lastXY = xy;
17250     },
17251
17252     storeLeftTop : function(left, top){
17253         delete this.lastXY;
17254         this.lastLT = [left, top];
17255     },
17256
17257     // private
17258     beforeFx : function(){
17259         this.beforeAction();
17260         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17261     },
17262
17263     // private
17264     afterFx : function(){
17265         Roo.Layer.superclass.afterFx.apply(this, arguments);
17266         this.sync(this.isVisible());
17267     },
17268
17269     // private
17270     beforeAction : function(){
17271         if(!this.updating && this.shadow){
17272             this.shadow.hide();
17273         }
17274     },
17275
17276     // overridden Element method
17277     setLeft : function(left){
17278         this.storeLeftTop(left, this.getTop(true));
17279         supr.setLeft.apply(this, arguments);
17280         this.sync();
17281     },
17282
17283     setTop : function(top){
17284         this.storeLeftTop(this.getLeft(true), top);
17285         supr.setTop.apply(this, arguments);
17286         this.sync();
17287     },
17288
17289     setLeftTop : function(left, top){
17290         this.storeLeftTop(left, top);
17291         supr.setLeftTop.apply(this, arguments);
17292         this.sync();
17293     },
17294
17295     setXY : function(xy, a, d, c, e){
17296         this.fixDisplay();
17297         this.beforeAction();
17298         this.storeXY(xy);
17299         var cb = this.createCB(c);
17300         supr.setXY.call(this, xy, a, d, cb, e);
17301         if(!a){
17302             cb();
17303         }
17304     },
17305
17306     // private
17307     createCB : function(c){
17308         var el = this;
17309         return function(){
17310             el.constrainXY();
17311             el.sync(true);
17312             if(c){
17313                 c();
17314             }
17315         };
17316     },
17317
17318     // overridden Element method
17319     setX : function(x, a, d, c, e){
17320         this.setXY([x, this.getY()], a, d, c, e);
17321     },
17322
17323     // overridden Element method
17324     setY : function(y, a, d, c, e){
17325         this.setXY([this.getX(), y], a, d, c, e);
17326     },
17327
17328     // overridden Element method
17329     setSize : function(w, h, a, d, c, e){
17330         this.beforeAction();
17331         var cb = this.createCB(c);
17332         supr.setSize.call(this, w, h, a, d, cb, e);
17333         if(!a){
17334             cb();
17335         }
17336     },
17337
17338     // overridden Element method
17339     setWidth : function(w, a, d, c, e){
17340         this.beforeAction();
17341         var cb = this.createCB(c);
17342         supr.setWidth.call(this, w, a, d, cb, e);
17343         if(!a){
17344             cb();
17345         }
17346     },
17347
17348     // overridden Element method
17349     setHeight : function(h, a, d, c, e){
17350         this.beforeAction();
17351         var cb = this.createCB(c);
17352         supr.setHeight.call(this, h, a, d, cb, e);
17353         if(!a){
17354             cb();
17355         }
17356     },
17357
17358     // overridden Element method
17359     setBounds : function(x, y, w, h, a, d, c, e){
17360         this.beforeAction();
17361         var cb = this.createCB(c);
17362         if(!a){
17363             this.storeXY([x, y]);
17364             supr.setXY.call(this, [x, y]);
17365             supr.setSize.call(this, w, h, a, d, cb, e);
17366             cb();
17367         }else{
17368             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17369         }
17370         return this;
17371     },
17372     
17373     /**
17374      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17375      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17376      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17377      * @param {Number} zindex The new z-index to set
17378      * @return {this} The Layer
17379      */
17380     setZIndex : function(zindex){
17381         this.zindex = zindex;
17382         this.setStyle("z-index", zindex + 2);
17383         if(this.shadow){
17384             this.shadow.setZIndex(zindex + 1);
17385         }
17386         if(this.shim){
17387             this.shim.setStyle("z-index", zindex);
17388         }
17389     }
17390 });
17391 })();/*
17392  * Original code for Roojs - LGPL
17393  * <script type="text/javascript">
17394  */
17395  
17396 /**
17397  * @class Roo.XComponent
17398  * A delayed Element creator...
17399  * Or a way to group chunks of interface together.
17400  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17401  *  used in conjunction with XComponent.build() it will create an instance of each element,
17402  *  then call addxtype() to build the User interface.
17403  * 
17404  * Mypart.xyx = new Roo.XComponent({
17405
17406     parent : 'Mypart.xyz', // empty == document.element.!!
17407     order : '001',
17408     name : 'xxxx'
17409     region : 'xxxx'
17410     disabled : function() {} 
17411      
17412     tree : function() { // return an tree of xtype declared components
17413         var MODULE = this;
17414         return 
17415         {
17416             xtype : 'NestedLayoutPanel',
17417             // technicall
17418         }
17419      ]
17420  *})
17421  *
17422  *
17423  * It can be used to build a big heiracy, with parent etc.
17424  * or you can just use this to render a single compoent to a dom element
17425  * MYPART.render(Roo.Element | String(id) | dom_element )
17426  *
17427  *
17428  * Usage patterns.
17429  *
17430  * Classic Roo
17431  *
17432  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17433  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17434  *
17435  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17436  *
17437  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17438  * - if mulitple topModules exist, the last one is defined as the top module.
17439  *
17440  * Embeded Roo
17441  * 
17442  * When the top level or multiple modules are to embedded into a existing HTML page,
17443  * the parent element can container '#id' of the element where the module will be drawn.
17444  *
17445  * Bootstrap Roo
17446  *
17447  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17448  * it relies more on a include mechanism, where sub modules are included into an outer page.
17449  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17450  * 
17451  * Bootstrap Roo Included elements
17452  *
17453  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17454  * hence confusing the component builder as it thinks there are multiple top level elements. 
17455  *
17456  * String Over-ride & Translations
17457  *
17458  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17459  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17460  * are needed. @see Roo.XComponent.overlayString  
17461  * 
17462  * 
17463  * 
17464  * @extends Roo.util.Observable
17465  * @constructor
17466  * @param cfg {Object} configuration of component
17467  * 
17468  */
17469 Roo.XComponent = function(cfg) {
17470     Roo.apply(this, cfg);
17471     this.addEvents({ 
17472         /**
17473              * @event built
17474              * Fires when this the componnt is built
17475              * @param {Roo.XComponent} c the component
17476              */
17477         'built' : true
17478         
17479     });
17480     this.region = this.region || 'center'; // default..
17481     Roo.XComponent.register(this);
17482     this.modules = false;
17483     this.el = false; // where the layout goes..
17484     
17485     
17486 }
17487 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17488     /**
17489      * @property el
17490      * The created element (with Roo.factory())
17491      * @type {Roo.Layout}
17492      */
17493     el  : false,
17494     
17495     /**
17496      * @property el
17497      * for BC  - use el in new code
17498      * @type {Roo.Layout}
17499      */
17500     panel : false,
17501     
17502     /**
17503      * @property layout
17504      * for BC  - use el in new code
17505      * @type {Roo.Layout}
17506      */
17507     layout : false,
17508     
17509      /**
17510      * @cfg {Function|boolean} disabled
17511      * If this module is disabled by some rule, return true from the funtion
17512      */
17513     disabled : false,
17514     
17515     /**
17516      * @cfg {String} parent 
17517      * Name of parent element which it get xtype added to..
17518      */
17519     parent: false,
17520     
17521     /**
17522      * @cfg {String} order
17523      * Used to set the order in which elements are created (usefull for multiple tabs)
17524      */
17525     
17526     order : false,
17527     /**
17528      * @cfg {String} name
17529      * String to display while loading.
17530      */
17531     name : false,
17532     /**
17533      * @cfg {String} region
17534      * Region to render component to (defaults to center)
17535      */
17536     region : 'center',
17537     
17538     /**
17539      * @cfg {Array} items
17540      * A single item array - the first element is the root of the tree..
17541      * It's done this way to stay compatible with the Xtype system...
17542      */
17543     items : false,
17544     
17545     /**
17546      * @property _tree
17547      * The method that retuns the tree of parts that make up this compoennt 
17548      * @type {function}
17549      */
17550     _tree  : false,
17551     
17552      /**
17553      * render
17554      * render element to dom or tree
17555      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17556      */
17557     
17558     render : function(el)
17559     {
17560         
17561         el = el || false;
17562         var hp = this.parent ? 1 : 0;
17563         Roo.debug &&  Roo.log(this);
17564         
17565         var tree = this._tree ? this._tree() : this.tree();
17566
17567         
17568         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17569             // if parent is a '#.....' string, then let's use that..
17570             var ename = this.parent.substr(1);
17571             this.parent = false;
17572             Roo.debug && Roo.log(ename);
17573             switch (ename) {
17574                 case 'bootstrap-body':
17575                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
17576                         // this is the BorderLayout standard?
17577                        this.parent = { el : true };
17578                        break;
17579                     }
17580                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
17581                         // need to insert stuff...
17582                         this.parent =  {
17583                              el : new Roo.bootstrap.layout.Border({
17584                                  el : document.body, 
17585                      
17586                                  center: {
17587                                     titlebar: false,
17588                                     autoScroll:false,
17589                                     closeOnTab: true,
17590                                     tabPosition: 'top',
17591                                       //resizeTabs: true,
17592                                     alwaysShowTabs: true,
17593                                     hideTabs: false
17594                                      //minTabWidth: 140
17595                                  }
17596                              })
17597                         
17598                          };
17599                          break;
17600                     }
17601                          
17602                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17603                         this.parent = { el :  new  Roo.bootstrap.Body() };
17604                         Roo.debug && Roo.log("setting el to doc body");
17605                          
17606                     } else {
17607                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17608                     }
17609                     break;
17610                 case 'bootstrap':
17611                     this.parent = { el : true};
17612                     // fall through
17613                 default:
17614                     el = Roo.get(ename);
17615                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17616                         this.parent = { el : true};
17617                     }
17618                     
17619                     break;
17620             }
17621                 
17622             
17623             if (!el && !this.parent) {
17624                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17625                 return;
17626             }
17627         }
17628         
17629         Roo.debug && Roo.log("EL:");
17630         Roo.debug && Roo.log(el);
17631         Roo.debug && Roo.log("this.parent.el:");
17632         Roo.debug && Roo.log(this.parent.el);
17633         
17634
17635         // altertive root elements ??? - we need a better way to indicate these.
17636         var is_alt = Roo.XComponent.is_alt ||
17637                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17638                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17639                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17640         
17641         
17642         
17643         if (!this.parent && is_alt) {
17644             //el = Roo.get(document.body);
17645             this.parent = { el : true };
17646         }
17647             
17648             
17649         
17650         if (!this.parent) {
17651             
17652             Roo.debug && Roo.log("no parent - creating one");
17653             
17654             el = el ? Roo.get(el) : false;      
17655             
17656             if (typeof(Roo.BorderLayout) == 'undefined' ) {
17657                 
17658                 this.parent =  {
17659                     el : new Roo.bootstrap.layout.Border({
17660                         el: el || document.body,
17661                     
17662                         center: {
17663                             titlebar: false,
17664                             autoScroll:false,
17665                             closeOnTab: true,
17666                             tabPosition: 'top',
17667                              //resizeTabs: true,
17668                             alwaysShowTabs: false,
17669                             hideTabs: true,
17670                             minTabWidth: 140,
17671                             overflow: 'visible'
17672                          }
17673                      })
17674                 };
17675             } else {
17676             
17677                 // it's a top level one..
17678                 this.parent =  {
17679                     el : new Roo.BorderLayout(el || document.body, {
17680                         center: {
17681                             titlebar: false,
17682                             autoScroll:false,
17683                             closeOnTab: true,
17684                             tabPosition: 'top',
17685                              //resizeTabs: true,
17686                             alwaysShowTabs: el && hp? false :  true,
17687                             hideTabs: el || !hp ? true :  false,
17688                             minTabWidth: 140
17689                          }
17690                     })
17691                 };
17692             }
17693         }
17694         
17695         if (!this.parent.el) {
17696                 // probably an old style ctor, which has been disabled.
17697                 return;
17698
17699         }
17700                 // The 'tree' method is  '_tree now' 
17701             
17702         tree.region = tree.region || this.region;
17703         var is_body = false;
17704         if (this.parent.el === true) {
17705             // bootstrap... - body..
17706             if (el) {
17707                 tree.el = el;
17708             }
17709             this.parent.el = Roo.factory(tree);
17710             is_body = true;
17711         }
17712         
17713         this.el = this.parent.el.addxtype(tree, undefined, is_body);
17714         this.fireEvent('built', this);
17715         
17716         this.panel = this.el;
17717         this.layout = this.panel.layout;
17718         this.parentLayout = this.parent.layout  || false;  
17719          
17720     }
17721     
17722 });
17723
17724 Roo.apply(Roo.XComponent, {
17725     /**
17726      * @property  hideProgress
17727      * true to disable the building progress bar.. usefull on single page renders.
17728      * @type Boolean
17729      */
17730     hideProgress : false,
17731     /**
17732      * @property  buildCompleted
17733      * True when the builder has completed building the interface.
17734      * @type Boolean
17735      */
17736     buildCompleted : false,
17737      
17738     /**
17739      * @property  topModule
17740      * the upper most module - uses document.element as it's constructor.
17741      * @type Object
17742      */
17743      
17744     topModule  : false,
17745       
17746     /**
17747      * @property  modules
17748      * array of modules to be created by registration system.
17749      * @type {Array} of Roo.XComponent
17750      */
17751     
17752     modules : [],
17753     /**
17754      * @property  elmodules
17755      * array of modules to be created by which use #ID 
17756      * @type {Array} of Roo.XComponent
17757      */
17758      
17759     elmodules : [],
17760
17761      /**
17762      * @property  is_alt
17763      * Is an alternative Root - normally used by bootstrap or other systems,
17764      *    where the top element in the tree can wrap 'body' 
17765      * @type {boolean}  (default false)
17766      */
17767      
17768     is_alt : false,
17769     /**
17770      * @property  build_from_html
17771      * Build elements from html - used by bootstrap HTML stuff 
17772      *    - this is cleared after build is completed
17773      * @type {boolean}    (default false)
17774      */
17775      
17776     build_from_html : false,
17777     /**
17778      * Register components to be built later.
17779      *
17780      * This solves the following issues
17781      * - Building is not done on page load, but after an authentication process has occured.
17782      * - Interface elements are registered on page load
17783      * - Parent Interface elements may not be loaded before child, so this handles that..
17784      * 
17785      *
17786      * example:
17787      * 
17788      * MyApp.register({
17789           order : '000001',
17790           module : 'Pman.Tab.projectMgr',
17791           region : 'center',
17792           parent : 'Pman.layout',
17793           disabled : false,  // or use a function..
17794         })
17795      
17796      * * @param {Object} details about module
17797      */
17798     register : function(obj) {
17799                 
17800         Roo.XComponent.event.fireEvent('register', obj);
17801         switch(typeof(obj.disabled) ) {
17802                 
17803             case 'undefined':
17804                 break;
17805             
17806             case 'function':
17807                 if ( obj.disabled() ) {
17808                         return;
17809                 }
17810                 break;
17811             
17812             default:
17813                 if (obj.disabled || obj.region == '#disabled') {
17814                         return;
17815                 }
17816                 break;
17817         }
17818                 
17819         this.modules.push(obj);
17820          
17821     },
17822     /**
17823      * convert a string to an object..
17824      * eg. 'AAA.BBB' -> finds AAA.BBB
17825
17826      */
17827     
17828     toObject : function(str)
17829     {
17830         if (!str || typeof(str) == 'object') {
17831             return str;
17832         }
17833         if (str.substring(0,1) == '#') {
17834             return str;
17835         }
17836
17837         var ar = str.split('.');
17838         var rt, o;
17839         rt = ar.shift();
17840             /** eval:var:o */
17841         try {
17842             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17843         } catch (e) {
17844             throw "Module not found : " + str;
17845         }
17846         
17847         if (o === false) {
17848             throw "Module not found : " + str;
17849         }
17850         Roo.each(ar, function(e) {
17851             if (typeof(o[e]) == 'undefined') {
17852                 throw "Module not found : " + str;
17853             }
17854             o = o[e];
17855         });
17856         
17857         return o;
17858         
17859     },
17860     
17861     
17862     /**
17863      * move modules into their correct place in the tree..
17864      * 
17865      */
17866     preBuild : function ()
17867     {
17868         var _t = this;
17869         Roo.each(this.modules , function (obj)
17870         {
17871             Roo.XComponent.event.fireEvent('beforebuild', obj);
17872             
17873             var opar = obj.parent;
17874             try { 
17875                 obj.parent = this.toObject(opar);
17876             } catch(e) {
17877                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17878                 return;
17879             }
17880             
17881             if (!obj.parent) {
17882                 Roo.debug && Roo.log("GOT top level module");
17883                 Roo.debug && Roo.log(obj);
17884                 obj.modules = new Roo.util.MixedCollection(false, 
17885                     function(o) { return o.order + '' }
17886                 );
17887                 this.topModule = obj;
17888                 return;
17889             }
17890                         // parent is a string (usually a dom element name..)
17891             if (typeof(obj.parent) == 'string') {
17892                 this.elmodules.push(obj);
17893                 return;
17894             }
17895             if (obj.parent.constructor != Roo.XComponent) {
17896                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17897             }
17898             if (!obj.parent.modules) {
17899                 obj.parent.modules = new Roo.util.MixedCollection(false, 
17900                     function(o) { return o.order + '' }
17901                 );
17902             }
17903             if (obj.parent.disabled) {
17904                 obj.disabled = true;
17905             }
17906             obj.parent.modules.add(obj);
17907         }, this);
17908     },
17909     
17910      /**
17911      * make a list of modules to build.
17912      * @return {Array} list of modules. 
17913      */ 
17914     
17915     buildOrder : function()
17916     {
17917         var _this = this;
17918         var cmp = function(a,b) {   
17919             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17920         };
17921         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17922             throw "No top level modules to build";
17923         }
17924         
17925         // make a flat list in order of modules to build.
17926         var mods = this.topModule ? [ this.topModule ] : [];
17927                 
17928         
17929         // elmodules (is a list of DOM based modules )
17930         Roo.each(this.elmodules, function(e) {
17931             mods.push(e);
17932             if (!this.topModule &&
17933                 typeof(e.parent) == 'string' &&
17934                 e.parent.substring(0,1) == '#' &&
17935                 Roo.get(e.parent.substr(1))
17936                ) {
17937                 
17938                 _this.topModule = e;
17939             }
17940             
17941         });
17942
17943         
17944         // add modules to their parents..
17945         var addMod = function(m) {
17946             Roo.debug && Roo.log("build Order: add: " + m.name);
17947                 
17948             mods.push(m);
17949             if (m.modules && !m.disabled) {
17950                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17951                 m.modules.keySort('ASC',  cmp );
17952                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17953     
17954                 m.modules.each(addMod);
17955             } else {
17956                 Roo.debug && Roo.log("build Order: no child modules");
17957             }
17958             // not sure if this is used any more..
17959             if (m.finalize) {
17960                 m.finalize.name = m.name + " (clean up) ";
17961                 mods.push(m.finalize);
17962             }
17963             
17964         }
17965         if (this.topModule && this.topModule.modules) { 
17966             this.topModule.modules.keySort('ASC',  cmp );
17967             this.topModule.modules.each(addMod);
17968         } 
17969         return mods;
17970     },
17971     
17972      /**
17973      * Build the registered modules.
17974      * @param {Object} parent element.
17975      * @param {Function} optional method to call after module has been added.
17976      * 
17977      */ 
17978    
17979     build : function(opts) 
17980     {
17981         
17982         if (typeof(opts) != 'undefined') {
17983             Roo.apply(this,opts);
17984         }
17985         
17986         this.preBuild();
17987         var mods = this.buildOrder();
17988       
17989         //this.allmods = mods;
17990         //Roo.debug && Roo.log(mods);
17991         //return;
17992         if (!mods.length) { // should not happen
17993             throw "NO modules!!!";
17994         }
17995         
17996         
17997         var msg = "Building Interface...";
17998         // flash it up as modal - so we store the mask!?
17999         if (!this.hideProgress && Roo.MessageBox) {
18000             Roo.MessageBox.show({ title: 'loading' });
18001             Roo.MessageBox.show({
18002                title: "Please wait...",
18003                msg: msg,
18004                width:450,
18005                progress:true,
18006                buttons : false,
18007                closable:false,
18008                modal: false
18009               
18010             });
18011         }
18012         var total = mods.length;
18013         
18014         var _this = this;
18015         var progressRun = function() {
18016             if (!mods.length) {
18017                 Roo.debug && Roo.log('hide?');
18018                 if (!this.hideProgress && Roo.MessageBox) {
18019                     Roo.MessageBox.hide();
18020                 }
18021                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18022                 
18023                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18024                 
18025                 // THE END...
18026                 return false;   
18027             }
18028             
18029             var m = mods.shift();
18030             
18031             
18032             Roo.debug && Roo.log(m);
18033             // not sure if this is supported any more.. - modules that are are just function
18034             if (typeof(m) == 'function') { 
18035                 m.call(this);
18036                 return progressRun.defer(10, _this);
18037             } 
18038             
18039             
18040             msg = "Building Interface " + (total  - mods.length) + 
18041                     " of " + total + 
18042                     (m.name ? (' - ' + m.name) : '');
18043                         Roo.debug && Roo.log(msg);
18044             if (!_this.hideProgress &&  Roo.MessageBox) { 
18045                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18046             }
18047             
18048          
18049             // is the module disabled?
18050             var disabled = (typeof(m.disabled) == 'function') ?
18051                 m.disabled.call(m.module.disabled) : m.disabled;    
18052             
18053             
18054             if (disabled) {
18055                 return progressRun(); // we do not update the display!
18056             }
18057             
18058             // now build 
18059             
18060                         
18061                         
18062             m.render();
18063             // it's 10 on top level, and 1 on others??? why...
18064             return progressRun.defer(10, _this);
18065              
18066         }
18067         progressRun.defer(1, _this);
18068      
18069         
18070         
18071     },
18072     /**
18073      * Overlay a set of modified strings onto a component
18074      * This is dependant on our builder exporting the strings and 'named strings' elements.
18075      * 
18076      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18077      * @param {Object} associative array of 'named' string and it's new value.
18078      * 
18079      */
18080         overlayStrings : function( component, strings )
18081     {
18082         if (typeof(component['_named_strings']) == 'undefined') {
18083             throw "ERROR: component does not have _named_strings";
18084         }
18085         for ( var k in strings ) {
18086             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18087             if (md !== false) {
18088                 component['_strings'][md] = strings[k];
18089             } else {
18090                 Roo.log('could not find named string: ' + k + ' in');
18091                 Roo.log(component);
18092             }
18093             
18094         }
18095         
18096     },
18097     
18098         
18099         /**
18100          * Event Object.
18101          *
18102          *
18103          */
18104         event: false, 
18105     /**
18106          * wrapper for event.on - aliased later..  
18107          * Typically use to register a event handler for register:
18108          *
18109          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18110          *
18111          */
18112     on : false
18113    
18114     
18115     
18116 });
18117
18118 Roo.XComponent.event = new Roo.util.Observable({
18119                 events : { 
18120                         /**
18121                          * @event register
18122                          * Fires when an Component is registered,
18123                          * set the disable property on the Component to stop registration.
18124                          * @param {Roo.XComponent} c the component being registerd.
18125                          * 
18126                          */
18127                         'register' : true,
18128             /**
18129                          * @event beforebuild
18130                          * Fires before each Component is built
18131                          * can be used to apply permissions.
18132                          * @param {Roo.XComponent} c the component being registerd.
18133                          * 
18134                          */
18135                         'beforebuild' : true,
18136                         /**
18137                          * @event buildcomplete
18138                          * Fires on the top level element when all elements have been built
18139                          * @param {Roo.XComponent} the top level component.
18140                          */
18141                         'buildcomplete' : true
18142                         
18143                 }
18144 });
18145
18146 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18147  //
18148  /**
18149  * marked - a markdown parser
18150  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18151  * https://github.com/chjj/marked
18152  */
18153
18154
18155 /**
18156  *
18157  * Roo.Markdown - is a very crude wrapper around marked..
18158  *
18159  * usage:
18160  * 
18161  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18162  * 
18163  * Note: move the sample code to the bottom of this
18164  * file before uncommenting it.
18165  *
18166  */
18167
18168 Roo.Markdown = {};
18169 Roo.Markdown.toHtml = function(text) {
18170     
18171     var c = new Roo.Markdown.marked.setOptions({
18172             renderer: new Roo.Markdown.marked.Renderer(),
18173             gfm: true,
18174             tables: true,
18175             breaks: false,
18176             pedantic: false,
18177             sanitize: false,
18178             smartLists: true,
18179             smartypants: false
18180           });
18181     // A FEW HACKS!!?
18182     
18183     text = text.replace(/\\\n/g,' ');
18184     return Roo.Markdown.marked(text);
18185 };
18186 //
18187 // converter
18188 //
18189 // Wraps all "globals" so that the only thing
18190 // exposed is makeHtml().
18191 //
18192 (function() {
18193     
18194      /**
18195          * eval:var:escape
18196          * eval:var:unescape
18197          * eval:var:replace
18198          */
18199       
18200     /**
18201      * Helpers
18202      */
18203     
18204     var escape = function (html, encode) {
18205       return html
18206         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18207         .replace(/</g, '&lt;')
18208         .replace(/>/g, '&gt;')
18209         .replace(/"/g, '&quot;')
18210         .replace(/'/g, '&#39;');
18211     }
18212     
18213     var unescape = function (html) {
18214         // explicitly match decimal, hex, and named HTML entities 
18215       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18216         n = n.toLowerCase();
18217         if (n === 'colon') { return ':'; }
18218         if (n.charAt(0) === '#') {
18219           return n.charAt(1) === 'x'
18220             ? String.fromCharCode(parseInt(n.substring(2), 16))
18221             : String.fromCharCode(+n.substring(1));
18222         }
18223         return '';
18224       });
18225     }
18226     
18227     var replace = function (regex, opt) {
18228       regex = regex.source;
18229       opt = opt || '';
18230       return function self(name, val) {
18231         if (!name) { return new RegExp(regex, opt); }
18232         val = val.source || val;
18233         val = val.replace(/(^|[^\[])\^/g, '$1');
18234         regex = regex.replace(name, val);
18235         return self;
18236       };
18237     }
18238
18239
18240          /**
18241          * eval:var:noop
18242     */
18243     var noop = function () {}
18244     noop.exec = noop;
18245     
18246          /**
18247          * eval:var:merge
18248     */
18249     var merge = function (obj) {
18250       var i = 1
18251         , target
18252         , key;
18253     
18254       for (; i < arguments.length; i++) {
18255         target = arguments[i];
18256         for (key in target) {
18257           if (Object.prototype.hasOwnProperty.call(target, key)) {
18258             obj[key] = target[key];
18259           }
18260         }
18261       }
18262     
18263       return obj;
18264     }
18265     
18266     
18267     /**
18268      * Block-Level Grammar
18269      */
18270     
18271     
18272     
18273     
18274     var block = {
18275       newline: /^\n+/,
18276       code: /^( {4}[^\n]+\n*)+/,
18277       fences: noop,
18278       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18279       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18280       nptable: noop,
18281       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18282       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18283       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18284       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18285       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18286       table: noop,
18287       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18288       text: /^[^\n]+/
18289     };
18290     
18291     block.bullet = /(?:[*+-]|\d+\.)/;
18292     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18293     block.item = replace(block.item, 'gm')
18294       (/bull/g, block.bullet)
18295       ();
18296     
18297     block.list = replace(block.list)
18298       (/bull/g, block.bullet)
18299       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18300       ('def', '\\n+(?=' + block.def.source + ')')
18301       ();
18302     
18303     block.blockquote = replace(block.blockquote)
18304       ('def', block.def)
18305       ();
18306     
18307     block._tag = '(?!(?:'
18308       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18309       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18310       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18311     
18312     block.html = replace(block.html)
18313       ('comment', /<!--[\s\S]*?-->/)
18314       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18315       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18316       (/tag/g, block._tag)
18317       ();
18318     
18319     block.paragraph = replace(block.paragraph)
18320       ('hr', block.hr)
18321       ('heading', block.heading)
18322       ('lheading', block.lheading)
18323       ('blockquote', block.blockquote)
18324       ('tag', '<' + block._tag)
18325       ('def', block.def)
18326       ();
18327     
18328     /**
18329      * Normal Block Grammar
18330      */
18331     
18332     block.normal = merge({}, block);
18333     
18334     /**
18335      * GFM Block Grammar
18336      */
18337     
18338     block.gfm = merge({}, block.normal, {
18339       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18340       paragraph: /^/,
18341       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18342     });
18343     
18344     block.gfm.paragraph = replace(block.paragraph)
18345       ('(?!', '(?!'
18346         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18347         + block.list.source.replace('\\1', '\\3') + '|')
18348       ();
18349     
18350     /**
18351      * GFM + Tables Block Grammar
18352      */
18353     
18354     block.tables = merge({}, block.gfm, {
18355       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18356       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18357     });
18358     
18359     /**
18360      * Block Lexer
18361      */
18362     
18363     var Lexer = function (options) {
18364       this.tokens = [];
18365       this.tokens.links = {};
18366       this.options = options || marked.defaults;
18367       this.rules = block.normal;
18368     
18369       if (this.options.gfm) {
18370         if (this.options.tables) {
18371           this.rules = block.tables;
18372         } else {
18373           this.rules = block.gfm;
18374         }
18375       }
18376     }
18377     
18378     /**
18379      * Expose Block Rules
18380      */
18381     
18382     Lexer.rules = block;
18383     
18384     /**
18385      * Static Lex Method
18386      */
18387     
18388     Lexer.lex = function(src, options) {
18389       var lexer = new Lexer(options);
18390       return lexer.lex(src);
18391     };
18392     
18393     /**
18394      * Preprocessing
18395      */
18396     
18397     Lexer.prototype.lex = function(src) {
18398       src = src
18399         .replace(/\r\n|\r/g, '\n')
18400         .replace(/\t/g, '    ')
18401         .replace(/\u00a0/g, ' ')
18402         .replace(/\u2424/g, '\n');
18403     
18404       return this.token(src, true);
18405     };
18406     
18407     /**
18408      * Lexing
18409      */
18410     
18411     Lexer.prototype.token = function(src, top, bq) {
18412       var src = src.replace(/^ +$/gm, '')
18413         , next
18414         , loose
18415         , cap
18416         , bull
18417         , b
18418         , item
18419         , space
18420         , i
18421         , l;
18422     
18423       while (src) {
18424         // newline
18425         if (cap = this.rules.newline.exec(src)) {
18426           src = src.substring(cap[0].length);
18427           if (cap[0].length > 1) {
18428             this.tokens.push({
18429               type: 'space'
18430             });
18431           }
18432         }
18433     
18434         // code
18435         if (cap = this.rules.code.exec(src)) {
18436           src = src.substring(cap[0].length);
18437           cap = cap[0].replace(/^ {4}/gm, '');
18438           this.tokens.push({
18439             type: 'code',
18440             text: !this.options.pedantic
18441               ? cap.replace(/\n+$/, '')
18442               : cap
18443           });
18444           continue;
18445         }
18446     
18447         // fences (gfm)
18448         if (cap = this.rules.fences.exec(src)) {
18449           src = src.substring(cap[0].length);
18450           this.tokens.push({
18451             type: 'code',
18452             lang: cap[2],
18453             text: cap[3] || ''
18454           });
18455           continue;
18456         }
18457     
18458         // heading
18459         if (cap = this.rules.heading.exec(src)) {
18460           src = src.substring(cap[0].length);
18461           this.tokens.push({
18462             type: 'heading',
18463             depth: cap[1].length,
18464             text: cap[2]
18465           });
18466           continue;
18467         }
18468     
18469         // table no leading pipe (gfm)
18470         if (top && (cap = this.rules.nptable.exec(src))) {
18471           src = src.substring(cap[0].length);
18472     
18473           item = {
18474             type: 'table',
18475             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18476             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18477             cells: cap[3].replace(/\n$/, '').split('\n')
18478           };
18479     
18480           for (i = 0; i < item.align.length; i++) {
18481             if (/^ *-+: *$/.test(item.align[i])) {
18482               item.align[i] = 'right';
18483             } else if (/^ *:-+: *$/.test(item.align[i])) {
18484               item.align[i] = 'center';
18485             } else if (/^ *:-+ *$/.test(item.align[i])) {
18486               item.align[i] = 'left';
18487             } else {
18488               item.align[i] = null;
18489             }
18490           }
18491     
18492           for (i = 0; i < item.cells.length; i++) {
18493             item.cells[i] = item.cells[i].split(/ *\| */);
18494           }
18495     
18496           this.tokens.push(item);
18497     
18498           continue;
18499         }
18500     
18501         // lheading
18502         if (cap = this.rules.lheading.exec(src)) {
18503           src = src.substring(cap[0].length);
18504           this.tokens.push({
18505             type: 'heading',
18506             depth: cap[2] === '=' ? 1 : 2,
18507             text: cap[1]
18508           });
18509           continue;
18510         }
18511     
18512         // hr
18513         if (cap = this.rules.hr.exec(src)) {
18514           src = src.substring(cap[0].length);
18515           this.tokens.push({
18516             type: 'hr'
18517           });
18518           continue;
18519         }
18520     
18521         // blockquote
18522         if (cap = this.rules.blockquote.exec(src)) {
18523           src = src.substring(cap[0].length);
18524     
18525           this.tokens.push({
18526             type: 'blockquote_start'
18527           });
18528     
18529           cap = cap[0].replace(/^ *> ?/gm, '');
18530     
18531           // Pass `top` to keep the current
18532           // "toplevel" state. This is exactly
18533           // how markdown.pl works.
18534           this.token(cap, top, true);
18535     
18536           this.tokens.push({
18537             type: 'blockquote_end'
18538           });
18539     
18540           continue;
18541         }
18542     
18543         // list
18544         if (cap = this.rules.list.exec(src)) {
18545           src = src.substring(cap[0].length);
18546           bull = cap[2];
18547     
18548           this.tokens.push({
18549             type: 'list_start',
18550             ordered: bull.length > 1
18551           });
18552     
18553           // Get each top-level item.
18554           cap = cap[0].match(this.rules.item);
18555     
18556           next = false;
18557           l = cap.length;
18558           i = 0;
18559     
18560           for (; i < l; i++) {
18561             item = cap[i];
18562     
18563             // Remove the list item's bullet
18564             // so it is seen as the next token.
18565             space = item.length;
18566             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18567     
18568             // Outdent whatever the
18569             // list item contains. Hacky.
18570             if (~item.indexOf('\n ')) {
18571               space -= item.length;
18572               item = !this.options.pedantic
18573                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18574                 : item.replace(/^ {1,4}/gm, '');
18575             }
18576     
18577             // Determine whether the next list item belongs here.
18578             // Backpedal if it does not belong in this list.
18579             if (this.options.smartLists && i !== l - 1) {
18580               b = block.bullet.exec(cap[i + 1])[0];
18581               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18582                 src = cap.slice(i + 1).join('\n') + src;
18583                 i = l - 1;
18584               }
18585             }
18586     
18587             // Determine whether item is loose or not.
18588             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18589             // for discount behavior.
18590             loose = next || /\n\n(?!\s*$)/.test(item);
18591             if (i !== l - 1) {
18592               next = item.charAt(item.length - 1) === '\n';
18593               if (!loose) { loose = next; }
18594             }
18595     
18596             this.tokens.push({
18597               type: loose
18598                 ? 'loose_item_start'
18599                 : 'list_item_start'
18600             });
18601     
18602             // Recurse.
18603             this.token(item, false, bq);
18604     
18605             this.tokens.push({
18606               type: 'list_item_end'
18607             });
18608           }
18609     
18610           this.tokens.push({
18611             type: 'list_end'
18612           });
18613     
18614           continue;
18615         }
18616     
18617         // html
18618         if (cap = this.rules.html.exec(src)) {
18619           src = src.substring(cap[0].length);
18620           this.tokens.push({
18621             type: this.options.sanitize
18622               ? 'paragraph'
18623               : 'html',
18624             pre: !this.options.sanitizer
18625               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18626             text: cap[0]
18627           });
18628           continue;
18629         }
18630     
18631         // def
18632         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18633           src = src.substring(cap[0].length);
18634           this.tokens.links[cap[1].toLowerCase()] = {
18635             href: cap[2],
18636             title: cap[3]
18637           };
18638           continue;
18639         }
18640     
18641         // table (gfm)
18642         if (top && (cap = this.rules.table.exec(src))) {
18643           src = src.substring(cap[0].length);
18644     
18645           item = {
18646             type: 'table',
18647             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18648             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18649             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18650           };
18651     
18652           for (i = 0; i < item.align.length; i++) {
18653             if (/^ *-+: *$/.test(item.align[i])) {
18654               item.align[i] = 'right';
18655             } else if (/^ *:-+: *$/.test(item.align[i])) {
18656               item.align[i] = 'center';
18657             } else if (/^ *:-+ *$/.test(item.align[i])) {
18658               item.align[i] = 'left';
18659             } else {
18660               item.align[i] = null;
18661             }
18662           }
18663     
18664           for (i = 0; i < item.cells.length; i++) {
18665             item.cells[i] = item.cells[i]
18666               .replace(/^ *\| *| *\| *$/g, '')
18667               .split(/ *\| */);
18668           }
18669     
18670           this.tokens.push(item);
18671     
18672           continue;
18673         }
18674     
18675         // top-level paragraph
18676         if (top && (cap = this.rules.paragraph.exec(src))) {
18677           src = src.substring(cap[0].length);
18678           this.tokens.push({
18679             type: 'paragraph',
18680             text: cap[1].charAt(cap[1].length - 1) === '\n'
18681               ? cap[1].slice(0, -1)
18682               : cap[1]
18683           });
18684           continue;
18685         }
18686     
18687         // text
18688         if (cap = this.rules.text.exec(src)) {
18689           // Top-level should never reach here.
18690           src = src.substring(cap[0].length);
18691           this.tokens.push({
18692             type: 'text',
18693             text: cap[0]
18694           });
18695           continue;
18696         }
18697     
18698         if (src) {
18699           throw new
18700             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18701         }
18702       }
18703     
18704       return this.tokens;
18705     };
18706     
18707     /**
18708      * Inline-Level Grammar
18709      */
18710     
18711     var inline = {
18712       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18713       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18714       url: noop,
18715       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18716       link: /^!?\[(inside)\]\(href\)/,
18717       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18718       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18719       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18720       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18721       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18722       br: /^ {2,}\n(?!\s*$)/,
18723       del: noop,
18724       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18725     };
18726     
18727     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18728     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18729     
18730     inline.link = replace(inline.link)
18731       ('inside', inline._inside)
18732       ('href', inline._href)
18733       ();
18734     
18735     inline.reflink = replace(inline.reflink)
18736       ('inside', inline._inside)
18737       ();
18738     
18739     /**
18740      * Normal Inline Grammar
18741      */
18742     
18743     inline.normal = merge({}, inline);
18744     
18745     /**
18746      * Pedantic Inline Grammar
18747      */
18748     
18749     inline.pedantic = merge({}, inline.normal, {
18750       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18751       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18752     });
18753     
18754     /**
18755      * GFM Inline Grammar
18756      */
18757     
18758     inline.gfm = merge({}, inline.normal, {
18759       escape: replace(inline.escape)('])', '~|])')(),
18760       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18761       del: /^~~(?=\S)([\s\S]*?\S)~~/,
18762       text: replace(inline.text)
18763         (']|', '~]|')
18764         ('|', '|https?://|')
18765         ()
18766     });
18767     
18768     /**
18769      * GFM + Line Breaks Inline Grammar
18770      */
18771     
18772     inline.breaks = merge({}, inline.gfm, {
18773       br: replace(inline.br)('{2,}', '*')(),
18774       text: replace(inline.gfm.text)('{2,}', '*')()
18775     });
18776     
18777     /**
18778      * Inline Lexer & Compiler
18779      */
18780     
18781     var InlineLexer  = function (links, options) {
18782       this.options = options || marked.defaults;
18783       this.links = links;
18784       this.rules = inline.normal;
18785       this.renderer = this.options.renderer || new Renderer;
18786       this.renderer.options = this.options;
18787     
18788       if (!this.links) {
18789         throw new
18790           Error('Tokens array requires a `links` property.');
18791       }
18792     
18793       if (this.options.gfm) {
18794         if (this.options.breaks) {
18795           this.rules = inline.breaks;
18796         } else {
18797           this.rules = inline.gfm;
18798         }
18799       } else if (this.options.pedantic) {
18800         this.rules = inline.pedantic;
18801       }
18802     }
18803     
18804     /**
18805      * Expose Inline Rules
18806      */
18807     
18808     InlineLexer.rules = inline;
18809     
18810     /**
18811      * Static Lexing/Compiling Method
18812      */
18813     
18814     InlineLexer.output = function(src, links, options) {
18815       var inline = new InlineLexer(links, options);
18816       return inline.output(src);
18817     };
18818     
18819     /**
18820      * Lexing/Compiling
18821      */
18822     
18823     InlineLexer.prototype.output = function(src) {
18824       var out = ''
18825         , link
18826         , text
18827         , href
18828         , cap;
18829     
18830       while (src) {
18831         // escape
18832         if (cap = this.rules.escape.exec(src)) {
18833           src = src.substring(cap[0].length);
18834           out += cap[1];
18835           continue;
18836         }
18837     
18838         // autolink
18839         if (cap = this.rules.autolink.exec(src)) {
18840           src = src.substring(cap[0].length);
18841           if (cap[2] === '@') {
18842             text = cap[1].charAt(6) === ':'
18843               ? this.mangle(cap[1].substring(7))
18844               : this.mangle(cap[1]);
18845             href = this.mangle('mailto:') + text;
18846           } else {
18847             text = escape(cap[1]);
18848             href = text;
18849           }
18850           out += this.renderer.link(href, null, text);
18851           continue;
18852         }
18853     
18854         // url (gfm)
18855         if (!this.inLink && (cap = this.rules.url.exec(src))) {
18856           src = src.substring(cap[0].length);
18857           text = escape(cap[1]);
18858           href = text;
18859           out += this.renderer.link(href, null, text);
18860           continue;
18861         }
18862     
18863         // tag
18864         if (cap = this.rules.tag.exec(src)) {
18865           if (!this.inLink && /^<a /i.test(cap[0])) {
18866             this.inLink = true;
18867           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18868             this.inLink = false;
18869           }
18870           src = src.substring(cap[0].length);
18871           out += this.options.sanitize
18872             ? this.options.sanitizer
18873               ? this.options.sanitizer(cap[0])
18874               : escape(cap[0])
18875             : cap[0];
18876           continue;
18877         }
18878     
18879         // link
18880         if (cap = this.rules.link.exec(src)) {
18881           src = src.substring(cap[0].length);
18882           this.inLink = true;
18883           out += this.outputLink(cap, {
18884             href: cap[2],
18885             title: cap[3]
18886           });
18887           this.inLink = false;
18888           continue;
18889         }
18890     
18891         // reflink, nolink
18892         if ((cap = this.rules.reflink.exec(src))
18893             || (cap = this.rules.nolink.exec(src))) {
18894           src = src.substring(cap[0].length);
18895           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18896           link = this.links[link.toLowerCase()];
18897           if (!link || !link.href) {
18898             out += cap[0].charAt(0);
18899             src = cap[0].substring(1) + src;
18900             continue;
18901           }
18902           this.inLink = true;
18903           out += this.outputLink(cap, link);
18904           this.inLink = false;
18905           continue;
18906         }
18907     
18908         // strong
18909         if (cap = this.rules.strong.exec(src)) {
18910           src = src.substring(cap[0].length);
18911           out += this.renderer.strong(this.output(cap[2] || cap[1]));
18912           continue;
18913         }
18914     
18915         // em
18916         if (cap = this.rules.em.exec(src)) {
18917           src = src.substring(cap[0].length);
18918           out += this.renderer.em(this.output(cap[2] || cap[1]));
18919           continue;
18920         }
18921     
18922         // code
18923         if (cap = this.rules.code.exec(src)) {
18924           src = src.substring(cap[0].length);
18925           out += this.renderer.codespan(escape(cap[2], true));
18926           continue;
18927         }
18928     
18929         // br
18930         if (cap = this.rules.br.exec(src)) {
18931           src = src.substring(cap[0].length);
18932           out += this.renderer.br();
18933           continue;
18934         }
18935     
18936         // del (gfm)
18937         if (cap = this.rules.del.exec(src)) {
18938           src = src.substring(cap[0].length);
18939           out += this.renderer.del(this.output(cap[1]));
18940           continue;
18941         }
18942     
18943         // text
18944         if (cap = this.rules.text.exec(src)) {
18945           src = src.substring(cap[0].length);
18946           out += this.renderer.text(escape(this.smartypants(cap[0])));
18947           continue;
18948         }
18949     
18950         if (src) {
18951           throw new
18952             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18953         }
18954       }
18955     
18956       return out;
18957     };
18958     
18959     /**
18960      * Compile Link
18961      */
18962     
18963     InlineLexer.prototype.outputLink = function(cap, link) {
18964       var href = escape(link.href)
18965         , title = link.title ? escape(link.title) : null;
18966     
18967       return cap[0].charAt(0) !== '!'
18968         ? this.renderer.link(href, title, this.output(cap[1]))
18969         : this.renderer.image(href, title, escape(cap[1]));
18970     };
18971     
18972     /**
18973      * Smartypants Transformations
18974      */
18975     
18976     InlineLexer.prototype.smartypants = function(text) {
18977       if (!this.options.smartypants)  { return text; }
18978       return text
18979         // em-dashes
18980         .replace(/---/g, '\u2014')
18981         // en-dashes
18982         .replace(/--/g, '\u2013')
18983         // opening singles
18984         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18985         // closing singles & apostrophes
18986         .replace(/'/g, '\u2019')
18987         // opening doubles
18988         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18989         // closing doubles
18990         .replace(/"/g, '\u201d')
18991         // ellipses
18992         .replace(/\.{3}/g, '\u2026');
18993     };
18994     
18995     /**
18996      * Mangle Links
18997      */
18998     
18999     InlineLexer.prototype.mangle = function(text) {
19000       if (!this.options.mangle) { return text; }
19001       var out = ''
19002         , l = text.length
19003         , i = 0
19004         , ch;
19005     
19006       for (; i < l; i++) {
19007         ch = text.charCodeAt(i);
19008         if (Math.random() > 0.5) {
19009           ch = 'x' + ch.toString(16);
19010         }
19011         out += '&#' + ch + ';';
19012       }
19013     
19014       return out;
19015     };
19016     
19017     /**
19018      * Renderer
19019      */
19020     
19021      /**
19022          * eval:var:Renderer
19023     */
19024     
19025     var Renderer   = function (options) {
19026       this.options = options || {};
19027     }
19028     
19029     Renderer.prototype.code = function(code, lang, escaped) {
19030       if (this.options.highlight) {
19031         var out = this.options.highlight(code, lang);
19032         if (out != null && out !== code) {
19033           escaped = true;
19034           code = out;
19035         }
19036       } else {
19037             // hack!!! - it's already escapeD?
19038             escaped = true;
19039       }
19040     
19041       if (!lang) {
19042         return '<pre><code>'
19043           + (escaped ? code : escape(code, true))
19044           + '\n</code></pre>';
19045       }
19046     
19047       return '<pre><code class="'
19048         + this.options.langPrefix
19049         + escape(lang, true)
19050         + '">'
19051         + (escaped ? code : escape(code, true))
19052         + '\n</code></pre>\n';
19053     };
19054     
19055     Renderer.prototype.blockquote = function(quote) {
19056       return '<blockquote>\n' + quote + '</blockquote>\n';
19057     };
19058     
19059     Renderer.prototype.html = function(html) {
19060       return html;
19061     };
19062     
19063     Renderer.prototype.heading = function(text, level, raw) {
19064       return '<h'
19065         + level
19066         + ' id="'
19067         + this.options.headerPrefix
19068         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19069         + '">'
19070         + text
19071         + '</h'
19072         + level
19073         + '>\n';
19074     };
19075     
19076     Renderer.prototype.hr = function() {
19077       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19078     };
19079     
19080     Renderer.prototype.list = function(body, ordered) {
19081       var type = ordered ? 'ol' : 'ul';
19082       return '<' + type + '>\n' + body + '</' + type + '>\n';
19083     };
19084     
19085     Renderer.prototype.listitem = function(text) {
19086       return '<li>' + text + '</li>\n';
19087     };
19088     
19089     Renderer.prototype.paragraph = function(text) {
19090       return '<p>' + text + '</p>\n';
19091     };
19092     
19093     Renderer.prototype.table = function(header, body) {
19094       return '<table class="table table-striped">\n'
19095         + '<thead>\n'
19096         + header
19097         + '</thead>\n'
19098         + '<tbody>\n'
19099         + body
19100         + '</tbody>\n'
19101         + '</table>\n';
19102     };
19103     
19104     Renderer.prototype.tablerow = function(content) {
19105       return '<tr>\n' + content + '</tr>\n';
19106     };
19107     
19108     Renderer.prototype.tablecell = function(content, flags) {
19109       var type = flags.header ? 'th' : 'td';
19110       var tag = flags.align
19111         ? '<' + type + ' style="text-align:' + flags.align + '">'
19112         : '<' + type + '>';
19113       return tag + content + '</' + type + '>\n';
19114     };
19115     
19116     // span level renderer
19117     Renderer.prototype.strong = function(text) {
19118       return '<strong>' + text + '</strong>';
19119     };
19120     
19121     Renderer.prototype.em = function(text) {
19122       return '<em>' + text + '</em>';
19123     };
19124     
19125     Renderer.prototype.codespan = function(text) {
19126       return '<code>' + text + '</code>';
19127     };
19128     
19129     Renderer.prototype.br = function() {
19130       return this.options.xhtml ? '<br/>' : '<br>';
19131     };
19132     
19133     Renderer.prototype.del = function(text) {
19134       return '<del>' + text + '</del>';
19135     };
19136     
19137     Renderer.prototype.link = function(href, title, text) {
19138       if (this.options.sanitize) {
19139         try {
19140           var prot = decodeURIComponent(unescape(href))
19141             .replace(/[^\w:]/g, '')
19142             .toLowerCase();
19143         } catch (e) {
19144           return '';
19145         }
19146         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19147           return '';
19148         }
19149       }
19150       var out = '<a href="' + href + '"';
19151       if (title) {
19152         out += ' title="' + title + '"';
19153       }
19154       out += '>' + text + '</a>';
19155       return out;
19156     };
19157     
19158     Renderer.prototype.image = function(href, title, text) {
19159       var out = '<img src="' + href + '" alt="' + text + '"';
19160       if (title) {
19161         out += ' title="' + title + '"';
19162       }
19163       out += this.options.xhtml ? '/>' : '>';
19164       return out;
19165     };
19166     
19167     Renderer.prototype.text = function(text) {
19168       return text;
19169     };
19170     
19171     /**
19172      * Parsing & Compiling
19173      */
19174          /**
19175          * eval:var:Parser
19176     */
19177     
19178     var Parser= function (options) {
19179       this.tokens = [];
19180       this.token = null;
19181       this.options = options || marked.defaults;
19182       this.options.renderer = this.options.renderer || new Renderer;
19183       this.renderer = this.options.renderer;
19184       this.renderer.options = this.options;
19185     }
19186     
19187     /**
19188      * Static Parse Method
19189      */
19190     
19191     Parser.parse = function(src, options, renderer) {
19192       var parser = new Parser(options, renderer);
19193       return parser.parse(src);
19194     };
19195     
19196     /**
19197      * Parse Loop
19198      */
19199     
19200     Parser.prototype.parse = function(src) {
19201       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19202       this.tokens = src.reverse();
19203     
19204       var out = '';
19205       while (this.next()) {
19206         out += this.tok();
19207       }
19208     
19209       return out;
19210     };
19211     
19212     /**
19213      * Next Token
19214      */
19215     
19216     Parser.prototype.next = function() {
19217       return this.token = this.tokens.pop();
19218     };
19219     
19220     /**
19221      * Preview Next Token
19222      */
19223     
19224     Parser.prototype.peek = function() {
19225       return this.tokens[this.tokens.length - 1] || 0;
19226     };
19227     
19228     /**
19229      * Parse Text Tokens
19230      */
19231     
19232     Parser.prototype.parseText = function() {
19233       var body = this.token.text;
19234     
19235       while (this.peek().type === 'text') {
19236         body += '\n' + this.next().text;
19237       }
19238     
19239       return this.inline.output(body);
19240     };
19241     
19242     /**
19243      * Parse Current Token
19244      */
19245     
19246     Parser.prototype.tok = function() {
19247       switch (this.token.type) {
19248         case 'space': {
19249           return '';
19250         }
19251         case 'hr': {
19252           return this.renderer.hr();
19253         }
19254         case 'heading': {
19255           return this.renderer.heading(
19256             this.inline.output(this.token.text),
19257             this.token.depth,
19258             this.token.text);
19259         }
19260         case 'code': {
19261           return this.renderer.code(this.token.text,
19262             this.token.lang,
19263             this.token.escaped);
19264         }
19265         case 'table': {
19266           var header = ''
19267             , body = ''
19268             , i
19269             , row
19270             , cell
19271             , flags
19272             , j;
19273     
19274           // header
19275           cell = '';
19276           for (i = 0; i < this.token.header.length; i++) {
19277             flags = { header: true, align: this.token.align[i] };
19278             cell += this.renderer.tablecell(
19279               this.inline.output(this.token.header[i]),
19280               { header: true, align: this.token.align[i] }
19281             );
19282           }
19283           header += this.renderer.tablerow(cell);
19284     
19285           for (i = 0; i < this.token.cells.length; i++) {
19286             row = this.token.cells[i];
19287     
19288             cell = '';
19289             for (j = 0; j < row.length; j++) {
19290               cell += this.renderer.tablecell(
19291                 this.inline.output(row[j]),
19292                 { header: false, align: this.token.align[j] }
19293               );
19294             }
19295     
19296             body += this.renderer.tablerow(cell);
19297           }
19298           return this.renderer.table(header, body);
19299         }
19300         case 'blockquote_start': {
19301           var body = '';
19302     
19303           while (this.next().type !== 'blockquote_end') {
19304             body += this.tok();
19305           }
19306     
19307           return this.renderer.blockquote(body);
19308         }
19309         case 'list_start': {
19310           var body = ''
19311             , ordered = this.token.ordered;
19312     
19313           while (this.next().type !== 'list_end') {
19314             body += this.tok();
19315           }
19316     
19317           return this.renderer.list(body, ordered);
19318         }
19319         case 'list_item_start': {
19320           var body = '';
19321     
19322           while (this.next().type !== 'list_item_end') {
19323             body += this.token.type === 'text'
19324               ? this.parseText()
19325               : this.tok();
19326           }
19327     
19328           return this.renderer.listitem(body);
19329         }
19330         case 'loose_item_start': {
19331           var body = '';
19332     
19333           while (this.next().type !== 'list_item_end') {
19334             body += this.tok();
19335           }
19336     
19337           return this.renderer.listitem(body);
19338         }
19339         case 'html': {
19340           var html = !this.token.pre && !this.options.pedantic
19341             ? this.inline.output(this.token.text)
19342             : this.token.text;
19343           return this.renderer.html(html);
19344         }
19345         case 'paragraph': {
19346           return this.renderer.paragraph(this.inline.output(this.token.text));
19347         }
19348         case 'text': {
19349           return this.renderer.paragraph(this.parseText());
19350         }
19351       }
19352     };
19353   
19354     
19355     /**
19356      * Marked
19357      */
19358          /**
19359          * eval:var:marked
19360     */
19361     var marked = function (src, opt, callback) {
19362       if (callback || typeof opt === 'function') {
19363         if (!callback) {
19364           callback = opt;
19365           opt = null;
19366         }
19367     
19368         opt = merge({}, marked.defaults, opt || {});
19369     
19370         var highlight = opt.highlight
19371           , tokens
19372           , pending
19373           , i = 0;
19374     
19375         try {
19376           tokens = Lexer.lex(src, opt)
19377         } catch (e) {
19378           return callback(e);
19379         }
19380     
19381         pending = tokens.length;
19382          /**
19383          * eval:var:done
19384     */
19385         var done = function(err) {
19386           if (err) {
19387             opt.highlight = highlight;
19388             return callback(err);
19389           }
19390     
19391           var out;
19392     
19393           try {
19394             out = Parser.parse(tokens, opt);
19395           } catch (e) {
19396             err = e;
19397           }
19398     
19399           opt.highlight = highlight;
19400     
19401           return err
19402             ? callback(err)
19403             : callback(null, out);
19404         };
19405     
19406         if (!highlight || highlight.length < 3) {
19407           return done();
19408         }
19409     
19410         delete opt.highlight;
19411     
19412         if (!pending) { return done(); }
19413     
19414         for (; i < tokens.length; i++) {
19415           (function(token) {
19416             if (token.type !== 'code') {
19417               return --pending || done();
19418             }
19419             return highlight(token.text, token.lang, function(err, code) {
19420               if (err) { return done(err); }
19421               if (code == null || code === token.text) {
19422                 return --pending || done();
19423               }
19424               token.text = code;
19425               token.escaped = true;
19426               --pending || done();
19427             });
19428           })(tokens[i]);
19429         }
19430     
19431         return;
19432       }
19433       try {
19434         if (opt) { opt = merge({}, marked.defaults, opt); }
19435         return Parser.parse(Lexer.lex(src, opt), opt);
19436       } catch (e) {
19437         e.message += '\nPlease report this to https://github.com/chjj/marked.';
19438         if ((opt || marked.defaults).silent) {
19439           return '<p>An error occured:</p><pre>'
19440             + escape(e.message + '', true)
19441             + '</pre>';
19442         }
19443         throw e;
19444       }
19445     }
19446     
19447     /**
19448      * Options
19449      */
19450     
19451     marked.options =
19452     marked.setOptions = function(opt) {
19453       merge(marked.defaults, opt);
19454       return marked;
19455     };
19456     
19457     marked.defaults = {
19458       gfm: true,
19459       tables: true,
19460       breaks: false,
19461       pedantic: false,
19462       sanitize: false,
19463       sanitizer: null,
19464       mangle: true,
19465       smartLists: false,
19466       silent: false,
19467       highlight: null,
19468       langPrefix: 'lang-',
19469       smartypants: false,
19470       headerPrefix: '',
19471       renderer: new Renderer,
19472       xhtml: false
19473     };
19474     
19475     /**
19476      * Expose
19477      */
19478     
19479     marked.Parser = Parser;
19480     marked.parser = Parser.parse;
19481     
19482     marked.Renderer = Renderer;
19483     
19484     marked.Lexer = Lexer;
19485     marked.lexer = Lexer.lex;
19486     
19487     marked.InlineLexer = InlineLexer;
19488     marked.inlineLexer = InlineLexer.output;
19489     
19490     marked.parse = marked;
19491     
19492     Roo.Markdown.marked = marked;
19493
19494 })();/*
19495  * Based on:
19496  * Ext JS Library 1.1.1
19497  * Copyright(c) 2006-2007, Ext JS, LLC.
19498  *
19499  * Originally Released Under LGPL - original licence link has changed is not relivant.
19500  *
19501  * Fork - LGPL
19502  * <script type="text/javascript">
19503  */
19504
19505
19506
19507 /*
19508  * These classes are derivatives of the similarly named classes in the YUI Library.
19509  * The original license:
19510  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19511  * Code licensed under the BSD License:
19512  * http://developer.yahoo.net/yui/license.txt
19513  */
19514
19515 (function() {
19516
19517 var Event=Roo.EventManager;
19518 var Dom=Roo.lib.Dom;
19519
19520 /**
19521  * @class Roo.dd.DragDrop
19522  * @extends Roo.util.Observable
19523  * Defines the interface and base operation of items that that can be
19524  * dragged or can be drop targets.  It was designed to be extended, overriding
19525  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19526  * Up to three html elements can be associated with a DragDrop instance:
19527  * <ul>
19528  * <li>linked element: the element that is passed into the constructor.
19529  * This is the element which defines the boundaries for interaction with
19530  * other DragDrop objects.</li>
19531  * <li>handle element(s): The drag operation only occurs if the element that
19532  * was clicked matches a handle element.  By default this is the linked
19533  * element, but there are times that you will want only a portion of the
19534  * linked element to initiate the drag operation, and the setHandleElId()
19535  * method provides a way to define this.</li>
19536  * <li>drag element: this represents the element that would be moved along
19537  * with the cursor during a drag operation.  By default, this is the linked
19538  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
19539  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19540  * </li>
19541  * </ul>
19542  * This class should not be instantiated until the onload event to ensure that
19543  * the associated elements are available.
19544  * The following would define a DragDrop obj that would interact with any
19545  * other DragDrop obj in the "group1" group:
19546  * <pre>
19547  *  dd = new Roo.dd.DragDrop("div1", "group1");
19548  * </pre>
19549  * Since none of the event handlers have been implemented, nothing would
19550  * actually happen if you were to run the code above.  Normally you would
19551  * override this class or one of the default implementations, but you can
19552  * also override the methods you want on an instance of the class...
19553  * <pre>
19554  *  dd.onDragDrop = function(e, id) {
19555  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
19556  *  }
19557  * </pre>
19558  * @constructor
19559  * @param {String} id of the element that is linked to this instance
19560  * @param {String} sGroup the group of related DragDrop objects
19561  * @param {object} config an object containing configurable attributes
19562  *                Valid properties for DragDrop:
19563  *                    padding, isTarget, maintainOffset, primaryButtonOnly
19564  */
19565 Roo.dd.DragDrop = function(id, sGroup, config) {
19566     if (id) {
19567         this.init(id, sGroup, config);
19568     }
19569     
19570 };
19571
19572 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19573
19574     /**
19575      * The id of the element associated with this object.  This is what we
19576      * refer to as the "linked element" because the size and position of
19577      * this element is used to determine when the drag and drop objects have
19578      * interacted.
19579      * @property id
19580      * @type String
19581      */
19582     id: null,
19583
19584     /**
19585      * Configuration attributes passed into the constructor
19586      * @property config
19587      * @type object
19588      */
19589     config: null,
19590
19591     /**
19592      * The id of the element that will be dragged.  By default this is same
19593      * as the linked element , but could be changed to another element. Ex:
19594      * Roo.dd.DDProxy
19595      * @property dragElId
19596      * @type String
19597      * @private
19598      */
19599     dragElId: null,
19600
19601     /**
19602      * the id of the element that initiates the drag operation.  By default
19603      * this is the linked element, but could be changed to be a child of this
19604      * element.  This lets us do things like only starting the drag when the
19605      * header element within the linked html element is clicked.
19606      * @property handleElId
19607      * @type String
19608      * @private
19609      */
19610     handleElId: null,
19611
19612     /**
19613      * An associative array of HTML tags that will be ignored if clicked.
19614      * @property invalidHandleTypes
19615      * @type {string: string}
19616      */
19617     invalidHandleTypes: null,
19618
19619     /**
19620      * An associative array of ids for elements that will be ignored if clicked
19621      * @property invalidHandleIds
19622      * @type {string: string}
19623      */
19624     invalidHandleIds: null,
19625
19626     /**
19627      * An indexted array of css class names for elements that will be ignored
19628      * if clicked.
19629      * @property invalidHandleClasses
19630      * @type string[]
19631      */
19632     invalidHandleClasses: null,
19633
19634     /**
19635      * The linked element's absolute X position at the time the drag was
19636      * started
19637      * @property startPageX
19638      * @type int
19639      * @private
19640      */
19641     startPageX: 0,
19642
19643     /**
19644      * The linked element's absolute X position at the time the drag was
19645      * started
19646      * @property startPageY
19647      * @type int
19648      * @private
19649      */
19650     startPageY: 0,
19651
19652     /**
19653      * The group defines a logical collection of DragDrop objects that are
19654      * related.  Instances only get events when interacting with other
19655      * DragDrop object in the same group.  This lets us define multiple
19656      * groups using a single DragDrop subclass if we want.
19657      * @property groups
19658      * @type {string: string}
19659      */
19660     groups: null,
19661
19662     /**
19663      * Individual drag/drop instances can be locked.  This will prevent
19664      * onmousedown start drag.
19665      * @property locked
19666      * @type boolean
19667      * @private
19668      */
19669     locked: false,
19670
19671     /**
19672      * Lock this instance
19673      * @method lock
19674      */
19675     lock: function() { this.locked = true; },
19676
19677     /**
19678      * Unlock this instace
19679      * @method unlock
19680      */
19681     unlock: function() { this.locked = false; },
19682
19683     /**
19684      * By default, all insances can be a drop target.  This can be disabled by
19685      * setting isTarget to false.
19686      * @method isTarget
19687      * @type boolean
19688      */
19689     isTarget: true,
19690
19691     /**
19692      * The padding configured for this drag and drop object for calculating
19693      * the drop zone intersection with this object.
19694      * @method padding
19695      * @type int[]
19696      */
19697     padding: null,
19698
19699     /**
19700      * Cached reference to the linked element
19701      * @property _domRef
19702      * @private
19703      */
19704     _domRef: null,
19705
19706     /**
19707      * Internal typeof flag
19708      * @property __ygDragDrop
19709      * @private
19710      */
19711     __ygDragDrop: true,
19712
19713     /**
19714      * Set to true when horizontal contraints are applied
19715      * @property constrainX
19716      * @type boolean
19717      * @private
19718      */
19719     constrainX: false,
19720
19721     /**
19722      * Set to true when vertical contraints are applied
19723      * @property constrainY
19724      * @type boolean
19725      * @private
19726      */
19727     constrainY: false,
19728
19729     /**
19730      * The left constraint
19731      * @property minX
19732      * @type int
19733      * @private
19734      */
19735     minX: 0,
19736
19737     /**
19738      * The right constraint
19739      * @property maxX
19740      * @type int
19741      * @private
19742      */
19743     maxX: 0,
19744
19745     /**
19746      * The up constraint
19747      * @property minY
19748      * @type int
19749      * @type int
19750      * @private
19751      */
19752     minY: 0,
19753
19754     /**
19755      * The down constraint
19756      * @property maxY
19757      * @type int
19758      * @private
19759      */
19760     maxY: 0,
19761
19762     /**
19763      * Maintain offsets when we resetconstraints.  Set to true when you want
19764      * the position of the element relative to its parent to stay the same
19765      * when the page changes
19766      *
19767      * @property maintainOffset
19768      * @type boolean
19769      */
19770     maintainOffset: false,
19771
19772     /**
19773      * Array of pixel locations the element will snap to if we specified a
19774      * horizontal graduation/interval.  This array is generated automatically
19775      * when you define a tick interval.
19776      * @property xTicks
19777      * @type int[]
19778      */
19779     xTicks: null,
19780
19781     /**
19782      * Array of pixel locations the element will snap to if we specified a
19783      * vertical graduation/interval.  This array is generated automatically
19784      * when you define a tick interval.
19785      * @property yTicks
19786      * @type int[]
19787      */
19788     yTicks: null,
19789
19790     /**
19791      * By default the drag and drop instance will only respond to the primary
19792      * button click (left button for a right-handed mouse).  Set to true to
19793      * allow drag and drop to start with any mouse click that is propogated
19794      * by the browser
19795      * @property primaryButtonOnly
19796      * @type boolean
19797      */
19798     primaryButtonOnly: true,
19799
19800     /**
19801      * The availabe property is false until the linked dom element is accessible.
19802      * @property available
19803      * @type boolean
19804      */
19805     available: false,
19806
19807     /**
19808      * By default, drags can only be initiated if the mousedown occurs in the
19809      * region the linked element is.  This is done in part to work around a
19810      * bug in some browsers that mis-report the mousedown if the previous
19811      * mouseup happened outside of the window.  This property is set to true
19812      * if outer handles are defined.
19813      *
19814      * @property hasOuterHandles
19815      * @type boolean
19816      * @default false
19817      */
19818     hasOuterHandles: false,
19819
19820     /**
19821      * Code that executes immediately before the startDrag event
19822      * @method b4StartDrag
19823      * @private
19824      */
19825     b4StartDrag: function(x, y) { },
19826
19827     /**
19828      * Abstract method called after a drag/drop object is clicked
19829      * and the drag or mousedown time thresholds have beeen met.
19830      * @method startDrag
19831      * @param {int} X click location
19832      * @param {int} Y click location
19833      */
19834     startDrag: function(x, y) { /* override this */ },
19835
19836     /**
19837      * Code that executes immediately before the onDrag event
19838      * @method b4Drag
19839      * @private
19840      */
19841     b4Drag: function(e) { },
19842
19843     /**
19844      * Abstract method called during the onMouseMove event while dragging an
19845      * object.
19846      * @method onDrag
19847      * @param {Event} e the mousemove event
19848      */
19849     onDrag: function(e) { /* override this */ },
19850
19851     /**
19852      * Abstract method called when this element fist begins hovering over
19853      * another DragDrop obj
19854      * @method onDragEnter
19855      * @param {Event} e the mousemove event
19856      * @param {String|DragDrop[]} id In POINT mode, the element
19857      * id this is hovering over.  In INTERSECT mode, an array of one or more
19858      * dragdrop items being hovered over.
19859      */
19860     onDragEnter: function(e, id) { /* override this */ },
19861
19862     /**
19863      * Code that executes immediately before the onDragOver event
19864      * @method b4DragOver
19865      * @private
19866      */
19867     b4DragOver: function(e) { },
19868
19869     /**
19870      * Abstract method called when this element is hovering over another
19871      * DragDrop obj
19872      * @method onDragOver
19873      * @param {Event} e the mousemove event
19874      * @param {String|DragDrop[]} id In POINT mode, the element
19875      * id this is hovering over.  In INTERSECT mode, an array of dd items
19876      * being hovered over.
19877      */
19878     onDragOver: function(e, id) { /* override this */ },
19879
19880     /**
19881      * Code that executes immediately before the onDragOut event
19882      * @method b4DragOut
19883      * @private
19884      */
19885     b4DragOut: function(e) { },
19886
19887     /**
19888      * Abstract method called when we are no longer hovering over an element
19889      * @method onDragOut
19890      * @param {Event} e the mousemove event
19891      * @param {String|DragDrop[]} id In POINT mode, the element
19892      * id this was hovering over.  In INTERSECT mode, an array of dd items
19893      * that the mouse is no longer over.
19894      */
19895     onDragOut: function(e, id) { /* override this */ },
19896
19897     /**
19898      * Code that executes immediately before the onDragDrop event
19899      * @method b4DragDrop
19900      * @private
19901      */
19902     b4DragDrop: function(e) { },
19903
19904     /**
19905      * Abstract method called when this item is dropped on another DragDrop
19906      * obj
19907      * @method onDragDrop
19908      * @param {Event} e the mouseup event
19909      * @param {String|DragDrop[]} id In POINT mode, the element
19910      * id this was dropped on.  In INTERSECT mode, an array of dd items this
19911      * was dropped on.
19912      */
19913     onDragDrop: function(e, id) { /* override this */ },
19914
19915     /**
19916      * Abstract method called when this item is dropped on an area with no
19917      * drop target
19918      * @method onInvalidDrop
19919      * @param {Event} e the mouseup event
19920      */
19921     onInvalidDrop: function(e) { /* override this */ },
19922
19923     /**
19924      * Code that executes immediately before the endDrag event
19925      * @method b4EndDrag
19926      * @private
19927      */
19928     b4EndDrag: function(e) { },
19929
19930     /**
19931      * Fired when we are done dragging the object
19932      * @method endDrag
19933      * @param {Event} e the mouseup event
19934      */
19935     endDrag: function(e) { /* override this */ },
19936
19937     /**
19938      * Code executed immediately before the onMouseDown event
19939      * @method b4MouseDown
19940      * @param {Event} e the mousedown event
19941      * @private
19942      */
19943     b4MouseDown: function(e) {  },
19944
19945     /**
19946      * Event handler that fires when a drag/drop obj gets a mousedown
19947      * @method onMouseDown
19948      * @param {Event} e the mousedown event
19949      */
19950     onMouseDown: function(e) { /* override this */ },
19951
19952     /**
19953      * Event handler that fires when a drag/drop obj gets a mouseup
19954      * @method onMouseUp
19955      * @param {Event} e the mouseup event
19956      */
19957     onMouseUp: function(e) { /* override this */ },
19958
19959     /**
19960      * Override the onAvailable method to do what is needed after the initial
19961      * position was determined.
19962      * @method onAvailable
19963      */
19964     onAvailable: function () {
19965     },
19966
19967     /*
19968      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19969      * @type Object
19970      */
19971     defaultPadding : {left:0, right:0, top:0, bottom:0},
19972
19973     /*
19974      * Initializes the drag drop object's constraints to restrict movement to a certain element.
19975  *
19976  * Usage:
19977  <pre><code>
19978  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19979                 { dragElId: "existingProxyDiv" });
19980  dd.startDrag = function(){
19981      this.constrainTo("parent-id");
19982  };
19983  </code></pre>
19984  * Or you can initalize it using the {@link Roo.Element} object:
19985  <pre><code>
19986  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19987      startDrag : function(){
19988          this.constrainTo("parent-id");
19989      }
19990  });
19991  </code></pre>
19992      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19993      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19994      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19995      * an object containing the sides to pad. For example: {right:10, bottom:10}
19996      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19997      */
19998     constrainTo : function(constrainTo, pad, inContent){
19999         if(typeof pad == "number"){
20000             pad = {left: pad, right:pad, top:pad, bottom:pad};
20001         }
20002         pad = pad || this.defaultPadding;
20003         var b = Roo.get(this.getEl()).getBox();
20004         var ce = Roo.get(constrainTo);
20005         var s = ce.getScroll();
20006         var c, cd = ce.dom;
20007         if(cd == document.body){
20008             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20009         }else{
20010             xy = ce.getXY();
20011             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20012         }
20013
20014
20015         var topSpace = b.y - c.y;
20016         var leftSpace = b.x - c.x;
20017
20018         this.resetConstraints();
20019         this.setXConstraint(leftSpace - (pad.left||0), // left
20020                 c.width - leftSpace - b.width - (pad.right||0) //right
20021         );
20022         this.setYConstraint(topSpace - (pad.top||0), //top
20023                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20024         );
20025     },
20026
20027     /**
20028      * Returns a reference to the linked element
20029      * @method getEl
20030      * @return {HTMLElement} the html element
20031      */
20032     getEl: function() {
20033         if (!this._domRef) {
20034             this._domRef = Roo.getDom(this.id);
20035         }
20036
20037         return this._domRef;
20038     },
20039
20040     /**
20041      * Returns a reference to the actual element to drag.  By default this is
20042      * the same as the html element, but it can be assigned to another
20043      * element. An example of this can be found in Roo.dd.DDProxy
20044      * @method getDragEl
20045      * @return {HTMLElement} the html element
20046      */
20047     getDragEl: function() {
20048         return Roo.getDom(this.dragElId);
20049     },
20050
20051     /**
20052      * Sets up the DragDrop object.  Must be called in the constructor of any
20053      * Roo.dd.DragDrop subclass
20054      * @method init
20055      * @param id the id of the linked element
20056      * @param {String} sGroup the group of related items
20057      * @param {object} config configuration attributes
20058      */
20059     init: function(id, sGroup, config) {
20060         this.initTarget(id, sGroup, config);
20061         if (!Roo.isTouch) {
20062             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20063         }
20064         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20065         // Event.on(this.id, "selectstart", Event.preventDefault);
20066     },
20067
20068     /**
20069      * Initializes Targeting functionality only... the object does not
20070      * get a mousedown handler.
20071      * @method initTarget
20072      * @param id the id of the linked element
20073      * @param {String} sGroup the group of related items
20074      * @param {object} config configuration attributes
20075      */
20076     initTarget: function(id, sGroup, config) {
20077
20078         // configuration attributes
20079         this.config = config || {};
20080
20081         // create a local reference to the drag and drop manager
20082         this.DDM = Roo.dd.DDM;
20083         // initialize the groups array
20084         this.groups = {};
20085
20086         // assume that we have an element reference instead of an id if the
20087         // parameter is not a string
20088         if (typeof id !== "string") {
20089             id = Roo.id(id);
20090         }
20091
20092         // set the id
20093         this.id = id;
20094
20095         // add to an interaction group
20096         this.addToGroup((sGroup) ? sGroup : "default");
20097
20098         // We don't want to register this as the handle with the manager
20099         // so we just set the id rather than calling the setter.
20100         this.handleElId = id;
20101
20102         // the linked element is the element that gets dragged by default
20103         this.setDragElId(id);
20104
20105         // by default, clicked anchors will not start drag operations.
20106         this.invalidHandleTypes = { A: "A" };
20107         this.invalidHandleIds = {};
20108         this.invalidHandleClasses = [];
20109
20110         this.applyConfig();
20111
20112         this.handleOnAvailable();
20113     },
20114
20115     /**
20116      * Applies the configuration parameters that were passed into the constructor.
20117      * This is supposed to happen at each level through the inheritance chain.  So
20118      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20119      * DragDrop in order to get all of the parameters that are available in
20120      * each object.
20121      * @method applyConfig
20122      */
20123     applyConfig: function() {
20124
20125         // configurable properties:
20126         //    padding, isTarget, maintainOffset, primaryButtonOnly
20127         this.padding           = this.config.padding || [0, 0, 0, 0];
20128         this.isTarget          = (this.config.isTarget !== false);
20129         this.maintainOffset    = (this.config.maintainOffset);
20130         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20131
20132     },
20133
20134     /**
20135      * Executed when the linked element is available
20136      * @method handleOnAvailable
20137      * @private
20138      */
20139     handleOnAvailable: function() {
20140         this.available = true;
20141         this.resetConstraints();
20142         this.onAvailable();
20143     },
20144
20145      /**
20146      * Configures the padding for the target zone in px.  Effectively expands
20147      * (or reduces) the virtual object size for targeting calculations.
20148      * Supports css-style shorthand; if only one parameter is passed, all sides
20149      * will have that padding, and if only two are passed, the top and bottom
20150      * will have the first param, the left and right the second.
20151      * @method setPadding
20152      * @param {int} iTop    Top pad
20153      * @param {int} iRight  Right pad
20154      * @param {int} iBot    Bot pad
20155      * @param {int} iLeft   Left pad
20156      */
20157     setPadding: function(iTop, iRight, iBot, iLeft) {
20158         // this.padding = [iLeft, iRight, iTop, iBot];
20159         if (!iRight && 0 !== iRight) {
20160             this.padding = [iTop, iTop, iTop, iTop];
20161         } else if (!iBot && 0 !== iBot) {
20162             this.padding = [iTop, iRight, iTop, iRight];
20163         } else {
20164             this.padding = [iTop, iRight, iBot, iLeft];
20165         }
20166     },
20167
20168     /**
20169      * Stores the initial placement of the linked element.
20170      * @method setInitialPosition
20171      * @param {int} diffX   the X offset, default 0
20172      * @param {int} diffY   the Y offset, default 0
20173      */
20174     setInitPosition: function(diffX, diffY) {
20175         var el = this.getEl();
20176
20177         if (!this.DDM.verifyEl(el)) {
20178             return;
20179         }
20180
20181         var dx = diffX || 0;
20182         var dy = diffY || 0;
20183
20184         var p = Dom.getXY( el );
20185
20186         this.initPageX = p[0] - dx;
20187         this.initPageY = p[1] - dy;
20188
20189         this.lastPageX = p[0];
20190         this.lastPageY = p[1];
20191
20192
20193         this.setStartPosition(p);
20194     },
20195
20196     /**
20197      * Sets the start position of the element.  This is set when the obj
20198      * is initialized, the reset when a drag is started.
20199      * @method setStartPosition
20200      * @param pos current position (from previous lookup)
20201      * @private
20202      */
20203     setStartPosition: function(pos) {
20204         var p = pos || Dom.getXY( this.getEl() );
20205         this.deltaSetXY = null;
20206
20207         this.startPageX = p[0];
20208         this.startPageY = p[1];
20209     },
20210
20211     /**
20212      * Add this instance to a group of related drag/drop objects.  All
20213      * instances belong to at least one group, and can belong to as many
20214      * groups as needed.
20215      * @method addToGroup
20216      * @param sGroup {string} the name of the group
20217      */
20218     addToGroup: function(sGroup) {
20219         this.groups[sGroup] = true;
20220         this.DDM.regDragDrop(this, sGroup);
20221     },
20222
20223     /**
20224      * Remove's this instance from the supplied interaction group
20225      * @method removeFromGroup
20226      * @param {string}  sGroup  The group to drop
20227      */
20228     removeFromGroup: function(sGroup) {
20229         if (this.groups[sGroup]) {
20230             delete this.groups[sGroup];
20231         }
20232
20233         this.DDM.removeDDFromGroup(this, sGroup);
20234     },
20235
20236     /**
20237      * Allows you to specify that an element other than the linked element
20238      * will be moved with the cursor during a drag
20239      * @method setDragElId
20240      * @param id {string} the id of the element that will be used to initiate the drag
20241      */
20242     setDragElId: function(id) {
20243         this.dragElId = id;
20244     },
20245
20246     /**
20247      * Allows you to specify a child of the linked element that should be
20248      * used to initiate the drag operation.  An example of this would be if
20249      * you have a content div with text and links.  Clicking anywhere in the
20250      * content area would normally start the drag operation.  Use this method
20251      * to specify that an element inside of the content div is the element
20252      * that starts the drag operation.
20253      * @method setHandleElId
20254      * @param id {string} the id of the element that will be used to
20255      * initiate the drag.
20256      */
20257     setHandleElId: function(id) {
20258         if (typeof id !== "string") {
20259             id = Roo.id(id);
20260         }
20261         this.handleElId = id;
20262         this.DDM.regHandle(this.id, id);
20263     },
20264
20265     /**
20266      * Allows you to set an element outside of the linked element as a drag
20267      * handle
20268      * @method setOuterHandleElId
20269      * @param id the id of the element that will be used to initiate the drag
20270      */
20271     setOuterHandleElId: function(id) {
20272         if (typeof id !== "string") {
20273             id = Roo.id(id);
20274         }
20275         Event.on(id, "mousedown",
20276                 this.handleMouseDown, this);
20277         this.setHandleElId(id);
20278
20279         this.hasOuterHandles = true;
20280     },
20281
20282     /**
20283      * Remove all drag and drop hooks for this element
20284      * @method unreg
20285      */
20286     unreg: function() {
20287         Event.un(this.id, "mousedown",
20288                 this.handleMouseDown);
20289         Event.un(this.id, "touchstart",
20290                 this.handleMouseDown);
20291         this._domRef = null;
20292         this.DDM._remove(this);
20293     },
20294
20295     destroy : function(){
20296         this.unreg();
20297     },
20298
20299     /**
20300      * Returns true if this instance is locked, or the drag drop mgr is locked
20301      * (meaning that all drag/drop is disabled on the page.)
20302      * @method isLocked
20303      * @return {boolean} true if this obj or all drag/drop is locked, else
20304      * false
20305      */
20306     isLocked: function() {
20307         return (this.DDM.isLocked() || this.locked);
20308     },
20309
20310     /**
20311      * Fired when this object is clicked
20312      * @method handleMouseDown
20313      * @param {Event} e
20314      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20315      * @private
20316      */
20317     handleMouseDown: function(e, oDD){
20318      
20319         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20320             //Roo.log('not touch/ button !=0');
20321             return;
20322         }
20323         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20324             return; // double touch..
20325         }
20326         
20327
20328         if (this.isLocked()) {
20329             //Roo.log('locked');
20330             return;
20331         }
20332
20333         this.DDM.refreshCache(this.groups);
20334 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20335         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20336         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20337             //Roo.log('no outer handes or not over target');
20338                 // do nothing.
20339         } else {
20340 //            Roo.log('check validator');
20341             if (this.clickValidator(e)) {
20342 //                Roo.log('validate success');
20343                 // set the initial element position
20344                 this.setStartPosition();
20345
20346
20347                 this.b4MouseDown(e);
20348                 this.onMouseDown(e);
20349
20350                 this.DDM.handleMouseDown(e, this);
20351
20352                 this.DDM.stopEvent(e);
20353             } else {
20354
20355
20356             }
20357         }
20358     },
20359
20360     clickValidator: function(e) {
20361         var target = e.getTarget();
20362         return ( this.isValidHandleChild(target) &&
20363                     (this.id == this.handleElId ||
20364                         this.DDM.handleWasClicked(target, this.id)) );
20365     },
20366
20367     /**
20368      * Allows you to specify a tag name that should not start a drag operation
20369      * when clicked.  This is designed to facilitate embedding links within a
20370      * drag handle that do something other than start the drag.
20371      * @method addInvalidHandleType
20372      * @param {string} tagName the type of element to exclude
20373      */
20374     addInvalidHandleType: function(tagName) {
20375         var type = tagName.toUpperCase();
20376         this.invalidHandleTypes[type] = type;
20377     },
20378
20379     /**
20380      * Lets you to specify an element id for a child of a drag handle
20381      * that should not initiate a drag
20382      * @method addInvalidHandleId
20383      * @param {string} id the element id of the element you wish to ignore
20384      */
20385     addInvalidHandleId: function(id) {
20386         if (typeof id !== "string") {
20387             id = Roo.id(id);
20388         }
20389         this.invalidHandleIds[id] = id;
20390     },
20391
20392     /**
20393      * Lets you specify a css class of elements that will not initiate a drag
20394      * @method addInvalidHandleClass
20395      * @param {string} cssClass the class of the elements you wish to ignore
20396      */
20397     addInvalidHandleClass: function(cssClass) {
20398         this.invalidHandleClasses.push(cssClass);
20399     },
20400
20401     /**
20402      * Unsets an excluded tag name set by addInvalidHandleType
20403      * @method removeInvalidHandleType
20404      * @param {string} tagName the type of element to unexclude
20405      */
20406     removeInvalidHandleType: function(tagName) {
20407         var type = tagName.toUpperCase();
20408         // this.invalidHandleTypes[type] = null;
20409         delete this.invalidHandleTypes[type];
20410     },
20411
20412     /**
20413      * Unsets an invalid handle id
20414      * @method removeInvalidHandleId
20415      * @param {string} id the id of the element to re-enable
20416      */
20417     removeInvalidHandleId: function(id) {
20418         if (typeof id !== "string") {
20419             id = Roo.id(id);
20420         }
20421         delete this.invalidHandleIds[id];
20422     },
20423
20424     /**
20425      * Unsets an invalid css class
20426      * @method removeInvalidHandleClass
20427      * @param {string} cssClass the class of the element(s) you wish to
20428      * re-enable
20429      */
20430     removeInvalidHandleClass: function(cssClass) {
20431         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20432             if (this.invalidHandleClasses[i] == cssClass) {
20433                 delete this.invalidHandleClasses[i];
20434             }
20435         }
20436     },
20437
20438     /**
20439      * Checks the tag exclusion list to see if this click should be ignored
20440      * @method isValidHandleChild
20441      * @param {HTMLElement} node the HTMLElement to evaluate
20442      * @return {boolean} true if this is a valid tag type, false if not
20443      */
20444     isValidHandleChild: function(node) {
20445
20446         var valid = true;
20447         // var n = (node.nodeName == "#text") ? node.parentNode : node;
20448         var nodeName;
20449         try {
20450             nodeName = node.nodeName.toUpperCase();
20451         } catch(e) {
20452             nodeName = node.nodeName;
20453         }
20454         valid = valid && !this.invalidHandleTypes[nodeName];
20455         valid = valid && !this.invalidHandleIds[node.id];
20456
20457         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20458             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20459         }
20460
20461
20462         return valid;
20463
20464     },
20465
20466     /**
20467      * Create the array of horizontal tick marks if an interval was specified
20468      * in setXConstraint().
20469      * @method setXTicks
20470      * @private
20471      */
20472     setXTicks: function(iStartX, iTickSize) {
20473         this.xTicks = [];
20474         this.xTickSize = iTickSize;
20475
20476         var tickMap = {};
20477
20478         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20479             if (!tickMap[i]) {
20480                 this.xTicks[this.xTicks.length] = i;
20481                 tickMap[i] = true;
20482             }
20483         }
20484
20485         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20486             if (!tickMap[i]) {
20487                 this.xTicks[this.xTicks.length] = i;
20488                 tickMap[i] = true;
20489             }
20490         }
20491
20492         this.xTicks.sort(this.DDM.numericSort) ;
20493     },
20494
20495     /**
20496      * Create the array of vertical tick marks if an interval was specified in
20497      * setYConstraint().
20498      * @method setYTicks
20499      * @private
20500      */
20501     setYTicks: function(iStartY, iTickSize) {
20502         this.yTicks = [];
20503         this.yTickSize = iTickSize;
20504
20505         var tickMap = {};
20506
20507         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20508             if (!tickMap[i]) {
20509                 this.yTicks[this.yTicks.length] = i;
20510                 tickMap[i] = true;
20511             }
20512         }
20513
20514         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20515             if (!tickMap[i]) {
20516                 this.yTicks[this.yTicks.length] = i;
20517                 tickMap[i] = true;
20518             }
20519         }
20520
20521         this.yTicks.sort(this.DDM.numericSort) ;
20522     },
20523
20524     /**
20525      * By default, the element can be dragged any place on the screen.  Use
20526      * this method to limit the horizontal travel of the element.  Pass in
20527      * 0,0 for the parameters if you want to lock the drag to the y axis.
20528      * @method setXConstraint
20529      * @param {int} iLeft the number of pixels the element can move to the left
20530      * @param {int} iRight the number of pixels the element can move to the
20531      * right
20532      * @param {int} iTickSize optional parameter for specifying that the
20533      * element
20534      * should move iTickSize pixels at a time.
20535      */
20536     setXConstraint: function(iLeft, iRight, iTickSize) {
20537         this.leftConstraint = iLeft;
20538         this.rightConstraint = iRight;
20539
20540         this.minX = this.initPageX - iLeft;
20541         this.maxX = this.initPageX + iRight;
20542         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20543
20544         this.constrainX = true;
20545     },
20546
20547     /**
20548      * Clears any constraints applied to this instance.  Also clears ticks
20549      * since they can't exist independent of a constraint at this time.
20550      * @method clearConstraints
20551      */
20552     clearConstraints: function() {
20553         this.constrainX = false;
20554         this.constrainY = false;
20555         this.clearTicks();
20556     },
20557
20558     /**
20559      * Clears any tick interval defined for this instance
20560      * @method clearTicks
20561      */
20562     clearTicks: function() {
20563         this.xTicks = null;
20564         this.yTicks = null;
20565         this.xTickSize = 0;
20566         this.yTickSize = 0;
20567     },
20568
20569     /**
20570      * By default, the element can be dragged any place on the screen.  Set
20571      * this to limit the vertical travel of the element.  Pass in 0,0 for the
20572      * parameters if you want to lock the drag to the x axis.
20573      * @method setYConstraint
20574      * @param {int} iUp the number of pixels the element can move up
20575      * @param {int} iDown the number of pixels the element can move down
20576      * @param {int} iTickSize optional parameter for specifying that the
20577      * element should move iTickSize pixels at a time.
20578      */
20579     setYConstraint: function(iUp, iDown, iTickSize) {
20580         this.topConstraint = iUp;
20581         this.bottomConstraint = iDown;
20582
20583         this.minY = this.initPageY - iUp;
20584         this.maxY = this.initPageY + iDown;
20585         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20586
20587         this.constrainY = true;
20588
20589     },
20590
20591     /**
20592      * resetConstraints must be called if you manually reposition a dd element.
20593      * @method resetConstraints
20594      * @param {boolean} maintainOffset
20595      */
20596     resetConstraints: function() {
20597
20598
20599         // Maintain offsets if necessary
20600         if (this.initPageX || this.initPageX === 0) {
20601             // figure out how much this thing has moved
20602             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20603             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20604
20605             this.setInitPosition(dx, dy);
20606
20607         // This is the first time we have detected the element's position
20608         } else {
20609             this.setInitPosition();
20610         }
20611
20612         if (this.constrainX) {
20613             this.setXConstraint( this.leftConstraint,
20614                                  this.rightConstraint,
20615                                  this.xTickSize        );
20616         }
20617
20618         if (this.constrainY) {
20619             this.setYConstraint( this.topConstraint,
20620                                  this.bottomConstraint,
20621                                  this.yTickSize         );
20622         }
20623     },
20624
20625     /**
20626      * Normally the drag element is moved pixel by pixel, but we can specify
20627      * that it move a number of pixels at a time.  This method resolves the
20628      * location when we have it set up like this.
20629      * @method getTick
20630      * @param {int} val where we want to place the object
20631      * @param {int[]} tickArray sorted array of valid points
20632      * @return {int} the closest tick
20633      * @private
20634      */
20635     getTick: function(val, tickArray) {
20636
20637         if (!tickArray) {
20638             // If tick interval is not defined, it is effectively 1 pixel,
20639             // so we return the value passed to us.
20640             return val;
20641         } else if (tickArray[0] >= val) {
20642             // The value is lower than the first tick, so we return the first
20643             // tick.
20644             return tickArray[0];
20645         } else {
20646             for (var i=0, len=tickArray.length; i<len; ++i) {
20647                 var next = i + 1;
20648                 if (tickArray[next] && tickArray[next] >= val) {
20649                     var diff1 = val - tickArray[i];
20650                     var diff2 = tickArray[next] - val;
20651                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20652                 }
20653             }
20654
20655             // The value is larger than the last tick, so we return the last
20656             // tick.
20657             return tickArray[tickArray.length - 1];
20658         }
20659     },
20660
20661     /**
20662      * toString method
20663      * @method toString
20664      * @return {string} string representation of the dd obj
20665      */
20666     toString: function() {
20667         return ("DragDrop " + this.id);
20668     }
20669
20670 });
20671
20672 })();
20673 /*
20674  * Based on:
20675  * Ext JS Library 1.1.1
20676  * Copyright(c) 2006-2007, Ext JS, LLC.
20677  *
20678  * Originally Released Under LGPL - original licence link has changed is not relivant.
20679  *
20680  * Fork - LGPL
20681  * <script type="text/javascript">
20682  */
20683
20684
20685 /**
20686  * The drag and drop utility provides a framework for building drag and drop
20687  * applications.  In addition to enabling drag and drop for specific elements,
20688  * the drag and drop elements are tracked by the manager class, and the
20689  * interactions between the various elements are tracked during the drag and
20690  * the implementing code is notified about these important moments.
20691  */
20692
20693 // Only load the library once.  Rewriting the manager class would orphan
20694 // existing drag and drop instances.
20695 if (!Roo.dd.DragDropMgr) {
20696
20697 /**
20698  * @class Roo.dd.DragDropMgr
20699  * DragDropMgr is a singleton that tracks the element interaction for
20700  * all DragDrop items in the window.  Generally, you will not call
20701  * this class directly, but it does have helper methods that could
20702  * be useful in your DragDrop implementations.
20703  * @static
20704  */
20705 Roo.dd.DragDropMgr = function() {
20706
20707     var Event = Roo.EventManager;
20708
20709     return {
20710
20711         /**
20712          * Two dimensional Array of registered DragDrop objects.  The first
20713          * dimension is the DragDrop item group, the second the DragDrop
20714          * object.
20715          * @property ids
20716          * @type {string: string}
20717          * @private
20718          * @static
20719          */
20720         ids: {},
20721
20722         /**
20723          * Array of element ids defined as drag handles.  Used to determine
20724          * if the element that generated the mousedown event is actually the
20725          * handle and not the html element itself.
20726          * @property handleIds
20727          * @type {string: string}
20728          * @private
20729          * @static
20730          */
20731         handleIds: {},
20732
20733         /**
20734          * the DragDrop object that is currently being dragged
20735          * @property dragCurrent
20736          * @type DragDrop
20737          * @private
20738          * @static
20739          **/
20740         dragCurrent: null,
20741
20742         /**
20743          * the DragDrop object(s) that are being hovered over
20744          * @property dragOvers
20745          * @type Array
20746          * @private
20747          * @static
20748          */
20749         dragOvers: {},
20750
20751         /**
20752          * the X distance between the cursor and the object being dragged
20753          * @property deltaX
20754          * @type int
20755          * @private
20756          * @static
20757          */
20758         deltaX: 0,
20759
20760         /**
20761          * the Y distance between the cursor and the object being dragged
20762          * @property deltaY
20763          * @type int
20764          * @private
20765          * @static
20766          */
20767         deltaY: 0,
20768
20769         /**
20770          * Flag to determine if we should prevent the default behavior of the
20771          * events we define. By default this is true, but this can be set to
20772          * false if you need the default behavior (not recommended)
20773          * @property preventDefault
20774          * @type boolean
20775          * @static
20776          */
20777         preventDefault: true,
20778
20779         /**
20780          * Flag to determine if we should stop the propagation of the events
20781          * we generate. This is true by default but you may want to set it to
20782          * false if the html element contains other features that require the
20783          * mouse click.
20784          * @property stopPropagation
20785          * @type boolean
20786          * @static
20787          */
20788         stopPropagation: true,
20789
20790         /**
20791          * Internal flag that is set to true when drag and drop has been
20792          * intialized
20793          * @property initialized
20794          * @private
20795          * @static
20796          */
20797         initalized: false,
20798
20799         /**
20800          * All drag and drop can be disabled.
20801          * @property locked
20802          * @private
20803          * @static
20804          */
20805         locked: false,
20806
20807         /**
20808          * Called the first time an element is registered.
20809          * @method init
20810          * @private
20811          * @static
20812          */
20813         init: function() {
20814             this.initialized = true;
20815         },
20816
20817         /**
20818          * In point mode, drag and drop interaction is defined by the
20819          * location of the cursor during the drag/drop
20820          * @property POINT
20821          * @type int
20822          * @static
20823          */
20824         POINT: 0,
20825
20826         /**
20827          * In intersect mode, drag and drop interactio nis defined by the
20828          * overlap of two or more drag and drop objects.
20829          * @property INTERSECT
20830          * @type int
20831          * @static
20832          */
20833         INTERSECT: 1,
20834
20835         /**
20836          * The current drag and drop mode.  Default: POINT
20837          * @property mode
20838          * @type int
20839          * @static
20840          */
20841         mode: 0,
20842
20843         /**
20844          * Runs method on all drag and drop objects
20845          * @method _execOnAll
20846          * @private
20847          * @static
20848          */
20849         _execOnAll: function(sMethod, args) {
20850             for (var i in this.ids) {
20851                 for (var j in this.ids[i]) {
20852                     var oDD = this.ids[i][j];
20853                     if (! this.isTypeOfDD(oDD)) {
20854                         continue;
20855                     }
20856                     oDD[sMethod].apply(oDD, args);
20857                 }
20858             }
20859         },
20860
20861         /**
20862          * Drag and drop initialization.  Sets up the global event handlers
20863          * @method _onLoad
20864          * @private
20865          * @static
20866          */
20867         _onLoad: function() {
20868
20869             this.init();
20870
20871             if (!Roo.isTouch) {
20872                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
20873                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20874             }
20875             Event.on(document, "touchend",   this.handleMouseUp, this, true);
20876             Event.on(document, "touchmove", this.handleMouseMove, this, true);
20877             
20878             Event.on(window,   "unload",    this._onUnload, this, true);
20879             Event.on(window,   "resize",    this._onResize, this, true);
20880             // Event.on(window,   "mouseout",    this._test);
20881
20882         },
20883
20884         /**
20885          * Reset constraints on all drag and drop objs
20886          * @method _onResize
20887          * @private
20888          * @static
20889          */
20890         _onResize: function(e) {
20891             this._execOnAll("resetConstraints", []);
20892         },
20893
20894         /**
20895          * Lock all drag and drop functionality
20896          * @method lock
20897          * @static
20898          */
20899         lock: function() { this.locked = true; },
20900
20901         /**
20902          * Unlock all drag and drop functionality
20903          * @method unlock
20904          * @static
20905          */
20906         unlock: function() { this.locked = false; },
20907
20908         /**
20909          * Is drag and drop locked?
20910          * @method isLocked
20911          * @return {boolean} True if drag and drop is locked, false otherwise.
20912          * @static
20913          */
20914         isLocked: function() { return this.locked; },
20915
20916         /**
20917          * Location cache that is set for all drag drop objects when a drag is
20918          * initiated, cleared when the drag is finished.
20919          * @property locationCache
20920          * @private
20921          * @static
20922          */
20923         locationCache: {},
20924
20925         /**
20926          * Set useCache to false if you want to force object the lookup of each
20927          * drag and drop linked element constantly during a drag.
20928          * @property useCache
20929          * @type boolean
20930          * @static
20931          */
20932         useCache: true,
20933
20934         /**
20935          * The number of pixels that the mouse needs to move after the
20936          * mousedown before the drag is initiated.  Default=3;
20937          * @property clickPixelThresh
20938          * @type int
20939          * @static
20940          */
20941         clickPixelThresh: 3,
20942
20943         /**
20944          * The number of milliseconds after the mousedown event to initiate the
20945          * drag if we don't get a mouseup event. Default=1000
20946          * @property clickTimeThresh
20947          * @type int
20948          * @static
20949          */
20950         clickTimeThresh: 350,
20951
20952         /**
20953          * Flag that indicates that either the drag pixel threshold or the
20954          * mousdown time threshold has been met
20955          * @property dragThreshMet
20956          * @type boolean
20957          * @private
20958          * @static
20959          */
20960         dragThreshMet: false,
20961
20962         /**
20963          * Timeout used for the click time threshold
20964          * @property clickTimeout
20965          * @type Object
20966          * @private
20967          * @static
20968          */
20969         clickTimeout: null,
20970
20971         /**
20972          * The X position of the mousedown event stored for later use when a
20973          * drag threshold is met.
20974          * @property startX
20975          * @type int
20976          * @private
20977          * @static
20978          */
20979         startX: 0,
20980
20981         /**
20982          * The Y position of the mousedown event stored for later use when a
20983          * drag threshold is met.
20984          * @property startY
20985          * @type int
20986          * @private
20987          * @static
20988          */
20989         startY: 0,
20990
20991         /**
20992          * Each DragDrop instance must be registered with the DragDropMgr.
20993          * This is executed in DragDrop.init()
20994          * @method regDragDrop
20995          * @param {DragDrop} oDD the DragDrop object to register
20996          * @param {String} sGroup the name of the group this element belongs to
20997          * @static
20998          */
20999         regDragDrop: function(oDD, sGroup) {
21000             if (!this.initialized) { this.init(); }
21001
21002             if (!this.ids[sGroup]) {
21003                 this.ids[sGroup] = {};
21004             }
21005             this.ids[sGroup][oDD.id] = oDD;
21006         },
21007
21008         /**
21009          * Removes the supplied dd instance from the supplied group. Executed
21010          * by DragDrop.removeFromGroup, so don't call this function directly.
21011          * @method removeDDFromGroup
21012          * @private
21013          * @static
21014          */
21015         removeDDFromGroup: function(oDD, sGroup) {
21016             if (!this.ids[sGroup]) {
21017                 this.ids[sGroup] = {};
21018             }
21019
21020             var obj = this.ids[sGroup];
21021             if (obj && obj[oDD.id]) {
21022                 delete obj[oDD.id];
21023             }
21024         },
21025
21026         /**
21027          * Unregisters a drag and drop item.  This is executed in
21028          * DragDrop.unreg, use that method instead of calling this directly.
21029          * @method _remove
21030          * @private
21031          * @static
21032          */
21033         _remove: function(oDD) {
21034             for (var g in oDD.groups) {
21035                 if (g && this.ids[g][oDD.id]) {
21036                     delete this.ids[g][oDD.id];
21037                 }
21038             }
21039             delete this.handleIds[oDD.id];
21040         },
21041
21042         /**
21043          * Each DragDrop handle element must be registered.  This is done
21044          * automatically when executing DragDrop.setHandleElId()
21045          * @method regHandle
21046          * @param {String} sDDId the DragDrop id this element is a handle for
21047          * @param {String} sHandleId the id of the element that is the drag
21048          * handle
21049          * @static
21050          */
21051         regHandle: function(sDDId, sHandleId) {
21052             if (!this.handleIds[sDDId]) {
21053                 this.handleIds[sDDId] = {};
21054             }
21055             this.handleIds[sDDId][sHandleId] = sHandleId;
21056         },
21057
21058         /**
21059          * Utility function to determine if a given element has been
21060          * registered as a drag drop item.
21061          * @method isDragDrop
21062          * @param {String} id the element id to check
21063          * @return {boolean} true if this element is a DragDrop item,
21064          * false otherwise
21065          * @static
21066          */
21067         isDragDrop: function(id) {
21068             return ( this.getDDById(id) ) ? true : false;
21069         },
21070
21071         /**
21072          * Returns the drag and drop instances that are in all groups the
21073          * passed in instance belongs to.
21074          * @method getRelated
21075          * @param {DragDrop} p_oDD the obj to get related data for
21076          * @param {boolean} bTargetsOnly if true, only return targetable objs
21077          * @return {DragDrop[]} the related instances
21078          * @static
21079          */
21080         getRelated: function(p_oDD, bTargetsOnly) {
21081             var oDDs = [];
21082             for (var i in p_oDD.groups) {
21083                 for (j in this.ids[i]) {
21084                     var dd = this.ids[i][j];
21085                     if (! this.isTypeOfDD(dd)) {
21086                         continue;
21087                     }
21088                     if (!bTargetsOnly || dd.isTarget) {
21089                         oDDs[oDDs.length] = dd;
21090                     }
21091                 }
21092             }
21093
21094             return oDDs;
21095         },
21096
21097         /**
21098          * Returns true if the specified dd target is a legal target for
21099          * the specifice drag obj
21100          * @method isLegalTarget
21101          * @param {DragDrop} the drag obj
21102          * @param {DragDrop} the target
21103          * @return {boolean} true if the target is a legal target for the
21104          * dd obj
21105          * @static
21106          */
21107         isLegalTarget: function (oDD, oTargetDD) {
21108             var targets = this.getRelated(oDD, true);
21109             for (var i=0, len=targets.length;i<len;++i) {
21110                 if (targets[i].id == oTargetDD.id) {
21111                     return true;
21112                 }
21113             }
21114
21115             return false;
21116         },
21117
21118         /**
21119          * My goal is to be able to transparently determine if an object is
21120          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21121          * returns "object", oDD.constructor.toString() always returns
21122          * "DragDrop" and not the name of the subclass.  So for now it just
21123          * evaluates a well-known variable in DragDrop.
21124          * @method isTypeOfDD
21125          * @param {Object} the object to evaluate
21126          * @return {boolean} true if typeof oDD = DragDrop
21127          * @static
21128          */
21129         isTypeOfDD: function (oDD) {
21130             return (oDD && oDD.__ygDragDrop);
21131         },
21132
21133         /**
21134          * Utility function to determine if a given element has been
21135          * registered as a drag drop handle for the given Drag Drop object.
21136          * @method isHandle
21137          * @param {String} id the element id to check
21138          * @return {boolean} true if this element is a DragDrop handle, false
21139          * otherwise
21140          * @static
21141          */
21142         isHandle: function(sDDId, sHandleId) {
21143             return ( this.handleIds[sDDId] &&
21144                             this.handleIds[sDDId][sHandleId] );
21145         },
21146
21147         /**
21148          * Returns the DragDrop instance for a given id
21149          * @method getDDById
21150          * @param {String} id the id of the DragDrop object
21151          * @return {DragDrop} the drag drop object, null if it is not found
21152          * @static
21153          */
21154         getDDById: function(id) {
21155             for (var i in this.ids) {
21156                 if (this.ids[i][id]) {
21157                     return this.ids[i][id];
21158                 }
21159             }
21160             return null;
21161         },
21162
21163         /**
21164          * Fired after a registered DragDrop object gets the mousedown event.
21165          * Sets up the events required to track the object being dragged
21166          * @method handleMouseDown
21167          * @param {Event} e the event
21168          * @param oDD the DragDrop object being dragged
21169          * @private
21170          * @static
21171          */
21172         handleMouseDown: function(e, oDD) {
21173             if(Roo.QuickTips){
21174                 Roo.QuickTips.disable();
21175             }
21176             this.currentTarget = e.getTarget();
21177
21178             this.dragCurrent = oDD;
21179
21180             var el = oDD.getEl();
21181
21182             // track start position
21183             this.startX = e.getPageX();
21184             this.startY = e.getPageY();
21185
21186             this.deltaX = this.startX - el.offsetLeft;
21187             this.deltaY = this.startY - el.offsetTop;
21188
21189             this.dragThreshMet = false;
21190
21191             this.clickTimeout = setTimeout(
21192                     function() {
21193                         var DDM = Roo.dd.DDM;
21194                         DDM.startDrag(DDM.startX, DDM.startY);
21195                     },
21196                     this.clickTimeThresh );
21197         },
21198
21199         /**
21200          * Fired when either the drag pixel threshol or the mousedown hold
21201          * time threshold has been met.
21202          * @method startDrag
21203          * @param x {int} the X position of the original mousedown
21204          * @param y {int} the Y position of the original mousedown
21205          * @static
21206          */
21207         startDrag: function(x, y) {
21208             clearTimeout(this.clickTimeout);
21209             if (this.dragCurrent) {
21210                 this.dragCurrent.b4StartDrag(x, y);
21211                 this.dragCurrent.startDrag(x, y);
21212             }
21213             this.dragThreshMet = true;
21214         },
21215
21216         /**
21217          * Internal function to handle the mouseup event.  Will be invoked
21218          * from the context of the document.
21219          * @method handleMouseUp
21220          * @param {Event} e the event
21221          * @private
21222          * @static
21223          */
21224         handleMouseUp: function(e) {
21225
21226             if(Roo.QuickTips){
21227                 Roo.QuickTips.enable();
21228             }
21229             if (! this.dragCurrent) {
21230                 return;
21231             }
21232
21233             clearTimeout(this.clickTimeout);
21234
21235             if (this.dragThreshMet) {
21236                 this.fireEvents(e, true);
21237             } else {
21238             }
21239
21240             this.stopDrag(e);
21241
21242             this.stopEvent(e);
21243         },
21244
21245         /**
21246          * Utility to stop event propagation and event default, if these
21247          * features are turned on.
21248          * @method stopEvent
21249          * @param {Event} e the event as returned by this.getEvent()
21250          * @static
21251          */
21252         stopEvent: function(e){
21253             if(this.stopPropagation) {
21254                 e.stopPropagation();
21255             }
21256
21257             if (this.preventDefault) {
21258                 e.preventDefault();
21259             }
21260         },
21261
21262         /**
21263          * Internal function to clean up event handlers after the drag
21264          * operation is complete
21265          * @method stopDrag
21266          * @param {Event} e the event
21267          * @private
21268          * @static
21269          */
21270         stopDrag: function(e) {
21271             // Fire the drag end event for the item that was dragged
21272             if (this.dragCurrent) {
21273                 if (this.dragThreshMet) {
21274                     this.dragCurrent.b4EndDrag(e);
21275                     this.dragCurrent.endDrag(e);
21276                 }
21277
21278                 this.dragCurrent.onMouseUp(e);
21279             }
21280
21281             this.dragCurrent = null;
21282             this.dragOvers = {};
21283         },
21284
21285         /**
21286          * Internal function to handle the mousemove event.  Will be invoked
21287          * from the context of the html element.
21288          *
21289          * @TODO figure out what we can do about mouse events lost when the
21290          * user drags objects beyond the window boundary.  Currently we can
21291          * detect this in internet explorer by verifying that the mouse is
21292          * down during the mousemove event.  Firefox doesn't give us the
21293          * button state on the mousemove event.
21294          * @method handleMouseMove
21295          * @param {Event} e the event
21296          * @private
21297          * @static
21298          */
21299         handleMouseMove: function(e) {
21300             if (! this.dragCurrent) {
21301                 return true;
21302             }
21303
21304             // var button = e.which || e.button;
21305
21306             // check for IE mouseup outside of page boundary
21307             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21308                 this.stopEvent(e);
21309                 return this.handleMouseUp(e);
21310             }
21311
21312             if (!this.dragThreshMet) {
21313                 var diffX = Math.abs(this.startX - e.getPageX());
21314                 var diffY = Math.abs(this.startY - e.getPageY());
21315                 if (diffX > this.clickPixelThresh ||
21316                             diffY > this.clickPixelThresh) {
21317                     this.startDrag(this.startX, this.startY);
21318                 }
21319             }
21320
21321             if (this.dragThreshMet) {
21322                 this.dragCurrent.b4Drag(e);
21323                 this.dragCurrent.onDrag(e);
21324                 if(!this.dragCurrent.moveOnly){
21325                     this.fireEvents(e, false);
21326                 }
21327             }
21328
21329             this.stopEvent(e);
21330
21331             return true;
21332         },
21333
21334         /**
21335          * Iterates over all of the DragDrop elements to find ones we are
21336          * hovering over or dropping on
21337          * @method fireEvents
21338          * @param {Event} e the event
21339          * @param {boolean} isDrop is this a drop op or a mouseover op?
21340          * @private
21341          * @static
21342          */
21343         fireEvents: function(e, isDrop) {
21344             var dc = this.dragCurrent;
21345
21346             // If the user did the mouse up outside of the window, we could
21347             // get here even though we have ended the drag.
21348             if (!dc || dc.isLocked()) {
21349                 return;
21350             }
21351
21352             var pt = e.getPoint();
21353
21354             // cache the previous dragOver array
21355             var oldOvers = [];
21356
21357             var outEvts   = [];
21358             var overEvts  = [];
21359             var dropEvts  = [];
21360             var enterEvts = [];
21361
21362             // Check to see if the object(s) we were hovering over is no longer
21363             // being hovered over so we can fire the onDragOut event
21364             for (var i in this.dragOvers) {
21365
21366                 var ddo = this.dragOvers[i];
21367
21368                 if (! this.isTypeOfDD(ddo)) {
21369                     continue;
21370                 }
21371
21372                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21373                     outEvts.push( ddo );
21374                 }
21375
21376                 oldOvers[i] = true;
21377                 delete this.dragOvers[i];
21378             }
21379
21380             for (var sGroup in dc.groups) {
21381
21382                 if ("string" != typeof sGroup) {
21383                     continue;
21384                 }
21385
21386                 for (i in this.ids[sGroup]) {
21387                     var oDD = this.ids[sGroup][i];
21388                     if (! this.isTypeOfDD(oDD)) {
21389                         continue;
21390                     }
21391
21392                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21393                         if (this.isOverTarget(pt, oDD, this.mode)) {
21394                             // look for drop interactions
21395                             if (isDrop) {
21396                                 dropEvts.push( oDD );
21397                             // look for drag enter and drag over interactions
21398                             } else {
21399
21400                                 // initial drag over: dragEnter fires
21401                                 if (!oldOvers[oDD.id]) {
21402                                     enterEvts.push( oDD );
21403                                 // subsequent drag overs: dragOver fires
21404                                 } else {
21405                                     overEvts.push( oDD );
21406                                 }
21407
21408                                 this.dragOvers[oDD.id] = oDD;
21409                             }
21410                         }
21411                     }
21412                 }
21413             }
21414
21415             if (this.mode) {
21416                 if (outEvts.length) {
21417                     dc.b4DragOut(e, outEvts);
21418                     dc.onDragOut(e, outEvts);
21419                 }
21420
21421                 if (enterEvts.length) {
21422                     dc.onDragEnter(e, enterEvts);
21423                 }
21424
21425                 if (overEvts.length) {
21426                     dc.b4DragOver(e, overEvts);
21427                     dc.onDragOver(e, overEvts);
21428                 }
21429
21430                 if (dropEvts.length) {
21431                     dc.b4DragDrop(e, dropEvts);
21432                     dc.onDragDrop(e, dropEvts);
21433                 }
21434
21435             } else {
21436                 // fire dragout events
21437                 var len = 0;
21438                 for (i=0, len=outEvts.length; i<len; ++i) {
21439                     dc.b4DragOut(e, outEvts[i].id);
21440                     dc.onDragOut(e, outEvts[i].id);
21441                 }
21442
21443                 // fire enter events
21444                 for (i=0,len=enterEvts.length; i<len; ++i) {
21445                     // dc.b4DragEnter(e, oDD.id);
21446                     dc.onDragEnter(e, enterEvts[i].id);
21447                 }
21448
21449                 // fire over events
21450                 for (i=0,len=overEvts.length; i<len; ++i) {
21451                     dc.b4DragOver(e, overEvts[i].id);
21452                     dc.onDragOver(e, overEvts[i].id);
21453                 }
21454
21455                 // fire drop events
21456                 for (i=0, len=dropEvts.length; i<len; ++i) {
21457                     dc.b4DragDrop(e, dropEvts[i].id);
21458                     dc.onDragDrop(e, dropEvts[i].id);
21459                 }
21460
21461             }
21462
21463             // notify about a drop that did not find a target
21464             if (isDrop && !dropEvts.length) {
21465                 dc.onInvalidDrop(e);
21466             }
21467
21468         },
21469
21470         /**
21471          * Helper function for getting the best match from the list of drag
21472          * and drop objects returned by the drag and drop events when we are
21473          * in INTERSECT mode.  It returns either the first object that the
21474          * cursor is over, or the object that has the greatest overlap with
21475          * the dragged element.
21476          * @method getBestMatch
21477          * @param  {DragDrop[]} dds The array of drag and drop objects
21478          * targeted
21479          * @return {DragDrop}       The best single match
21480          * @static
21481          */
21482         getBestMatch: function(dds) {
21483             var winner = null;
21484             // Return null if the input is not what we expect
21485             //if (!dds || !dds.length || dds.length == 0) {
21486                // winner = null;
21487             // If there is only one item, it wins
21488             //} else if (dds.length == 1) {
21489
21490             var len = dds.length;
21491
21492             if (len == 1) {
21493                 winner = dds[0];
21494             } else {
21495                 // Loop through the targeted items
21496                 for (var i=0; i<len; ++i) {
21497                     var dd = dds[i];
21498                     // If the cursor is over the object, it wins.  If the
21499                     // cursor is over multiple matches, the first one we come
21500                     // to wins.
21501                     if (dd.cursorIsOver) {
21502                         winner = dd;
21503                         break;
21504                     // Otherwise the object with the most overlap wins
21505                     } else {
21506                         if (!winner ||
21507                             winner.overlap.getArea() < dd.overlap.getArea()) {
21508                             winner = dd;
21509                         }
21510                     }
21511                 }
21512             }
21513
21514             return winner;
21515         },
21516
21517         /**
21518          * Refreshes the cache of the top-left and bottom-right points of the
21519          * drag and drop objects in the specified group(s).  This is in the
21520          * format that is stored in the drag and drop instance, so typical
21521          * usage is:
21522          * <code>
21523          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21524          * </code>
21525          * Alternatively:
21526          * <code>
21527          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21528          * </code>
21529          * @TODO this really should be an indexed array.  Alternatively this
21530          * method could accept both.
21531          * @method refreshCache
21532          * @param {Object} groups an associative array of groups to refresh
21533          * @static
21534          */
21535         refreshCache: function(groups) {
21536             for (var sGroup in groups) {
21537                 if ("string" != typeof sGroup) {
21538                     continue;
21539                 }
21540                 for (var i in this.ids[sGroup]) {
21541                     var oDD = this.ids[sGroup][i];
21542
21543                     if (this.isTypeOfDD(oDD)) {
21544                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21545                         var loc = this.getLocation(oDD);
21546                         if (loc) {
21547                             this.locationCache[oDD.id] = loc;
21548                         } else {
21549                             delete this.locationCache[oDD.id];
21550                             // this will unregister the drag and drop object if
21551                             // the element is not in a usable state
21552                             // oDD.unreg();
21553                         }
21554                     }
21555                 }
21556             }
21557         },
21558
21559         /**
21560          * This checks to make sure an element exists and is in the DOM.  The
21561          * main purpose is to handle cases where innerHTML is used to remove
21562          * drag and drop objects from the DOM.  IE provides an 'unspecified
21563          * error' when trying to access the offsetParent of such an element
21564          * @method verifyEl
21565          * @param {HTMLElement} el the element to check
21566          * @return {boolean} true if the element looks usable
21567          * @static
21568          */
21569         verifyEl: function(el) {
21570             if (el) {
21571                 var parent;
21572                 if(Roo.isIE){
21573                     try{
21574                         parent = el.offsetParent;
21575                     }catch(e){}
21576                 }else{
21577                     parent = el.offsetParent;
21578                 }
21579                 if (parent) {
21580                     return true;
21581                 }
21582             }
21583
21584             return false;
21585         },
21586
21587         /**
21588          * Returns a Region object containing the drag and drop element's position
21589          * and size, including the padding configured for it
21590          * @method getLocation
21591          * @param {DragDrop} oDD the drag and drop object to get the
21592          *                       location for
21593          * @return {Roo.lib.Region} a Region object representing the total area
21594          *                             the element occupies, including any padding
21595          *                             the instance is configured for.
21596          * @static
21597          */
21598         getLocation: function(oDD) {
21599             if (! this.isTypeOfDD(oDD)) {
21600                 return null;
21601             }
21602
21603             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21604
21605             try {
21606                 pos= Roo.lib.Dom.getXY(el);
21607             } catch (e) { }
21608
21609             if (!pos) {
21610                 return null;
21611             }
21612
21613             x1 = pos[0];
21614             x2 = x1 + el.offsetWidth;
21615             y1 = pos[1];
21616             y2 = y1 + el.offsetHeight;
21617
21618             t = y1 - oDD.padding[0];
21619             r = x2 + oDD.padding[1];
21620             b = y2 + oDD.padding[2];
21621             l = x1 - oDD.padding[3];
21622
21623             return new Roo.lib.Region( t, r, b, l );
21624         },
21625
21626         /**
21627          * Checks the cursor location to see if it over the target
21628          * @method isOverTarget
21629          * @param {Roo.lib.Point} pt The point to evaluate
21630          * @param {DragDrop} oTarget the DragDrop object we are inspecting
21631          * @return {boolean} true if the mouse is over the target
21632          * @private
21633          * @static
21634          */
21635         isOverTarget: function(pt, oTarget, intersect) {
21636             // use cache if available
21637             var loc = this.locationCache[oTarget.id];
21638             if (!loc || !this.useCache) {
21639                 loc = this.getLocation(oTarget);
21640                 this.locationCache[oTarget.id] = loc;
21641
21642             }
21643
21644             if (!loc) {
21645                 return false;
21646             }
21647
21648             oTarget.cursorIsOver = loc.contains( pt );
21649
21650             // DragDrop is using this as a sanity check for the initial mousedown
21651             // in this case we are done.  In POINT mode, if the drag obj has no
21652             // contraints, we are also done. Otherwise we need to evaluate the
21653             // location of the target as related to the actual location of the
21654             // dragged element.
21655             var dc = this.dragCurrent;
21656             if (!dc || !dc.getTargetCoord ||
21657                     (!intersect && !dc.constrainX && !dc.constrainY)) {
21658                 return oTarget.cursorIsOver;
21659             }
21660
21661             oTarget.overlap = null;
21662
21663             // Get the current location of the drag element, this is the
21664             // location of the mouse event less the delta that represents
21665             // where the original mousedown happened on the element.  We
21666             // need to consider constraints and ticks as well.
21667             var pos = dc.getTargetCoord(pt.x, pt.y);
21668
21669             var el = dc.getDragEl();
21670             var curRegion = new Roo.lib.Region( pos.y,
21671                                                    pos.x + el.offsetWidth,
21672                                                    pos.y + el.offsetHeight,
21673                                                    pos.x );
21674
21675             var overlap = curRegion.intersect(loc);
21676
21677             if (overlap) {
21678                 oTarget.overlap = overlap;
21679                 return (intersect) ? true : oTarget.cursorIsOver;
21680             } else {
21681                 return false;
21682             }
21683         },
21684
21685         /**
21686          * unload event handler
21687          * @method _onUnload
21688          * @private
21689          * @static
21690          */
21691         _onUnload: function(e, me) {
21692             Roo.dd.DragDropMgr.unregAll();
21693         },
21694
21695         /**
21696          * Cleans up the drag and drop events and objects.
21697          * @method unregAll
21698          * @private
21699          * @static
21700          */
21701         unregAll: function() {
21702
21703             if (this.dragCurrent) {
21704                 this.stopDrag();
21705                 this.dragCurrent = null;
21706             }
21707
21708             this._execOnAll("unreg", []);
21709
21710             for (i in this.elementCache) {
21711                 delete this.elementCache[i];
21712             }
21713
21714             this.elementCache = {};
21715             this.ids = {};
21716         },
21717
21718         /**
21719          * A cache of DOM elements
21720          * @property elementCache
21721          * @private
21722          * @static
21723          */
21724         elementCache: {},
21725
21726         /**
21727          * Get the wrapper for the DOM element specified
21728          * @method getElWrapper
21729          * @param {String} id the id of the element to get
21730          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21731          * @private
21732          * @deprecated This wrapper isn't that useful
21733          * @static
21734          */
21735         getElWrapper: function(id) {
21736             var oWrapper = this.elementCache[id];
21737             if (!oWrapper || !oWrapper.el) {
21738                 oWrapper = this.elementCache[id] =
21739                     new this.ElementWrapper(Roo.getDom(id));
21740             }
21741             return oWrapper;
21742         },
21743
21744         /**
21745          * Returns the actual DOM element
21746          * @method getElement
21747          * @param {String} id the id of the elment to get
21748          * @return {Object} The element
21749          * @deprecated use Roo.getDom instead
21750          * @static
21751          */
21752         getElement: function(id) {
21753             return Roo.getDom(id);
21754         },
21755
21756         /**
21757          * Returns the style property for the DOM element (i.e.,
21758          * document.getElById(id).style)
21759          * @method getCss
21760          * @param {String} id the id of the elment to get
21761          * @return {Object} The style property of the element
21762          * @deprecated use Roo.getDom instead
21763          * @static
21764          */
21765         getCss: function(id) {
21766             var el = Roo.getDom(id);
21767             return (el) ? el.style : null;
21768         },
21769
21770         /**
21771          * Inner class for cached elements
21772          * @class DragDropMgr.ElementWrapper
21773          * @for DragDropMgr
21774          * @private
21775          * @deprecated
21776          */
21777         ElementWrapper: function(el) {
21778                 /**
21779                  * The element
21780                  * @property el
21781                  */
21782                 this.el = el || null;
21783                 /**
21784                  * The element id
21785                  * @property id
21786                  */
21787                 this.id = this.el && el.id;
21788                 /**
21789                  * A reference to the style property
21790                  * @property css
21791                  */
21792                 this.css = this.el && el.style;
21793             },
21794
21795         /**
21796          * Returns the X position of an html element
21797          * @method getPosX
21798          * @param el the element for which to get the position
21799          * @return {int} the X coordinate
21800          * @for DragDropMgr
21801          * @deprecated use Roo.lib.Dom.getX instead
21802          * @static
21803          */
21804         getPosX: function(el) {
21805             return Roo.lib.Dom.getX(el);
21806         },
21807
21808         /**
21809          * Returns the Y position of an html element
21810          * @method getPosY
21811          * @param el the element for which to get the position
21812          * @return {int} the Y coordinate
21813          * @deprecated use Roo.lib.Dom.getY instead
21814          * @static
21815          */
21816         getPosY: function(el) {
21817             return Roo.lib.Dom.getY(el);
21818         },
21819
21820         /**
21821          * Swap two nodes.  In IE, we use the native method, for others we
21822          * emulate the IE behavior
21823          * @method swapNode
21824          * @param n1 the first node to swap
21825          * @param n2 the other node to swap
21826          * @static
21827          */
21828         swapNode: function(n1, n2) {
21829             if (n1.swapNode) {
21830                 n1.swapNode(n2);
21831             } else {
21832                 var p = n2.parentNode;
21833                 var s = n2.nextSibling;
21834
21835                 if (s == n1) {
21836                     p.insertBefore(n1, n2);
21837                 } else if (n2 == n1.nextSibling) {
21838                     p.insertBefore(n2, n1);
21839                 } else {
21840                     n1.parentNode.replaceChild(n2, n1);
21841                     p.insertBefore(n1, s);
21842                 }
21843             }
21844         },
21845
21846         /**
21847          * Returns the current scroll position
21848          * @method getScroll
21849          * @private
21850          * @static
21851          */
21852         getScroll: function () {
21853             var t, l, dde=document.documentElement, db=document.body;
21854             if (dde && (dde.scrollTop || dde.scrollLeft)) {
21855                 t = dde.scrollTop;
21856                 l = dde.scrollLeft;
21857             } else if (db) {
21858                 t = db.scrollTop;
21859                 l = db.scrollLeft;
21860             } else {
21861
21862             }
21863             return { top: t, left: l };
21864         },
21865
21866         /**
21867          * Returns the specified element style property
21868          * @method getStyle
21869          * @param {HTMLElement} el          the element
21870          * @param {string}      styleProp   the style property
21871          * @return {string} The value of the style property
21872          * @deprecated use Roo.lib.Dom.getStyle
21873          * @static
21874          */
21875         getStyle: function(el, styleProp) {
21876             return Roo.fly(el).getStyle(styleProp);
21877         },
21878
21879         /**
21880          * Gets the scrollTop
21881          * @method getScrollTop
21882          * @return {int} the document's scrollTop
21883          * @static
21884          */
21885         getScrollTop: function () { return this.getScroll().top; },
21886
21887         /**
21888          * Gets the scrollLeft
21889          * @method getScrollLeft
21890          * @return {int} the document's scrollTop
21891          * @static
21892          */
21893         getScrollLeft: function () { return this.getScroll().left; },
21894
21895         /**
21896          * Sets the x/y position of an element to the location of the
21897          * target element.
21898          * @method moveToEl
21899          * @param {HTMLElement} moveEl      The element to move
21900          * @param {HTMLElement} targetEl    The position reference element
21901          * @static
21902          */
21903         moveToEl: function (moveEl, targetEl) {
21904             var aCoord = Roo.lib.Dom.getXY(targetEl);
21905             Roo.lib.Dom.setXY(moveEl, aCoord);
21906         },
21907
21908         /**
21909          * Numeric array sort function
21910          * @method numericSort
21911          * @static
21912          */
21913         numericSort: function(a, b) { return (a - b); },
21914
21915         /**
21916          * Internal counter
21917          * @property _timeoutCount
21918          * @private
21919          * @static
21920          */
21921         _timeoutCount: 0,
21922
21923         /**
21924          * Trying to make the load order less important.  Without this we get
21925          * an error if this file is loaded before the Event Utility.
21926          * @method _addListeners
21927          * @private
21928          * @static
21929          */
21930         _addListeners: function() {
21931             var DDM = Roo.dd.DDM;
21932             if ( Roo.lib.Event && document ) {
21933                 DDM._onLoad();
21934             } else {
21935                 if (DDM._timeoutCount > 2000) {
21936                 } else {
21937                     setTimeout(DDM._addListeners, 10);
21938                     if (document && document.body) {
21939                         DDM._timeoutCount += 1;
21940                     }
21941                 }
21942             }
21943         },
21944
21945         /**
21946          * Recursively searches the immediate parent and all child nodes for
21947          * the handle element in order to determine wheter or not it was
21948          * clicked.
21949          * @method handleWasClicked
21950          * @param node the html element to inspect
21951          * @static
21952          */
21953         handleWasClicked: function(node, id) {
21954             if (this.isHandle(id, node.id)) {
21955                 return true;
21956             } else {
21957                 // check to see if this is a text node child of the one we want
21958                 var p = node.parentNode;
21959
21960                 while (p) {
21961                     if (this.isHandle(id, p.id)) {
21962                         return true;
21963                     } else {
21964                         p = p.parentNode;
21965                     }
21966                 }
21967             }
21968
21969             return false;
21970         }
21971
21972     };
21973
21974 }();
21975
21976 // shorter alias, save a few bytes
21977 Roo.dd.DDM = Roo.dd.DragDropMgr;
21978 Roo.dd.DDM._addListeners();
21979
21980 }/*
21981  * Based on:
21982  * Ext JS Library 1.1.1
21983  * Copyright(c) 2006-2007, Ext JS, LLC.
21984  *
21985  * Originally Released Under LGPL - original licence link has changed is not relivant.
21986  *
21987  * Fork - LGPL
21988  * <script type="text/javascript">
21989  */
21990
21991 /**
21992  * @class Roo.dd.DD
21993  * A DragDrop implementation where the linked element follows the
21994  * mouse cursor during a drag.
21995  * @extends Roo.dd.DragDrop
21996  * @constructor
21997  * @param {String} id the id of the linked element
21998  * @param {String} sGroup the group of related DragDrop items
21999  * @param {object} config an object containing configurable attributes
22000  *                Valid properties for DD:
22001  *                    scroll
22002  */
22003 Roo.dd.DD = function(id, sGroup, config) {
22004     if (id) {
22005         this.init(id, sGroup, config);
22006     }
22007 };
22008
22009 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22010
22011     /**
22012      * When set to true, the utility automatically tries to scroll the browser
22013      * window wehn a drag and drop element is dragged near the viewport boundary.
22014      * Defaults to true.
22015      * @property scroll
22016      * @type boolean
22017      */
22018     scroll: true,
22019
22020     /**
22021      * Sets the pointer offset to the distance between the linked element's top
22022      * left corner and the location the element was clicked
22023      * @method autoOffset
22024      * @param {int} iPageX the X coordinate of the click
22025      * @param {int} iPageY the Y coordinate of the click
22026      */
22027     autoOffset: function(iPageX, iPageY) {
22028         var x = iPageX - this.startPageX;
22029         var y = iPageY - this.startPageY;
22030         this.setDelta(x, y);
22031     },
22032
22033     /**
22034      * Sets the pointer offset.  You can call this directly to force the
22035      * offset to be in a particular location (e.g., pass in 0,0 to set it
22036      * to the center of the object)
22037      * @method setDelta
22038      * @param {int} iDeltaX the distance from the left
22039      * @param {int} iDeltaY the distance from the top
22040      */
22041     setDelta: function(iDeltaX, iDeltaY) {
22042         this.deltaX = iDeltaX;
22043         this.deltaY = iDeltaY;
22044     },
22045
22046     /**
22047      * Sets the drag element to the location of the mousedown or click event,
22048      * maintaining the cursor location relative to the location on the element
22049      * that was clicked.  Override this if you want to place the element in a
22050      * location other than where the cursor is.
22051      * @method setDragElPos
22052      * @param {int} iPageX the X coordinate of the mousedown or drag event
22053      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22054      */
22055     setDragElPos: function(iPageX, iPageY) {
22056         // the first time we do this, we are going to check to make sure
22057         // the element has css positioning
22058
22059         var el = this.getDragEl();
22060         this.alignElWithMouse(el, iPageX, iPageY);
22061     },
22062
22063     /**
22064      * Sets the element to the location of the mousedown or click event,
22065      * maintaining the cursor location relative to the location on the element
22066      * that was clicked.  Override this if you want to place the element in a
22067      * location other than where the cursor is.
22068      * @method alignElWithMouse
22069      * @param {HTMLElement} el the element to move
22070      * @param {int} iPageX the X coordinate of the mousedown or drag event
22071      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22072      */
22073     alignElWithMouse: function(el, iPageX, iPageY) {
22074         var oCoord = this.getTargetCoord(iPageX, iPageY);
22075         var fly = el.dom ? el : Roo.fly(el);
22076         if (!this.deltaSetXY) {
22077             var aCoord = [oCoord.x, oCoord.y];
22078             fly.setXY(aCoord);
22079             var newLeft = fly.getLeft(true);
22080             var newTop  = fly.getTop(true);
22081             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22082         } else {
22083             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22084         }
22085
22086         this.cachePosition(oCoord.x, oCoord.y);
22087         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22088         return oCoord;
22089     },
22090
22091     /**
22092      * Saves the most recent position so that we can reset the constraints and
22093      * tick marks on-demand.  We need to know this so that we can calculate the
22094      * number of pixels the element is offset from its original position.
22095      * @method cachePosition
22096      * @param iPageX the current x position (optional, this just makes it so we
22097      * don't have to look it up again)
22098      * @param iPageY the current y position (optional, this just makes it so we
22099      * don't have to look it up again)
22100      */
22101     cachePosition: function(iPageX, iPageY) {
22102         if (iPageX) {
22103             this.lastPageX = iPageX;
22104             this.lastPageY = iPageY;
22105         } else {
22106             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22107             this.lastPageX = aCoord[0];
22108             this.lastPageY = aCoord[1];
22109         }
22110     },
22111
22112     /**
22113      * Auto-scroll the window if the dragged object has been moved beyond the
22114      * visible window boundary.
22115      * @method autoScroll
22116      * @param {int} x the drag element's x position
22117      * @param {int} y the drag element's y position
22118      * @param {int} h the height of the drag element
22119      * @param {int} w the width of the drag element
22120      * @private
22121      */
22122     autoScroll: function(x, y, h, w) {
22123
22124         if (this.scroll) {
22125             // The client height
22126             var clientH = Roo.lib.Dom.getViewWidth();
22127
22128             // The client width
22129             var clientW = Roo.lib.Dom.getViewHeight();
22130
22131             // The amt scrolled down
22132             var st = this.DDM.getScrollTop();
22133
22134             // The amt scrolled right
22135             var sl = this.DDM.getScrollLeft();
22136
22137             // Location of the bottom of the element
22138             var bot = h + y;
22139
22140             // Location of the right of the element
22141             var right = w + x;
22142
22143             // The distance from the cursor to the bottom of the visible area,
22144             // adjusted so that we don't scroll if the cursor is beyond the
22145             // element drag constraints
22146             var toBot = (clientH + st - y - this.deltaY);
22147
22148             // The distance from the cursor to the right of the visible area
22149             var toRight = (clientW + sl - x - this.deltaX);
22150
22151
22152             // How close to the edge the cursor must be before we scroll
22153             // var thresh = (document.all) ? 100 : 40;
22154             var thresh = 40;
22155
22156             // How many pixels to scroll per autoscroll op.  This helps to reduce
22157             // clunky scrolling. IE is more sensitive about this ... it needs this
22158             // value to be higher.
22159             var scrAmt = (document.all) ? 80 : 30;
22160
22161             // Scroll down if we are near the bottom of the visible page and the
22162             // obj extends below the crease
22163             if ( bot > clientH && toBot < thresh ) {
22164                 window.scrollTo(sl, st + scrAmt);
22165             }
22166
22167             // Scroll up if the window is scrolled down and the top of the object
22168             // goes above the top border
22169             if ( y < st && st > 0 && y - st < thresh ) {
22170                 window.scrollTo(sl, st - scrAmt);
22171             }
22172
22173             // Scroll right if the obj is beyond the right border and the cursor is
22174             // near the border.
22175             if ( right > clientW && toRight < thresh ) {
22176                 window.scrollTo(sl + scrAmt, st);
22177             }
22178
22179             // Scroll left if the window has been scrolled to the right and the obj
22180             // extends past the left border
22181             if ( x < sl && sl > 0 && x - sl < thresh ) {
22182                 window.scrollTo(sl - scrAmt, st);
22183             }
22184         }
22185     },
22186
22187     /**
22188      * Finds the location the element should be placed if we want to move
22189      * it to where the mouse location less the click offset would place us.
22190      * @method getTargetCoord
22191      * @param {int} iPageX the X coordinate of the click
22192      * @param {int} iPageY the Y coordinate of the click
22193      * @return an object that contains the coordinates (Object.x and Object.y)
22194      * @private
22195      */
22196     getTargetCoord: function(iPageX, iPageY) {
22197
22198
22199         var x = iPageX - this.deltaX;
22200         var y = iPageY - this.deltaY;
22201
22202         if (this.constrainX) {
22203             if (x < this.minX) { x = this.minX; }
22204             if (x > this.maxX) { x = this.maxX; }
22205         }
22206
22207         if (this.constrainY) {
22208             if (y < this.minY) { y = this.minY; }
22209             if (y > this.maxY) { y = this.maxY; }
22210         }
22211
22212         x = this.getTick(x, this.xTicks);
22213         y = this.getTick(y, this.yTicks);
22214
22215
22216         return {x:x, y:y};
22217     },
22218
22219     /*
22220      * Sets up config options specific to this class. Overrides
22221      * Roo.dd.DragDrop, but all versions of this method through the
22222      * inheritance chain are called
22223      */
22224     applyConfig: function() {
22225         Roo.dd.DD.superclass.applyConfig.call(this);
22226         this.scroll = (this.config.scroll !== false);
22227     },
22228
22229     /*
22230      * Event that fires prior to the onMouseDown event.  Overrides
22231      * Roo.dd.DragDrop.
22232      */
22233     b4MouseDown: function(e) {
22234         // this.resetConstraints();
22235         this.autoOffset(e.getPageX(),
22236                             e.getPageY());
22237     },
22238
22239     /*
22240      * Event that fires prior to the onDrag event.  Overrides
22241      * Roo.dd.DragDrop.
22242      */
22243     b4Drag: function(e) {
22244         this.setDragElPos(e.getPageX(),
22245                             e.getPageY());
22246     },
22247
22248     toString: function() {
22249         return ("DD " + this.id);
22250     }
22251
22252     //////////////////////////////////////////////////////////////////////////
22253     // Debugging ygDragDrop events that can be overridden
22254     //////////////////////////////////////////////////////////////////////////
22255     /*
22256     startDrag: function(x, y) {
22257     },
22258
22259     onDrag: function(e) {
22260     },
22261
22262     onDragEnter: function(e, id) {
22263     },
22264
22265     onDragOver: function(e, id) {
22266     },
22267
22268     onDragOut: function(e, id) {
22269     },
22270
22271     onDragDrop: function(e, id) {
22272     },
22273
22274     endDrag: function(e) {
22275     }
22276
22277     */
22278
22279 });/*
22280  * Based on:
22281  * Ext JS Library 1.1.1
22282  * Copyright(c) 2006-2007, Ext JS, LLC.
22283  *
22284  * Originally Released Under LGPL - original licence link has changed is not relivant.
22285  *
22286  * Fork - LGPL
22287  * <script type="text/javascript">
22288  */
22289
22290 /**
22291  * @class Roo.dd.DDProxy
22292  * A DragDrop implementation that inserts an empty, bordered div into
22293  * the document that follows the cursor during drag operations.  At the time of
22294  * the click, the frame div is resized to the dimensions of the linked html
22295  * element, and moved to the exact location of the linked element.
22296  *
22297  * References to the "frame" element refer to the single proxy element that
22298  * was created to be dragged in place of all DDProxy elements on the
22299  * page.
22300  *
22301  * @extends Roo.dd.DD
22302  * @constructor
22303  * @param {String} id the id of the linked html element
22304  * @param {String} sGroup the group of related DragDrop objects
22305  * @param {object} config an object containing configurable attributes
22306  *                Valid properties for DDProxy in addition to those in DragDrop:
22307  *                   resizeFrame, centerFrame, dragElId
22308  */
22309 Roo.dd.DDProxy = function(id, sGroup, config) {
22310     if (id) {
22311         this.init(id, sGroup, config);
22312         this.initFrame();
22313     }
22314 };
22315
22316 /**
22317  * The default drag frame div id
22318  * @property Roo.dd.DDProxy.dragElId
22319  * @type String
22320  * @static
22321  */
22322 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22323
22324 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22325
22326     /**
22327      * By default we resize the drag frame to be the same size as the element
22328      * we want to drag (this is to get the frame effect).  We can turn it off
22329      * if we want a different behavior.
22330      * @property resizeFrame
22331      * @type boolean
22332      */
22333     resizeFrame: true,
22334
22335     /**
22336      * By default the frame is positioned exactly where the drag element is, so
22337      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22338      * you do not have constraints on the obj is to have the drag frame centered
22339      * around the cursor.  Set centerFrame to true for this effect.
22340      * @property centerFrame
22341      * @type boolean
22342      */
22343     centerFrame: false,
22344
22345     /**
22346      * Creates the proxy element if it does not yet exist
22347      * @method createFrame
22348      */
22349     createFrame: function() {
22350         var self = this;
22351         var body = document.body;
22352
22353         if (!body || !body.firstChild) {
22354             setTimeout( function() { self.createFrame(); }, 50 );
22355             return;
22356         }
22357
22358         var div = this.getDragEl();
22359
22360         if (!div) {
22361             div    = document.createElement("div");
22362             div.id = this.dragElId;
22363             var s  = div.style;
22364
22365             s.position   = "absolute";
22366             s.visibility = "hidden";
22367             s.cursor     = "move";
22368             s.border     = "2px solid #aaa";
22369             s.zIndex     = 999;
22370
22371             // appendChild can blow up IE if invoked prior to the window load event
22372             // while rendering a table.  It is possible there are other scenarios
22373             // that would cause this to happen as well.
22374             body.insertBefore(div, body.firstChild);
22375         }
22376     },
22377
22378     /**
22379      * Initialization for the drag frame element.  Must be called in the
22380      * constructor of all subclasses
22381      * @method initFrame
22382      */
22383     initFrame: function() {
22384         this.createFrame();
22385     },
22386
22387     applyConfig: function() {
22388         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22389
22390         this.resizeFrame = (this.config.resizeFrame !== false);
22391         this.centerFrame = (this.config.centerFrame);
22392         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22393     },
22394
22395     /**
22396      * Resizes the drag frame to the dimensions of the clicked object, positions
22397      * it over the object, and finally displays it
22398      * @method showFrame
22399      * @param {int} iPageX X click position
22400      * @param {int} iPageY Y click position
22401      * @private
22402      */
22403     showFrame: function(iPageX, iPageY) {
22404         var el = this.getEl();
22405         var dragEl = this.getDragEl();
22406         var s = dragEl.style;
22407
22408         this._resizeProxy();
22409
22410         if (this.centerFrame) {
22411             this.setDelta( Math.round(parseInt(s.width,  10)/2),
22412                            Math.round(parseInt(s.height, 10)/2) );
22413         }
22414
22415         this.setDragElPos(iPageX, iPageY);
22416
22417         Roo.fly(dragEl).show();
22418     },
22419
22420     /**
22421      * The proxy is automatically resized to the dimensions of the linked
22422      * element when a drag is initiated, unless resizeFrame is set to false
22423      * @method _resizeProxy
22424      * @private
22425      */
22426     _resizeProxy: function() {
22427         if (this.resizeFrame) {
22428             var el = this.getEl();
22429             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22430         }
22431     },
22432
22433     // overrides Roo.dd.DragDrop
22434     b4MouseDown: function(e) {
22435         var x = e.getPageX();
22436         var y = e.getPageY();
22437         this.autoOffset(x, y);
22438         this.setDragElPos(x, y);
22439     },
22440
22441     // overrides Roo.dd.DragDrop
22442     b4StartDrag: function(x, y) {
22443         // show the drag frame
22444         this.showFrame(x, y);
22445     },
22446
22447     // overrides Roo.dd.DragDrop
22448     b4EndDrag: function(e) {
22449         Roo.fly(this.getDragEl()).hide();
22450     },
22451
22452     // overrides Roo.dd.DragDrop
22453     // By default we try to move the element to the last location of the frame.
22454     // This is so that the default behavior mirrors that of Roo.dd.DD.
22455     endDrag: function(e) {
22456
22457         var lel = this.getEl();
22458         var del = this.getDragEl();
22459
22460         // Show the drag frame briefly so we can get its position
22461         del.style.visibility = "";
22462
22463         this.beforeMove();
22464         // Hide the linked element before the move to get around a Safari
22465         // rendering bug.
22466         lel.style.visibility = "hidden";
22467         Roo.dd.DDM.moveToEl(lel, del);
22468         del.style.visibility = "hidden";
22469         lel.style.visibility = "";
22470
22471         this.afterDrag();
22472     },
22473
22474     beforeMove : function(){
22475
22476     },
22477
22478     afterDrag : function(){
22479
22480     },
22481
22482     toString: function() {
22483         return ("DDProxy " + this.id);
22484     }
22485
22486 });
22487 /*
22488  * Based on:
22489  * Ext JS Library 1.1.1
22490  * Copyright(c) 2006-2007, Ext JS, LLC.
22491  *
22492  * Originally Released Under LGPL - original licence link has changed is not relivant.
22493  *
22494  * Fork - LGPL
22495  * <script type="text/javascript">
22496  */
22497
22498  /**
22499  * @class Roo.dd.DDTarget
22500  * A DragDrop implementation that does not move, but can be a drop
22501  * target.  You would get the same result by simply omitting implementation
22502  * for the event callbacks, but this way we reduce the processing cost of the
22503  * event listener and the callbacks.
22504  * @extends Roo.dd.DragDrop
22505  * @constructor
22506  * @param {String} id the id of the element that is a drop target
22507  * @param {String} sGroup the group of related DragDrop objects
22508  * @param {object} config an object containing configurable attributes
22509  *                 Valid properties for DDTarget in addition to those in
22510  *                 DragDrop:
22511  *                    none
22512  */
22513 Roo.dd.DDTarget = function(id, sGroup, config) {
22514     if (id) {
22515         this.initTarget(id, sGroup, config);
22516     }
22517     if (config && (config.listeners || config.events)) { 
22518         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
22519             listeners : config.listeners || {}, 
22520             events : config.events || {} 
22521         });    
22522     }
22523 };
22524
22525 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22526 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22527     toString: function() {
22528         return ("DDTarget " + this.id);
22529     }
22530 });
22531 /*
22532  * Based on:
22533  * Ext JS Library 1.1.1
22534  * Copyright(c) 2006-2007, Ext JS, LLC.
22535  *
22536  * Originally Released Under LGPL - original licence link has changed is not relivant.
22537  *
22538  * Fork - LGPL
22539  * <script type="text/javascript">
22540  */
22541  
22542
22543 /**
22544  * @class Roo.dd.ScrollManager
22545  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22546  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22547  * @static
22548  */
22549 Roo.dd.ScrollManager = function(){
22550     var ddm = Roo.dd.DragDropMgr;
22551     var els = {};
22552     var dragEl = null;
22553     var proc = {};
22554     
22555     
22556     
22557     var onStop = function(e){
22558         dragEl = null;
22559         clearProc();
22560     };
22561     
22562     var triggerRefresh = function(){
22563         if(ddm.dragCurrent){
22564              ddm.refreshCache(ddm.dragCurrent.groups);
22565         }
22566     };
22567     
22568     var doScroll = function(){
22569         if(ddm.dragCurrent){
22570             var dds = Roo.dd.ScrollManager;
22571             if(!dds.animate){
22572                 if(proc.el.scroll(proc.dir, dds.increment)){
22573                     triggerRefresh();
22574                 }
22575             }else{
22576                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22577             }
22578         }
22579     };
22580     
22581     var clearProc = function(){
22582         if(proc.id){
22583             clearInterval(proc.id);
22584         }
22585         proc.id = 0;
22586         proc.el = null;
22587         proc.dir = "";
22588     };
22589     
22590     var startProc = function(el, dir){
22591          Roo.log('scroll startproc');
22592         clearProc();
22593         proc.el = el;
22594         proc.dir = dir;
22595         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22596     };
22597     
22598     var onFire = function(e, isDrop){
22599        
22600         if(isDrop || !ddm.dragCurrent){ return; }
22601         var dds = Roo.dd.ScrollManager;
22602         if(!dragEl || dragEl != ddm.dragCurrent){
22603             dragEl = ddm.dragCurrent;
22604             // refresh regions on drag start
22605             dds.refreshCache();
22606         }
22607         
22608         var xy = Roo.lib.Event.getXY(e);
22609         var pt = new Roo.lib.Point(xy[0], xy[1]);
22610         for(var id in els){
22611             var el = els[id], r = el._region;
22612             if(r && r.contains(pt) && el.isScrollable()){
22613                 if(r.bottom - pt.y <= dds.thresh){
22614                     if(proc.el != el){
22615                         startProc(el, "down");
22616                     }
22617                     return;
22618                 }else if(r.right - pt.x <= dds.thresh){
22619                     if(proc.el != el){
22620                         startProc(el, "left");
22621                     }
22622                     return;
22623                 }else if(pt.y - r.top <= dds.thresh){
22624                     if(proc.el != el){
22625                         startProc(el, "up");
22626                     }
22627                     return;
22628                 }else if(pt.x - r.left <= dds.thresh){
22629                     if(proc.el != el){
22630                         startProc(el, "right");
22631                     }
22632                     return;
22633                 }
22634             }
22635         }
22636         clearProc();
22637     };
22638     
22639     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22640     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22641     
22642     return {
22643         /**
22644          * Registers new overflow element(s) to auto scroll
22645          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22646          */
22647         register : function(el){
22648             if(el instanceof Array){
22649                 for(var i = 0, len = el.length; i < len; i++) {
22650                         this.register(el[i]);
22651                 }
22652             }else{
22653                 el = Roo.get(el);
22654                 els[el.id] = el;
22655             }
22656             Roo.dd.ScrollManager.els = els;
22657         },
22658         
22659         /**
22660          * Unregisters overflow element(s) so they are no longer scrolled
22661          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22662          */
22663         unregister : function(el){
22664             if(el instanceof Array){
22665                 for(var i = 0, len = el.length; i < len; i++) {
22666                         this.unregister(el[i]);
22667                 }
22668             }else{
22669                 el = Roo.get(el);
22670                 delete els[el.id];
22671             }
22672         },
22673         
22674         /**
22675          * The number of pixels from the edge of a container the pointer needs to be to 
22676          * trigger scrolling (defaults to 25)
22677          * @type Number
22678          */
22679         thresh : 25,
22680         
22681         /**
22682          * The number of pixels to scroll in each scroll increment (defaults to 50)
22683          * @type Number
22684          */
22685         increment : 100,
22686         
22687         /**
22688          * The frequency of scrolls in milliseconds (defaults to 500)
22689          * @type Number
22690          */
22691         frequency : 500,
22692         
22693         /**
22694          * True to animate the scroll (defaults to true)
22695          * @type Boolean
22696          */
22697         animate: true,
22698         
22699         /**
22700          * The animation duration in seconds - 
22701          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22702          * @type Number
22703          */
22704         animDuration: .4,
22705         
22706         /**
22707          * Manually trigger a cache refresh.
22708          */
22709         refreshCache : function(){
22710             for(var id in els){
22711                 if(typeof els[id] == 'object'){ // for people extending the object prototype
22712                     els[id]._region = els[id].getRegion();
22713                 }
22714             }
22715         }
22716     };
22717 }();/*
22718  * Based on:
22719  * Ext JS Library 1.1.1
22720  * Copyright(c) 2006-2007, Ext JS, LLC.
22721  *
22722  * Originally Released Under LGPL - original licence link has changed is not relivant.
22723  *
22724  * Fork - LGPL
22725  * <script type="text/javascript">
22726  */
22727  
22728
22729 /**
22730  * @class Roo.dd.Registry
22731  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
22732  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22733  * @static
22734  */
22735 Roo.dd.Registry = function(){
22736     var elements = {}; 
22737     var handles = {}; 
22738     var autoIdSeed = 0;
22739
22740     var getId = function(el, autogen){
22741         if(typeof el == "string"){
22742             return el;
22743         }
22744         var id = el.id;
22745         if(!id && autogen !== false){
22746             id = "roodd-" + (++autoIdSeed);
22747             el.id = id;
22748         }
22749         return id;
22750     };
22751     
22752     return {
22753     /**
22754      * Register a drag drop element
22755      * @param {String|HTMLElement} element The id or DOM node to register
22756      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22757      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
22758      * knows how to interpret, plus there are some specific properties known to the Registry that should be
22759      * populated in the data object (if applicable):
22760      * <pre>
22761 Value      Description<br />
22762 ---------  ------------------------------------------<br />
22763 handles    Array of DOM nodes that trigger dragging<br />
22764            for the element being registered<br />
22765 isHandle   True if the element passed in triggers<br />
22766            dragging itself, else false
22767 </pre>
22768      */
22769         register : function(el, data){
22770             data = data || {};
22771             if(typeof el == "string"){
22772                 el = document.getElementById(el);
22773             }
22774             data.ddel = el;
22775             elements[getId(el)] = data;
22776             if(data.isHandle !== false){
22777                 handles[data.ddel.id] = data;
22778             }
22779             if(data.handles){
22780                 var hs = data.handles;
22781                 for(var i = 0, len = hs.length; i < len; i++){
22782                         handles[getId(hs[i])] = data;
22783                 }
22784             }
22785         },
22786
22787     /**
22788      * Unregister a drag drop element
22789      * @param {String|HTMLElement}  element The id or DOM node to unregister
22790      */
22791         unregister : function(el){
22792             var id = getId(el, false);
22793             var data = elements[id];
22794             if(data){
22795                 delete elements[id];
22796                 if(data.handles){
22797                     var hs = data.handles;
22798                     for(var i = 0, len = hs.length; i < len; i++){
22799                         delete handles[getId(hs[i], false)];
22800                     }
22801                 }
22802             }
22803         },
22804
22805     /**
22806      * Returns the handle registered for a DOM Node by id
22807      * @param {String|HTMLElement} id The DOM node or id to look up
22808      * @return {Object} handle The custom handle data
22809      */
22810         getHandle : function(id){
22811             if(typeof id != "string"){ // must be element?
22812                 id = id.id;
22813             }
22814             return handles[id];
22815         },
22816
22817     /**
22818      * Returns the handle that is registered for the DOM node that is the target of the event
22819      * @param {Event} e The event
22820      * @return {Object} handle The custom handle data
22821      */
22822         getHandleFromEvent : function(e){
22823             var t = Roo.lib.Event.getTarget(e);
22824             return t ? handles[t.id] : null;
22825         },
22826
22827     /**
22828      * Returns a custom data object that is registered for a DOM node by id
22829      * @param {String|HTMLElement} id The DOM node or id to look up
22830      * @return {Object} data The custom data
22831      */
22832         getTarget : function(id){
22833             if(typeof id != "string"){ // must be element?
22834                 id = id.id;
22835             }
22836             return elements[id];
22837         },
22838
22839     /**
22840      * Returns a custom data object that is registered for the DOM node that is the target of the event
22841      * @param {Event} e The event
22842      * @return {Object} data The custom data
22843      */
22844         getTargetFromEvent : function(e){
22845             var t = Roo.lib.Event.getTarget(e);
22846             return t ? elements[t.id] || handles[t.id] : null;
22847         }
22848     };
22849 }();/*
22850  * Based on:
22851  * Ext JS Library 1.1.1
22852  * Copyright(c) 2006-2007, Ext JS, LLC.
22853  *
22854  * Originally Released Under LGPL - original licence link has changed is not relivant.
22855  *
22856  * Fork - LGPL
22857  * <script type="text/javascript">
22858  */
22859  
22860
22861 /**
22862  * @class Roo.dd.StatusProxy
22863  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
22864  * default drag proxy used by all Roo.dd components.
22865  * @constructor
22866  * @param {Object} config
22867  */
22868 Roo.dd.StatusProxy = function(config){
22869     Roo.apply(this, config);
22870     this.id = this.id || Roo.id();
22871     this.el = new Roo.Layer({
22872         dh: {
22873             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22874                 {tag: "div", cls: "x-dd-drop-icon"},
22875                 {tag: "div", cls: "x-dd-drag-ghost"}
22876             ]
22877         }, 
22878         shadow: !config || config.shadow !== false
22879     });
22880     this.ghost = Roo.get(this.el.dom.childNodes[1]);
22881     this.dropStatus = this.dropNotAllowed;
22882 };
22883
22884 Roo.dd.StatusProxy.prototype = {
22885     /**
22886      * @cfg {String} dropAllowed
22887      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22888      */
22889     dropAllowed : "x-dd-drop-ok",
22890     /**
22891      * @cfg {String} dropNotAllowed
22892      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22893      */
22894     dropNotAllowed : "x-dd-drop-nodrop",
22895
22896     /**
22897      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22898      * over the current target element.
22899      * @param {String} cssClass The css class for the new drop status indicator image
22900      */
22901     setStatus : function(cssClass){
22902         cssClass = cssClass || this.dropNotAllowed;
22903         if(this.dropStatus != cssClass){
22904             this.el.replaceClass(this.dropStatus, cssClass);
22905             this.dropStatus = cssClass;
22906         }
22907     },
22908
22909     /**
22910      * Resets the status indicator to the default dropNotAllowed value
22911      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22912      */
22913     reset : function(clearGhost){
22914         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22915         this.dropStatus = this.dropNotAllowed;
22916         if(clearGhost){
22917             this.ghost.update("");
22918         }
22919     },
22920
22921     /**
22922      * Updates the contents of the ghost element
22923      * @param {String} html The html that will replace the current innerHTML of the ghost element
22924      */
22925     update : function(html){
22926         if(typeof html == "string"){
22927             this.ghost.update(html);
22928         }else{
22929             this.ghost.update("");
22930             html.style.margin = "0";
22931             this.ghost.dom.appendChild(html);
22932         }
22933         // ensure float = none set?? cant remember why though.
22934         var el = this.ghost.dom.firstChild;
22935                 if(el){
22936                         Roo.fly(el).setStyle('float', 'none');
22937                 }
22938     },
22939     
22940     /**
22941      * Returns the underlying proxy {@link Roo.Layer}
22942      * @return {Roo.Layer} el
22943     */
22944     getEl : function(){
22945         return this.el;
22946     },
22947
22948     /**
22949      * Returns the ghost element
22950      * @return {Roo.Element} el
22951      */
22952     getGhost : function(){
22953         return this.ghost;
22954     },
22955
22956     /**
22957      * Hides the proxy
22958      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22959      */
22960     hide : function(clear){
22961         this.el.hide();
22962         if(clear){
22963             this.reset(true);
22964         }
22965     },
22966
22967     /**
22968      * Stops the repair animation if it's currently running
22969      */
22970     stop : function(){
22971         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22972             this.anim.stop();
22973         }
22974     },
22975
22976     /**
22977      * Displays this proxy
22978      */
22979     show : function(){
22980         this.el.show();
22981     },
22982
22983     /**
22984      * Force the Layer to sync its shadow and shim positions to the element
22985      */
22986     sync : function(){
22987         this.el.sync();
22988     },
22989
22990     /**
22991      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
22992      * invalid drop operation by the item being dragged.
22993      * @param {Array} xy The XY position of the element ([x, y])
22994      * @param {Function} callback The function to call after the repair is complete
22995      * @param {Object} scope The scope in which to execute the callback
22996      */
22997     repair : function(xy, callback, scope){
22998         this.callback = callback;
22999         this.scope = scope;
23000         if(xy && this.animRepair !== false){
23001             this.el.addClass("x-dd-drag-repair");
23002             this.el.hideUnders(true);
23003             this.anim = this.el.shift({
23004                 duration: this.repairDuration || .5,
23005                 easing: 'easeOut',
23006                 xy: xy,
23007                 stopFx: true,
23008                 callback: this.afterRepair,
23009                 scope: this
23010             });
23011         }else{
23012             this.afterRepair();
23013         }
23014     },
23015
23016     // private
23017     afterRepair : function(){
23018         this.hide(true);
23019         if(typeof this.callback == "function"){
23020             this.callback.call(this.scope || this);
23021         }
23022         this.callback = null;
23023         this.scope = null;
23024     }
23025 };/*
23026  * Based on:
23027  * Ext JS Library 1.1.1
23028  * Copyright(c) 2006-2007, Ext JS, LLC.
23029  *
23030  * Originally Released Under LGPL - original licence link has changed is not relivant.
23031  *
23032  * Fork - LGPL
23033  * <script type="text/javascript">
23034  */
23035
23036 /**
23037  * @class Roo.dd.DragSource
23038  * @extends Roo.dd.DDProxy
23039  * A simple class that provides the basic implementation needed to make any element draggable.
23040  * @constructor
23041  * @param {String/HTMLElement/Element} el The container element
23042  * @param {Object} config
23043  */
23044 Roo.dd.DragSource = function(el, config){
23045     this.el = Roo.get(el);
23046     this.dragData = {};
23047     
23048     Roo.apply(this, config);
23049     
23050     if(!this.proxy){
23051         this.proxy = new Roo.dd.StatusProxy();
23052     }
23053
23054     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23055           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23056     
23057     this.dragging = false;
23058 };
23059
23060 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23061     /**
23062      * @cfg {String} dropAllowed
23063      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23064      */
23065     dropAllowed : "x-dd-drop-ok",
23066     /**
23067      * @cfg {String} dropNotAllowed
23068      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23069      */
23070     dropNotAllowed : "x-dd-drop-nodrop",
23071
23072     /**
23073      * Returns the data object associated with this drag source
23074      * @return {Object} data An object containing arbitrary data
23075      */
23076     getDragData : function(e){
23077         return this.dragData;
23078     },
23079
23080     // private
23081     onDragEnter : function(e, id){
23082         var target = Roo.dd.DragDropMgr.getDDById(id);
23083         this.cachedTarget = target;
23084         if(this.beforeDragEnter(target, e, id) !== false){
23085             if(target.isNotifyTarget){
23086                 var status = target.notifyEnter(this, e, this.dragData);
23087                 this.proxy.setStatus(status);
23088             }else{
23089                 this.proxy.setStatus(this.dropAllowed);
23090             }
23091             
23092             if(this.afterDragEnter){
23093                 /**
23094                  * An empty function by default, but provided so that you can perform a custom action
23095                  * when the dragged item enters the drop target by providing an implementation.
23096                  * @param {Roo.dd.DragDrop} target The drop target
23097                  * @param {Event} e The event object
23098                  * @param {String} id The id of the dragged element
23099                  * @method afterDragEnter
23100                  */
23101                 this.afterDragEnter(target, e, id);
23102             }
23103         }
23104     },
23105
23106     /**
23107      * An empty function by default, but provided so that you can perform a custom action
23108      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23109      * @param {Roo.dd.DragDrop} target The drop target
23110      * @param {Event} e The event object
23111      * @param {String} id The id of the dragged element
23112      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23113      */
23114     beforeDragEnter : function(target, e, id){
23115         return true;
23116     },
23117
23118     // private
23119     alignElWithMouse: function() {
23120         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23121         this.proxy.sync();
23122     },
23123
23124     // private
23125     onDragOver : function(e, id){
23126         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23127         if(this.beforeDragOver(target, e, id) !== false){
23128             if(target.isNotifyTarget){
23129                 var status = target.notifyOver(this, e, this.dragData);
23130                 this.proxy.setStatus(status);
23131             }
23132
23133             if(this.afterDragOver){
23134                 /**
23135                  * An empty function by default, but provided so that you can perform a custom action
23136                  * while the dragged item is over the drop target by providing an implementation.
23137                  * @param {Roo.dd.DragDrop} target The drop target
23138                  * @param {Event} e The event object
23139                  * @param {String} id The id of the dragged element
23140                  * @method afterDragOver
23141                  */
23142                 this.afterDragOver(target, e, id);
23143             }
23144         }
23145     },
23146
23147     /**
23148      * An empty function by default, but provided so that you can perform a custom action
23149      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23150      * @param {Roo.dd.DragDrop} target The drop target
23151      * @param {Event} e The event object
23152      * @param {String} id The id of the dragged element
23153      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23154      */
23155     beforeDragOver : function(target, e, id){
23156         return true;
23157     },
23158
23159     // private
23160     onDragOut : function(e, id){
23161         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23162         if(this.beforeDragOut(target, e, id) !== false){
23163             if(target.isNotifyTarget){
23164                 target.notifyOut(this, e, this.dragData);
23165             }
23166             this.proxy.reset();
23167             if(this.afterDragOut){
23168                 /**
23169                  * An empty function by default, but provided so that you can perform a custom action
23170                  * after the dragged item is dragged out of the target without dropping.
23171                  * @param {Roo.dd.DragDrop} target The drop target
23172                  * @param {Event} e The event object
23173                  * @param {String} id The id of the dragged element
23174                  * @method afterDragOut
23175                  */
23176                 this.afterDragOut(target, e, id);
23177             }
23178         }
23179         this.cachedTarget = null;
23180     },
23181
23182     /**
23183      * An empty function by default, but provided so that you can perform a custom action before the dragged
23184      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23185      * @param {Roo.dd.DragDrop} target The drop target
23186      * @param {Event} e The event object
23187      * @param {String} id The id of the dragged element
23188      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23189      */
23190     beforeDragOut : function(target, e, id){
23191         return true;
23192     },
23193     
23194     // private
23195     onDragDrop : function(e, id){
23196         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23197         if(this.beforeDragDrop(target, e, id) !== false){
23198             if(target.isNotifyTarget){
23199                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23200                     this.onValidDrop(target, e, id);
23201                 }else{
23202                     this.onInvalidDrop(target, e, id);
23203                 }
23204             }else{
23205                 this.onValidDrop(target, e, id);
23206             }
23207             
23208             if(this.afterDragDrop){
23209                 /**
23210                  * An empty function by default, but provided so that you can perform a custom action
23211                  * after a valid drag drop has occurred by providing an implementation.
23212                  * @param {Roo.dd.DragDrop} target The drop target
23213                  * @param {Event} e The event object
23214                  * @param {String} id The id of the dropped element
23215                  * @method afterDragDrop
23216                  */
23217                 this.afterDragDrop(target, e, id);
23218             }
23219         }
23220         delete this.cachedTarget;
23221     },
23222
23223     /**
23224      * An empty function by default, but provided so that you can perform a custom action before the dragged
23225      * item is dropped onto the target and optionally cancel the onDragDrop.
23226      * @param {Roo.dd.DragDrop} target The drop target
23227      * @param {Event} e The event object
23228      * @param {String} id The id of the dragged element
23229      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23230      */
23231     beforeDragDrop : function(target, e, id){
23232         return true;
23233     },
23234
23235     // private
23236     onValidDrop : function(target, e, id){
23237         this.hideProxy();
23238         if(this.afterValidDrop){
23239             /**
23240              * An empty function by default, but provided so that you can perform a custom action
23241              * after a valid drop has occurred by providing an implementation.
23242              * @param {Object} target The target DD 
23243              * @param {Event} e The event object
23244              * @param {String} id The id of the dropped element
23245              * @method afterInvalidDrop
23246              */
23247             this.afterValidDrop(target, e, id);
23248         }
23249     },
23250
23251     // private
23252     getRepairXY : function(e, data){
23253         return this.el.getXY();  
23254     },
23255
23256     // private
23257     onInvalidDrop : function(target, e, id){
23258         this.beforeInvalidDrop(target, e, id);
23259         if(this.cachedTarget){
23260             if(this.cachedTarget.isNotifyTarget){
23261                 this.cachedTarget.notifyOut(this, e, this.dragData);
23262             }
23263             this.cacheTarget = null;
23264         }
23265         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23266
23267         if(this.afterInvalidDrop){
23268             /**
23269              * An empty function by default, but provided so that you can perform a custom action
23270              * after an invalid drop has occurred by providing an implementation.
23271              * @param {Event} e The event object
23272              * @param {String} id The id of the dropped element
23273              * @method afterInvalidDrop
23274              */
23275             this.afterInvalidDrop(e, id);
23276         }
23277     },
23278
23279     // private
23280     afterRepair : function(){
23281         if(Roo.enableFx){
23282             this.el.highlight(this.hlColor || "c3daf9");
23283         }
23284         this.dragging = false;
23285     },
23286
23287     /**
23288      * An empty function by default, but provided so that you can perform a custom action after an invalid
23289      * drop has occurred.
23290      * @param {Roo.dd.DragDrop} target The drop target
23291      * @param {Event} e The event object
23292      * @param {String} id The id of the dragged element
23293      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23294      */
23295     beforeInvalidDrop : function(target, e, id){
23296         return true;
23297     },
23298
23299     // private
23300     handleMouseDown : function(e){
23301         if(this.dragging) {
23302             return;
23303         }
23304         var data = this.getDragData(e);
23305         if(data && this.onBeforeDrag(data, e) !== false){
23306             this.dragData = data;
23307             this.proxy.stop();
23308             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23309         } 
23310     },
23311
23312     /**
23313      * An empty function by default, but provided so that you can perform a custom action before the initial
23314      * drag event begins and optionally cancel it.
23315      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23316      * @param {Event} e The event object
23317      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23318      */
23319     onBeforeDrag : function(data, e){
23320         return true;
23321     },
23322
23323     /**
23324      * An empty function by default, but provided so that you can perform a custom action once the initial
23325      * drag event has begun.  The drag cannot be canceled from this function.
23326      * @param {Number} x The x position of the click on the dragged object
23327      * @param {Number} y The y position of the click on the dragged object
23328      */
23329     onStartDrag : Roo.emptyFn,
23330
23331     // private - YUI override
23332     startDrag : function(x, y){
23333         this.proxy.reset();
23334         this.dragging = true;
23335         this.proxy.update("");
23336         this.onInitDrag(x, y);
23337         this.proxy.show();
23338     },
23339
23340     // private
23341     onInitDrag : function(x, y){
23342         var clone = this.el.dom.cloneNode(true);
23343         clone.id = Roo.id(); // prevent duplicate ids
23344         this.proxy.update(clone);
23345         this.onStartDrag(x, y);
23346         return true;
23347     },
23348
23349     /**
23350      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23351      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23352      */
23353     getProxy : function(){
23354         return this.proxy;  
23355     },
23356
23357     /**
23358      * Hides the drag source's {@link Roo.dd.StatusProxy}
23359      */
23360     hideProxy : function(){
23361         this.proxy.hide();  
23362         this.proxy.reset(true);
23363         this.dragging = false;
23364     },
23365
23366     // private
23367     triggerCacheRefresh : function(){
23368         Roo.dd.DDM.refreshCache(this.groups);
23369     },
23370
23371     // private - override to prevent hiding
23372     b4EndDrag: function(e) {
23373     },
23374
23375     // private - override to prevent moving
23376     endDrag : function(e){
23377         this.onEndDrag(this.dragData, e);
23378     },
23379
23380     // private
23381     onEndDrag : function(data, e){
23382     },
23383     
23384     // private - pin to cursor
23385     autoOffset : function(x, y) {
23386         this.setDelta(-12, -20);
23387     }    
23388 });/*
23389  * Based on:
23390  * Ext JS Library 1.1.1
23391  * Copyright(c) 2006-2007, Ext JS, LLC.
23392  *
23393  * Originally Released Under LGPL - original licence link has changed is not relivant.
23394  *
23395  * Fork - LGPL
23396  * <script type="text/javascript">
23397  */
23398
23399
23400 /**
23401  * @class Roo.dd.DropTarget
23402  * @extends Roo.dd.DDTarget
23403  * A simple class that provides the basic implementation needed to make any element a drop target that can have
23404  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
23405  * @constructor
23406  * @param {String/HTMLElement/Element} el The container element
23407  * @param {Object} config
23408  */
23409 Roo.dd.DropTarget = function(el, config){
23410     this.el = Roo.get(el);
23411     
23412     var listeners = false; ;
23413     if (config && config.listeners) {
23414         listeners= config.listeners;
23415         delete config.listeners;
23416     }
23417     Roo.apply(this, config);
23418     
23419     if(this.containerScroll){
23420         Roo.dd.ScrollManager.register(this.el);
23421     }
23422     this.addEvents( {
23423          /**
23424          * @scope Roo.dd.DropTarget
23425          */
23426          
23427          /**
23428          * @event enter
23429          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23430          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
23431          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
23432          * 
23433          * IMPORTANT : it should set  this.valid to true|false
23434          * 
23435          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23436          * @param {Event} e The event
23437          * @param {Object} data An object containing arbitrary data supplied by the drag source
23438          */
23439         "enter" : true,
23440         
23441          /**
23442          * @event over
23443          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23444          * This method will be called on every mouse movement while the drag source is over the drop target.
23445          * This default implementation simply returns the dropAllowed config value.
23446          * 
23447          * IMPORTANT : it should set  this.valid to true|false
23448          * 
23449          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23450          * @param {Event} e The event
23451          * @param {Object} data An object containing arbitrary data supplied by the drag source
23452          
23453          */
23454         "over" : true,
23455         /**
23456          * @event out
23457          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23458          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
23459          * overClass (if any) from the drop element.
23460          * 
23461          * 
23462          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23463          * @param {Event} e The event
23464          * @param {Object} data An object containing arbitrary data supplied by the drag source
23465          */
23466          "out" : true,
23467          
23468         /**
23469          * @event drop
23470          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23471          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
23472          * implementation that does something to process the drop event and returns true so that the drag source's
23473          * repair action does not run.
23474          * 
23475          * IMPORTANT : it should set this.success
23476          * 
23477          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23478          * @param {Event} e The event
23479          * @param {Object} data An object containing arbitrary data supplied by the drag source
23480         */
23481          "drop" : true
23482     });
23483             
23484      
23485     Roo.dd.DropTarget.superclass.constructor.call(  this, 
23486         this.el.dom, 
23487         this.ddGroup || this.group,
23488         {
23489             isTarget: true,
23490             listeners : listeners || {} 
23491            
23492         
23493         }
23494     );
23495
23496 };
23497
23498 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23499     /**
23500      * @cfg {String} overClass
23501      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23502      */
23503      /**
23504      * @cfg {String} ddGroup
23505      * The drag drop group to handle drop events for
23506      */
23507      
23508     /**
23509      * @cfg {String} dropAllowed
23510      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23511      */
23512     dropAllowed : "x-dd-drop-ok",
23513     /**
23514      * @cfg {String} dropNotAllowed
23515      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23516      */
23517     dropNotAllowed : "x-dd-drop-nodrop",
23518     /**
23519      * @cfg {boolean} success
23520      * set this after drop listener.. 
23521      */
23522     success : false,
23523     /**
23524      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23525      * if the drop point is valid for over/enter..
23526      */
23527     valid : false,
23528     // private
23529     isTarget : true,
23530
23531     // private
23532     isNotifyTarget : true,
23533     
23534     /**
23535      * @hide
23536      */
23537     notifyEnter : function(dd, e, data)
23538     {
23539         this.valid = true;
23540         this.fireEvent('enter', dd, e, data);
23541         if(this.overClass){
23542             this.el.addClass(this.overClass);
23543         }
23544         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23545             this.valid ? this.dropAllowed : this.dropNotAllowed
23546         );
23547     },
23548
23549     /**
23550      * @hide
23551      */
23552     notifyOver : function(dd, e, data)
23553     {
23554         this.valid = true;
23555         this.fireEvent('over', dd, e, data);
23556         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23557             this.valid ? this.dropAllowed : this.dropNotAllowed
23558         );
23559     },
23560
23561     /**
23562      * @hide
23563      */
23564     notifyOut : function(dd, e, data)
23565     {
23566         this.fireEvent('out', dd, e, data);
23567         if(this.overClass){
23568             this.el.removeClass(this.overClass);
23569         }
23570     },
23571
23572     /**
23573      * @hide
23574      */
23575     notifyDrop : function(dd, e, data)
23576     {
23577         this.success = false;
23578         this.fireEvent('drop', dd, e, data);
23579         return this.success;
23580     }
23581 });/*
23582  * Based on:
23583  * Ext JS Library 1.1.1
23584  * Copyright(c) 2006-2007, Ext JS, LLC.
23585  *
23586  * Originally Released Under LGPL - original licence link has changed is not relivant.
23587  *
23588  * Fork - LGPL
23589  * <script type="text/javascript">
23590  */
23591
23592
23593 /**
23594  * @class Roo.dd.DragZone
23595  * @extends Roo.dd.DragSource
23596  * This class provides a container DD instance that proxies for multiple child node sources.<br />
23597  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23598  * @constructor
23599  * @param {String/HTMLElement/Element} el The container element
23600  * @param {Object} config
23601  */
23602 Roo.dd.DragZone = function(el, config){
23603     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23604     if(this.containerScroll){
23605         Roo.dd.ScrollManager.register(this.el);
23606     }
23607 };
23608
23609 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23610     /**
23611      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23612      * for auto scrolling during drag operations.
23613      */
23614     /**
23615      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23616      * method after a failed drop (defaults to "c3daf9" - light blue)
23617      */
23618
23619     /**
23620      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23621      * for a valid target to drag based on the mouse down. Override this method
23622      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23623      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23624      * @param {EventObject} e The mouse down event
23625      * @return {Object} The dragData
23626      */
23627     getDragData : function(e){
23628         return Roo.dd.Registry.getHandleFromEvent(e);
23629     },
23630     
23631     /**
23632      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23633      * this.dragData.ddel
23634      * @param {Number} x The x position of the click on the dragged object
23635      * @param {Number} y The y position of the click on the dragged object
23636      * @return {Boolean} true to continue the drag, false to cancel
23637      */
23638     onInitDrag : function(x, y){
23639         this.proxy.update(this.dragData.ddel.cloneNode(true));
23640         this.onStartDrag(x, y);
23641         return true;
23642     },
23643     
23644     /**
23645      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
23646      */
23647     afterRepair : function(){
23648         if(Roo.enableFx){
23649             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23650         }
23651         this.dragging = false;
23652     },
23653
23654     /**
23655      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23656      * the XY of this.dragData.ddel
23657      * @param {EventObject} e The mouse up event
23658      * @return {Array} The xy location (e.g. [100, 200])
23659      */
23660     getRepairXY : function(e){
23661         return Roo.Element.fly(this.dragData.ddel).getXY();  
23662     }
23663 });/*
23664  * Based on:
23665  * Ext JS Library 1.1.1
23666  * Copyright(c) 2006-2007, Ext JS, LLC.
23667  *
23668  * Originally Released Under LGPL - original licence link has changed is not relivant.
23669  *
23670  * Fork - LGPL
23671  * <script type="text/javascript">
23672  */
23673 /**
23674  * @class Roo.dd.DropZone
23675  * @extends Roo.dd.DropTarget
23676  * This class provides a container DD instance that proxies for multiple child node targets.<br />
23677  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23678  * @constructor
23679  * @param {String/HTMLElement/Element} el The container element
23680  * @param {Object} config
23681  */
23682 Roo.dd.DropZone = function(el, config){
23683     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23684 };
23685
23686 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23687     /**
23688      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
23689      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23690      * provide your own custom lookup.
23691      * @param {Event} e The event
23692      * @return {Object} data The custom data
23693      */
23694     getTargetFromEvent : function(e){
23695         return Roo.dd.Registry.getTargetFromEvent(e);
23696     },
23697
23698     /**
23699      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
23700      * that it has registered.  This method has no default implementation and should be overridden to provide
23701      * node-specific processing if necessary.
23702      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
23703      * {@link #getTargetFromEvent} for this node)
23704      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23705      * @param {Event} e The event
23706      * @param {Object} data An object containing arbitrary data supplied by the drag source
23707      */
23708     onNodeEnter : function(n, dd, e, data){
23709         
23710     },
23711
23712     /**
23713      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23714      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
23715      * overridden to provide the proper feedback.
23716      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23717      * {@link #getTargetFromEvent} for this node)
23718      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23719      * @param {Event} e The event
23720      * @param {Object} data An object containing arbitrary data supplied by the drag source
23721      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23722      * underlying {@link Roo.dd.StatusProxy} can be updated
23723      */
23724     onNodeOver : function(n, dd, e, data){
23725         return this.dropAllowed;
23726     },
23727
23728     /**
23729      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23730      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
23731      * node-specific processing if necessary.
23732      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23733      * {@link #getTargetFromEvent} for this node)
23734      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23735      * @param {Event} e The event
23736      * @param {Object} data An object containing arbitrary data supplied by the drag source
23737      */
23738     onNodeOut : function(n, dd, e, data){
23739         
23740     },
23741
23742     /**
23743      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23744      * the drop node.  The default implementation returns false, so it should be overridden to provide the
23745      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23746      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23747      * {@link #getTargetFromEvent} for this node)
23748      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23749      * @param {Event} e The event
23750      * @param {Object} data An object containing arbitrary data supplied by the drag source
23751      * @return {Boolean} True if the drop was valid, else false
23752      */
23753     onNodeDrop : function(n, dd, e, data){
23754         return false;
23755     },
23756
23757     /**
23758      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23759      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
23760      * it should be overridden to provide the proper feedback if necessary.
23761      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23762      * @param {Event} e The event
23763      * @param {Object} data An object containing arbitrary data supplied by the drag source
23764      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23765      * underlying {@link Roo.dd.StatusProxy} can be updated
23766      */
23767     onContainerOver : function(dd, e, data){
23768         return this.dropNotAllowed;
23769     },
23770
23771     /**
23772      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23773      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
23774      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23775      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
23776      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23777      * @param {Event} e The event
23778      * @param {Object} data An object containing arbitrary data supplied by the drag source
23779      * @return {Boolean} True if the drop was valid, else false
23780      */
23781     onContainerDrop : function(dd, e, data){
23782         return false;
23783     },
23784
23785     /**
23786      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23787      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
23788      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23789      * you should override this method and provide a custom implementation.
23790      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23791      * @param {Event} e The event
23792      * @param {Object} data An object containing arbitrary data supplied by the drag source
23793      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23794      * underlying {@link Roo.dd.StatusProxy} can be updated
23795      */
23796     notifyEnter : function(dd, e, data){
23797         return this.dropNotAllowed;
23798     },
23799
23800     /**
23801      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23802      * This method will be called on every mouse movement while the drag source is over the drop zone.
23803      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23804      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23805      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23806      * registered node, it will call {@link #onContainerOver}.
23807      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23808      * @param {Event} e The event
23809      * @param {Object} data An object containing arbitrary data supplied by the drag source
23810      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23811      * underlying {@link Roo.dd.StatusProxy} can be updated
23812      */
23813     notifyOver : function(dd, e, data){
23814         var n = this.getTargetFromEvent(e);
23815         if(!n){ // not over valid drop target
23816             if(this.lastOverNode){
23817                 this.onNodeOut(this.lastOverNode, dd, e, data);
23818                 this.lastOverNode = null;
23819             }
23820             return this.onContainerOver(dd, e, data);
23821         }
23822         if(this.lastOverNode != n){
23823             if(this.lastOverNode){
23824                 this.onNodeOut(this.lastOverNode, dd, e, data);
23825             }
23826             this.onNodeEnter(n, dd, e, data);
23827             this.lastOverNode = n;
23828         }
23829         return this.onNodeOver(n, dd, e, data);
23830     },
23831
23832     /**
23833      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23834      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
23835      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23836      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23837      * @param {Event} e The event
23838      * @param {Object} data An object containing arbitrary data supplied by the drag zone
23839      */
23840     notifyOut : function(dd, e, data){
23841         if(this.lastOverNode){
23842             this.onNodeOut(this.lastOverNode, dd, e, data);
23843             this.lastOverNode = null;
23844         }
23845     },
23846
23847     /**
23848      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23849      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
23850      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23851      * otherwise it will call {@link #onContainerDrop}.
23852      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23853      * @param {Event} e The event
23854      * @param {Object} data An object containing arbitrary data supplied by the drag source
23855      * @return {Boolean} True if the drop was valid, else false
23856      */
23857     notifyDrop : function(dd, e, data){
23858         if(this.lastOverNode){
23859             this.onNodeOut(this.lastOverNode, dd, e, data);
23860             this.lastOverNode = null;
23861         }
23862         var n = this.getTargetFromEvent(e);
23863         return n ?
23864             this.onNodeDrop(n, dd, e, data) :
23865             this.onContainerDrop(dd, e, data);
23866     },
23867
23868     // private
23869     triggerCacheRefresh : function(){
23870         Roo.dd.DDM.refreshCache(this.groups);
23871     }  
23872 });