fix #6962 - new editor
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @static
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 } 
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux" 
704                );
705 /*
706  * Based on:
707  * Ext JS Library 1.1.1
708  * Copyright(c) 2006-2007, Ext JS, LLC.
709  *
710  * Originally Released Under LGPL - original licence link has changed is not relivant.
711  *
712  * Fork - LGPL
713  * <script type="text/javascript">
714  */
715
716 (function() {    
717     // wrappedn so fnCleanup is not in global scope...
718     if(Roo.isIE) {
719         function fnCleanUp() {
720             var p = Function.prototype;
721             delete p.createSequence;
722             delete p.defer;
723             delete p.createDelegate;
724             delete p.createCallback;
725             delete p.createInterceptor;
726
727             window.detachEvent("onunload", fnCleanUp);
728         }
729         window.attachEvent("onunload", fnCleanUp);
730     }
731 })();
732
733
734 /**
735  * @class Function
736  * These functions are available on every Function object (any JavaScript function).
737  */
738 Roo.apply(Function.prototype, {
739      /**
740      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742      * Will create a function that is bound to those 2 args.
743      * @return {Function} The new function
744     */
745     createCallback : function(/*args...*/){
746         // make args available, in function below
747         var args = arguments;
748         var method = this;
749         return function() {
750             return method.apply(window, args);
751         };
752     },
753
754     /**
755      * Creates a delegate (callback) that sets the scope to obj.
756      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757      * Will create a function that is automatically scoped to this.
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Function} The new function
763      */
764     createDelegate : function(obj, args, appendArgs){
765         var method = this;
766         return function() {
767             var callArgs = args || arguments;
768             if(appendArgs === true){
769                 callArgs = Array.prototype.slice.call(arguments, 0);
770                 callArgs = callArgs.concat(args);
771             }else if(typeof appendArgs == "number"){
772                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
775             }
776             return method.apply(obj || window, callArgs);
777         };
778     },
779
780     /**
781      * Calls this function after the number of millseconds specified.
782      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783      * @param {Object} obj (optional) The object for which the scope is set
784      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786      *                                             if a number the args are inserted at the specified position
787      * @return {Number} The timeout id that can be used with clearTimeout
788      */
789     defer : function(millis, obj, args, appendArgs){
790         var fn = this.createDelegate(obj, args, appendArgs);
791         if(millis){
792             return setTimeout(fn, millis);
793         }
794         fn();
795         return 0;
796     },
797     /**
798      * Create a combined function call sequence of the original function + the passed function.
799      * The resulting function returns the results of the original function.
800      * The passed fcn is called with the parameters of the original function
801      * @param {Function} fcn The function to sequence
802      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803      * @return {Function} The new function
804      */
805     createSequence : function(fcn, scope){
806         if(typeof fcn != "function"){
807             return this;
808         }
809         var method = this;
810         return function() {
811             var retval = method.apply(this || window, arguments);
812             fcn.apply(scope || this || window, arguments);
813             return retval;
814         };
815     },
816
817     /**
818      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819      * The resulting function returns the results of the original function.
820      * The passed fcn is called with the parameters of the original function.
821      * @addon
822      * @param {Function} fcn The function to call before the original
823      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824      * @return {Function} The new function
825      */
826     createInterceptor : function(fcn, scope){
827         if(typeof fcn != "function"){
828             return this;
829         }
830         var method = this;
831         return function() {
832             fcn.target = this;
833             fcn.method = method;
834             if(fcn.apply(scope || this || window, arguments) === false){
835                 return;
836             }
837             return method.apply(this || window, arguments);
838         };
839     }
840 });
841 /*
842  * Based on:
843  * Ext JS Library 1.1.1
844  * Copyright(c) 2006-2007, Ext JS, LLC.
845  *
846  * Originally Released Under LGPL - original licence link has changed is not relivant.
847  *
848  * Fork - LGPL
849  * <script type="text/javascript">
850  */
851
852 Roo.applyIf(String, {
853     
854     /** @scope String */
855     
856     /**
857      * Escapes the passed string for ' and \
858      * @param {String} string The string to escape
859      * @return {String} The escaped string
860      * @static
861      */
862     escape : function(string) {
863         return string.replace(/('|\\)/g, "\\$1");
864     },
865
866     /**
867      * Pads the left side of a string with a specified character.  This is especially useful
868      * for normalizing number and date strings.  Example usage:
869      * <pre><code>
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
872 </code></pre>
873      * @param {String} string The original string
874      * @param {Number} size The total length of the output string
875      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876      * @return {String} The padded string
877      * @static
878      */
879     leftPad : function (val, size, ch) {
880         var result = new String(val);
881         if(ch === null || ch === undefined || ch === '') {
882             ch = " ";
883         }
884         while (result.length < size) {
885             result = ch + result;
886         }
887         return result;
888     },
889
890     /**
891      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
892      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
893      * <pre><code>
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
897 </code></pre>
898      * @param {String} string The tokenized string to be formatted
899      * @param {String} value1 The value to replace token {0}
900      * @param {String} value2 Etc...
901      * @return {String} The formatted string
902      * @static
903      */
904     format : function(format){
905         var args = Array.prototype.slice.call(arguments, 1);
906         return format.replace(/\{(\d+)\}/g, function(m, i){
907             return Roo.util.Format.htmlEncode(args[i]);
908         });
909     }
910   
911     
912 });
913
914 /**
915  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
916  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
917  * they are already different, the first value passed in is returned.  Note that this method returns the new value
918  * but does not change the current string.
919  * <pre><code>
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
922
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
925 </code></pre>
926  * @param {String} value The value to compare to the current string
927  * @param {String} other The new value to use if the string already equals the first value passed in
928  * @return {String} The new value
929  */
930  
931 String.prototype.toggle = function(value, other){
932     return this == value ? other : value;
933 };
934
935
936 /**
937   * Remove invalid unicode characters from a string 
938   *
939   * @return {String} The clean string
940   */
941 String.prototype.unicodeClean = function () {
942     return this.replace(/[\s\S]/g,
943         function(character) {
944             if (character.charCodeAt()< 256) {
945               return character;
946            }
947            try {
948                 encodeURIComponent(character);
949            } catch(e) { 
950               return '';
951            }
952            return character;
953         }
954     );
955 };
956   
957
958 /**
959   * Make the first letter of a string uppercase
960   *
961   * @return {String} The new string.
962   */
963 String.prototype.toUpperCaseFirst = function () {
964     return this.charAt(0).toUpperCase() + this.slice(1);
965 };  
966   
967 /*
968  * Based on:
969  * Ext JS Library 1.1.1
970  * Copyright(c) 2006-2007, Ext JS, LLC.
971  *
972  * Originally Released Under LGPL - original licence link has changed is not relivant.
973  *
974  * Fork - LGPL
975  * <script type="text/javascript">
976  */
977
978  /**
979  * @class Number
980  */
981 Roo.applyIf(Number.prototype, {
982     /**
983      * Checks whether or not the current number is within a desired range.  If the number is already within the
984      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
985      * exceeded.  Note that this method returns the constrained value but does not change the current number.
986      * @param {Number} min The minimum number in the range
987      * @param {Number} max The maximum number in the range
988      * @return {Number} The constrained value if outside the range, otherwise the current value
989      */
990     constrain : function(min, max){
991         return Math.min(Math.max(this, min), max);
992     }
993 });/*
994  * Based on:
995  * Ext JS Library 1.1.1
996  * Copyright(c) 2006-2007, Ext JS, LLC.
997  *
998  * Originally Released Under LGPL - original licence link has changed is not relivant.
999  *
1000  * Fork - LGPL
1001  * <script type="text/javascript">
1002  */
1003  /**
1004  * @class Array
1005  */
1006 Roo.applyIf(Array.prototype, {
1007     /**
1008      * 
1009      * Checks whether or not the specified object exists in the array.
1010      * @param {Object} o The object to check for
1011      * @return {Number} The index of o in the array (or -1 if it is not found)
1012      */
1013     indexOf : function(o){
1014        for (var i = 0, len = this.length; i < len; i++){
1015               if(this[i] == o) { return i; }
1016        }
1017            return -1;
1018     },
1019
1020     /**
1021      * Removes the specified object from the array.  If the object is not found nothing happens.
1022      * @param {Object} o The object to remove
1023      */
1024     remove : function(o){
1025        var index = this.indexOf(o);
1026        if(index != -1){
1027            this.splice(index, 1);
1028        }
1029     },
1030     /**
1031      * Map (JS 1.6 compatibility)
1032      * @param {Function} function  to call
1033      */
1034     map : function(fun )
1035     {
1036         var len = this.length >>> 0;
1037         if (typeof fun != "function") {
1038             throw new TypeError();
1039         }
1040         var res = new Array(len);
1041         var thisp = arguments[1];
1042         for (var i = 0; i < len; i++)
1043         {
1044             if (i in this) {
1045                 res[i] = fun.call(thisp, this[i], i, this);
1046             }
1047         }
1048
1049         return res;
1050     },
1051     /**
1052      * equals
1053      * @param {Array} o The array to compare to
1054      * @returns {Boolean} true if the same
1055      */
1056     equals : function(b)
1057     {
1058             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1059         if (this === b) {
1060             return true;
1061         }
1062         if (b == null) {
1063             return false;
1064         }
1065         if (this.length !== b.length) {
1066             return false;
1067         }
1068           
1069         // sort?? a.sort().equals(b.sort());
1070           
1071         for (var i = 0; i < this.length; ++i) {
1072             if (this[i] !== b[i]) {
1073             return false;
1074             }
1075         }
1076         return true;
1077     } 
1078     
1079     
1080     
1081     
1082 });
1083
1084 Roo.applyIf(Array, {
1085  /**
1086      * from
1087      * @static
1088      * @param {Array} o Or Array like object (eg. nodelist)
1089      * @returns {Array} 
1090      */
1091     from : function(o)
1092     {
1093         var ret= [];
1094     
1095         for (var i =0; i < o.length; i++) { 
1096             ret[i] = o[i];
1097         }
1098         return ret;
1099       
1100     }
1101 });
1102 /*
1103  * Based on:
1104  * Ext JS Library 1.1.1
1105  * Copyright(c) 2006-2007, Ext JS, LLC.
1106  *
1107  * Originally Released Under LGPL - original licence link has changed is not relivant.
1108  *
1109  * Fork - LGPL
1110  * <script type="text/javascript">
1111  */
1112
1113 /**
1114  * @class Date
1115  *
1116  * The date parsing and format syntax is a subset of
1117  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1118  * supported will provide results equivalent to their PHP versions.
1119  *
1120  * Following is the list of all currently supported formats:
1121  *<pre>
1122 Sample date:
1123 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1124
1125 Format  Output      Description
1126 ------  ----------  --------------------------------------------------------------
1127   d      10         Day of the month, 2 digits with leading zeros
1128   D      Wed        A textual representation of a day, three letters
1129   j      10         Day of the month without leading zeros
1130   l      Wednesday  A full textual representation of the day of the week
1131   S      th         English ordinal day of month suffix, 2 chars (use with j)
1132   w      3          Numeric representation of the day of the week
1133   z      9          The julian date, or day of the year (0-365)
1134   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1135   F      January    A full textual representation of the month
1136   m      01         Numeric representation of a month, with leading zeros
1137   M      Jan        Month name abbreviation, three letters
1138   n      1          Numeric representation of a month, without leading zeros
1139   t      31         Number of days in the given month
1140   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1141   Y      2007       A full numeric representation of a year, 4 digits
1142   y      07         A two digit representation of a year
1143   a      pm         Lowercase Ante meridiem and Post meridiem
1144   A      PM         Uppercase Ante meridiem and Post meridiem
1145   g      3          12-hour format of an hour without leading zeros
1146   G      15         24-hour format of an hour without leading zeros
1147   h      03         12-hour format of an hour with leading zeros
1148   H      15         24-hour format of an hour with leading zeros
1149   i      05         Minutes with leading zeros
1150   s      01         Seconds, with leading zeros
1151   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1152   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1153   T      CST        Timezone setting of the machine running the code
1154   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1155 </pre>
1156  *
1157  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1158  * <pre><code>
1159 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1160 document.write(dt.format('Y-m-d'));                         //2007-01-10
1161 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1162 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1163  </code></pre>
1164  *
1165  * Here are some standard date/time patterns that you might find helpful.  They
1166  * are not part of the source of Date.js, but to use them you can simply copy this
1167  * block of code into any script that is included after Date.js and they will also become
1168  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1169  * <pre><code>
1170 Date.patterns = {
1171     ISO8601Long:"Y-m-d H:i:s",
1172     ISO8601Short:"Y-m-d",
1173     ShortDate: "n/j/Y",
1174     LongDate: "l, F d, Y",
1175     FullDateTime: "l, F d, Y g:i:s A",
1176     MonthDay: "F d",
1177     ShortTime: "g:i A",
1178     LongTime: "g:i:s A",
1179     SortableDateTime: "Y-m-d\\TH:i:s",
1180     UniversalSortableDateTime: "Y-m-d H:i:sO",
1181     YearMonth: "F, Y"
1182 };
1183 </code></pre>
1184  *
1185  * Example usage:
1186  * <pre><code>
1187 var dt = new Date();
1188 document.write(dt.format(Date.patterns.ShortDate));
1189  </code></pre>
1190  */
1191
1192 /*
1193  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1194  * They generate precompiled functions from date formats instead of parsing and
1195  * processing the pattern every time you format a date.  These functions are available
1196  * on every Date object (any javascript function).
1197  *
1198  * The original article and download are here:
1199  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1200  *
1201  */
1202  
1203  
1204  // was in core
1205 /**
1206  Returns the number of milliseconds between this date and date
1207  @param {Date} date (optional) Defaults to now
1208  @return {Number} The diff in milliseconds
1209  @member Date getElapsed
1210  */
1211 Date.prototype.getElapsed = function(date) {
1212         return Math.abs((date || new Date()).getTime()-this.getTime());
1213 };
1214 // was in date file..
1215
1216
1217 // private
1218 Date.parseFunctions = {count:0};
1219 // private
1220 Date.parseRegexes = [];
1221 // private
1222 Date.formatFunctions = {count:0};
1223
1224 // private
1225 Date.prototype.dateFormat = function(format) {
1226     if (Date.formatFunctions[format] == null) {
1227         Date.createNewFormat(format);
1228     }
1229     var func = Date.formatFunctions[format];
1230     return this[func]();
1231 };
1232
1233
1234 /**
1235  * Formats a date given the supplied format string
1236  * @param {String} format The format string
1237  * @return {String} The formatted date
1238  * @method
1239  */
1240 Date.prototype.format = Date.prototype.dateFormat;
1241
1242 // private
1243 Date.createNewFormat = function(format) {
1244     var funcName = "format" + Date.formatFunctions.count++;
1245     Date.formatFunctions[format] = funcName;
1246     var code = "Date.prototype." + funcName + " = function(){return ";
1247     var special = false;
1248     var ch = '';
1249     for (var i = 0; i < format.length; ++i) {
1250         ch = format.charAt(i);
1251         if (!special && ch == "\\") {
1252             special = true;
1253         }
1254         else if (special) {
1255             special = false;
1256             code += "'" + String.escape(ch) + "' + ";
1257         }
1258         else {
1259             code += Date.getFormatCode(ch);
1260         }
1261     }
1262     /** eval:var:zzzzzzzzzzzzz */
1263     eval(code.substring(0, code.length - 3) + ";}");
1264 };
1265
1266 // private
1267 Date.getFormatCode = function(character) {
1268     switch (character) {
1269     case "d":
1270         return "String.leftPad(this.getDate(), 2, '0') + ";
1271     case "D":
1272         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1273     case "j":
1274         return "this.getDate() + ";
1275     case "l":
1276         return "Date.dayNames[this.getDay()] + ";
1277     case "S":
1278         return "this.getSuffix() + ";
1279     case "w":
1280         return "this.getDay() + ";
1281     case "z":
1282         return "this.getDayOfYear() + ";
1283     case "W":
1284         return "this.getWeekOfYear() + ";
1285     case "F":
1286         return "Date.monthNames[this.getMonth()] + ";
1287     case "m":
1288         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1289     case "M":
1290         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1291     case "n":
1292         return "(this.getMonth() + 1) + ";
1293     case "t":
1294         return "this.getDaysInMonth() + ";
1295     case "L":
1296         return "(this.isLeapYear() ? 1 : 0) + ";
1297     case "Y":
1298         return "this.getFullYear() + ";
1299     case "y":
1300         return "('' + this.getFullYear()).substring(2, 4) + ";
1301     case "a":
1302         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1303     case "A":
1304         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1305     case "g":
1306         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1307     case "G":
1308         return "this.getHours() + ";
1309     case "h":
1310         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1311     case "H":
1312         return "String.leftPad(this.getHours(), 2, '0') + ";
1313     case "i":
1314         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1315     case "s":
1316         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1317     case "O":
1318         return "this.getGMTOffset() + ";
1319     case "P":
1320         return "this.getGMTColonOffset() + ";
1321     case "T":
1322         return "this.getTimezone() + ";
1323     case "Z":
1324         return "(this.getTimezoneOffset() * -60) + ";
1325     default:
1326         return "'" + String.escape(character) + "' + ";
1327     }
1328 };
1329
1330 /**
1331  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1332  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1333  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1334  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1335  * string or the parse operation will fail.
1336  * Example Usage:
1337 <pre><code>
1338 //dt = Fri May 25 2007 (current date)
1339 var dt = new Date();
1340
1341 //dt = Thu May 25 2006 (today's month/day in 2006)
1342 dt = Date.parseDate("2006", "Y");
1343
1344 //dt = Sun Jan 15 2006 (all date parts specified)
1345 dt = Date.parseDate("2006-1-15", "Y-m-d");
1346
1347 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1348 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1349 </code></pre>
1350  * @param {String} input The unparsed date as a string
1351  * @param {String} format The format the date is in
1352  * @return {Date} The parsed date
1353  * @static
1354  */
1355 Date.parseDate = function(input, format) {
1356     if (Date.parseFunctions[format] == null) {
1357         Date.createParser(format);
1358     }
1359     var func = Date.parseFunctions[format];
1360     return Date[func](input);
1361 };
1362 /**
1363  * @private
1364  */
1365
1366 Date.createParser = function(format) {
1367     var funcName = "parse" + Date.parseFunctions.count++;
1368     var regexNum = Date.parseRegexes.length;
1369     var currentGroup = 1;
1370     Date.parseFunctions[format] = funcName;
1371
1372     var code = "Date." + funcName + " = function(input){\n"
1373         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1374         + "var d = new Date();\n"
1375         + "y = d.getFullYear();\n"
1376         + "m = d.getMonth();\n"
1377         + "d = d.getDate();\n"
1378         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1379         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1380         + "if (results && results.length > 0) {";
1381     var regex = "";
1382
1383     var special = false;
1384     var ch = '';
1385     for (var i = 0; i < format.length; ++i) {
1386         ch = format.charAt(i);
1387         if (!special && ch == "\\") {
1388             special = true;
1389         }
1390         else if (special) {
1391             special = false;
1392             regex += String.escape(ch);
1393         }
1394         else {
1395             var obj = Date.formatCodeToRegex(ch, currentGroup);
1396             currentGroup += obj.g;
1397             regex += obj.s;
1398             if (obj.g && obj.c) {
1399                 code += obj.c;
1400             }
1401         }
1402     }
1403
1404     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1405         + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1406         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1407         + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1408         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1409         + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1410         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1411         + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1412         + "else if (y >= 0 && m >= 0)\n"
1413         + "{v = new Date(y, m); v.setFullYear(y);}\n"
1414         + "else if (y >= 0)\n"
1415         + "{v = new Date(y); v.setFullYear(y);}\n"
1416         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1417         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1418         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1419         + ";}";
1420
1421     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1422     /** eval:var:zzzzzzzzzzzzz */
1423     eval(code);
1424 };
1425
1426 // private
1427 Date.formatCodeToRegex = function(character, currentGroup) {
1428     switch (character) {
1429     case "D":
1430         return {g:0,
1431         c:null,
1432         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1433     case "j":
1434         return {g:1,
1435             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1436             s:"(\\d{1,2})"}; // day of month without leading zeroes
1437     case "d":
1438         return {g:1,
1439             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1440             s:"(\\d{2})"}; // day of month with leading zeroes
1441     case "l":
1442         return {g:0,
1443             c:null,
1444             s:"(?:" + Date.dayNames.join("|") + ")"};
1445     case "S":
1446         return {g:0,
1447             c:null,
1448             s:"(?:st|nd|rd|th)"};
1449     case "w":
1450         return {g:0,
1451             c:null,
1452             s:"\\d"};
1453     case "z":
1454         return {g:0,
1455             c:null,
1456             s:"(?:\\d{1,3})"};
1457     case "W":
1458         return {g:0,
1459             c:null,
1460             s:"(?:\\d{2})"};
1461     case "F":
1462         return {g:1,
1463             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1464             s:"(" + Date.monthNames.join("|") + ")"};
1465     case "M":
1466         return {g:1,
1467             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1468             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1469     case "n":
1470         return {g:1,
1471             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1472             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1473     case "m":
1474         return {g:1,
1475             c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1476             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1477     case "t":
1478         return {g:0,
1479             c:null,
1480             s:"\\d{1,2}"};
1481     case "L":
1482         return {g:0,
1483             c:null,
1484             s:"(?:1|0)"};
1485     case "Y":
1486         return {g:1,
1487             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1488             s:"(\\d{4})"};
1489     case "y":
1490         return {g:1,
1491             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1492                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1493             s:"(\\d{1,2})"};
1494     case "a":
1495         return {g:1,
1496             c:"if (results[" + currentGroup + "] == 'am') {\n"
1497                 + "if (h == 12) { h = 0; }\n"
1498                 + "} else { if (h < 12) { h += 12; }}",
1499             s:"(am|pm)"};
1500     case "A":
1501         return {g:1,
1502             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1503                 + "if (h == 12) { h = 0; }\n"
1504                 + "} else { if (h < 12) { h += 12; }}",
1505             s:"(AM|PM)"};
1506     case "g":
1507     case "G":
1508         return {g:1,
1509             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1510             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1511     case "h":
1512     case "H":
1513         return {g:1,
1514             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1515             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1516     case "i":
1517         return {g:1,
1518             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1519             s:"(\\d{2})"};
1520     case "s":
1521         return {g:1,
1522             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1523             s:"(\\d{2})"};
1524     case "O":
1525         return {g:1,
1526             c:[
1527                 "o = results[", currentGroup, "];\n",
1528                 "var sn = o.substring(0,1);\n", // get + / - sign
1529                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1530                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1531                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1532                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1533             ].join(""),
1534             s:"([+\-]\\d{2,4})"};
1535     
1536     
1537     case "P":
1538         return {g:1,
1539                 c:[
1540                    "o = results[", currentGroup, "];\n",
1541                    "var sn = o.substring(0,1);\n",
1542                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1543                    "var mn = o.substring(4,6) % 60;\n",
1544                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1545                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1546             ].join(""),
1547             s:"([+\-]\\d{4})"};
1548     case "T":
1549         return {g:0,
1550             c:null,
1551             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1552     case "Z":
1553         return {g:1,
1554             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1555                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1556             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1557     default:
1558         return {g:0,
1559             c:null,
1560             s:String.escape(character)};
1561     }
1562 };
1563
1564 /**
1565  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1566  * @return {String} The abbreviated timezone name (e.g. 'CST')
1567  */
1568 Date.prototype.getTimezone = function() {
1569     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1570 };
1571
1572 /**
1573  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1574  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1575  */
1576 Date.prototype.getGMTOffset = function() {
1577     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1578         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1579         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1580 };
1581
1582 /**
1583  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1584  * @return {String} 2-characters representing hours and 2-characters representing minutes
1585  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1586  */
1587 Date.prototype.getGMTColonOffset = function() {
1588         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1589                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1590                 + ":"
1591                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1592 }
1593
1594 /**
1595  * Get the numeric day number of the year, adjusted for leap year.
1596  * @return {Number} 0 through 364 (365 in leap years)
1597  */
1598 Date.prototype.getDayOfYear = function() {
1599     var num = 0;
1600     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1601     for (var i = 0; i < this.getMonth(); ++i) {
1602         num += Date.daysInMonth[i];
1603     }
1604     return num + this.getDate() - 1;
1605 };
1606
1607 /**
1608  * Get the string representation of the numeric week number of the year
1609  * (equivalent to the format specifier 'W').
1610  * @return {String} '00' through '52'
1611  */
1612 Date.prototype.getWeekOfYear = function() {
1613     // Skip to Thursday of this week
1614     var now = this.getDayOfYear() + (4 - this.getDay());
1615     // Find the first Thursday of the year
1616     var jan1 = new Date(this.getFullYear(), 0, 1);
1617     var then = (7 - jan1.getDay() + 4);
1618     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1619 };
1620
1621 /**
1622  * Whether or not the current date is in a leap year.
1623  * @return {Boolean} True if the current date is in a leap year, else false
1624  */
1625 Date.prototype.isLeapYear = function() {
1626     var year = this.getFullYear();
1627     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1628 };
1629
1630 /**
1631  * Get the first day of the current month, adjusted for leap year.  The returned value
1632  * is the numeric day index within the week (0-6) which can be used in conjunction with
1633  * the {@link #monthNames} array to retrieve the textual day name.
1634  * Example:
1635  *<pre><code>
1636 var dt = new Date('1/10/2007');
1637 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1638 </code></pre>
1639  * @return {Number} The day number (0-6)
1640  */
1641 Date.prototype.getFirstDayOfMonth = function() {
1642     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1643     return (day < 0) ? (day + 7) : day;
1644 };
1645
1646 /**
1647  * Get the last day of the current month, adjusted for leap year.  The returned value
1648  * is the numeric day index within the week (0-6) which can be used in conjunction with
1649  * the {@link #monthNames} array to retrieve the textual day name.
1650  * Example:
1651  *<pre><code>
1652 var dt = new Date('1/10/2007');
1653 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1654 </code></pre>
1655  * @return {Number} The day number (0-6)
1656  */
1657 Date.prototype.getLastDayOfMonth = function() {
1658     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1659     return (day < 0) ? (day + 7) : day;
1660 };
1661
1662
1663 /**
1664  * Get the first date of this date's month
1665  * @return {Date}
1666  */
1667 Date.prototype.getFirstDateOfMonth = function() {
1668     return new Date(this.getFullYear(), this.getMonth(), 1);
1669 };
1670
1671 /**
1672  * Get the last date of this date's month
1673  * @return {Date}
1674  */
1675 Date.prototype.getLastDateOfMonth = function() {
1676     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1677 };
1678 /**
1679  * Get the number of days in the current month, adjusted for leap year.
1680  * @return {Number} The number of days in the month
1681  */
1682 Date.prototype.getDaysInMonth = function() {
1683     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1684     return Date.daysInMonth[this.getMonth()];
1685 };
1686
1687 /**
1688  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1689  * @return {String} 'st, 'nd', 'rd' or 'th'
1690  */
1691 Date.prototype.getSuffix = function() {
1692     switch (this.getDate()) {
1693         case 1:
1694         case 21:
1695         case 31:
1696             return "st";
1697         case 2:
1698         case 22:
1699             return "nd";
1700         case 3:
1701         case 23:
1702             return "rd";
1703         default:
1704             return "th";
1705     }
1706 };
1707
1708 // private
1709 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1710
1711 /**
1712  * An array of textual month names.
1713  * Override these values for international dates, for example...
1714  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1715  * @type Array
1716  * @static
1717  */
1718 Date.monthNames =
1719    ["January",
1720     "February",
1721     "March",
1722     "April",
1723     "May",
1724     "June",
1725     "July",
1726     "August",
1727     "September",
1728     "October",
1729     "November",
1730     "December"];
1731
1732 /**
1733  * An array of textual day names.
1734  * Override these values for international dates, for example...
1735  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1736  * @type Array
1737  * @static
1738  */
1739 Date.dayNames =
1740    ["Sunday",
1741     "Monday",
1742     "Tuesday",
1743     "Wednesday",
1744     "Thursday",
1745     "Friday",
1746     "Saturday"];
1747
1748 // private
1749 Date.y2kYear = 50;
1750 // private
1751 Date.monthNumbers = {
1752     Jan:0,
1753     Feb:1,
1754     Mar:2,
1755     Apr:3,
1756     May:4,
1757     Jun:5,
1758     Jul:6,
1759     Aug:7,
1760     Sep:8,
1761     Oct:9,
1762     Nov:10,
1763     Dec:11};
1764
1765 /**
1766  * Creates and returns a new Date instance with the exact same date value as the called instance.
1767  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1768  * variable will also be changed.  When the intention is to create a new variable that will not
1769  * modify the original instance, you should create a clone.
1770  *
1771  * Example of correctly cloning a date:
1772  * <pre><code>
1773 //wrong way:
1774 var orig = new Date('10/1/2006');
1775 var copy = orig;
1776 copy.setDate(5);
1777 document.write(orig);  //returns 'Thu Oct 05 2006'!
1778
1779 //correct way:
1780 var orig = new Date('10/1/2006');
1781 var copy = orig.clone();
1782 copy.setDate(5);
1783 document.write(orig);  //returns 'Thu Oct 01 2006'
1784 </code></pre>
1785  * @return {Date} The new Date instance
1786  */
1787 Date.prototype.clone = function() {
1788         return new Date(this.getTime());
1789 };
1790
1791 /**
1792  * Clears any time information from this date
1793  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1794  @return {Date} this or the clone
1795  */
1796 Date.prototype.clearTime = function(clone){
1797     if(clone){
1798         return this.clone().clearTime();
1799     }
1800     this.setHours(0);
1801     this.setMinutes(0);
1802     this.setSeconds(0);
1803     this.setMilliseconds(0);
1804     return this;
1805 };
1806
1807 // private
1808 // safari setMonth is broken -- check that this is only donw once...
1809 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1810     Date.brokenSetMonth = Date.prototype.setMonth;
1811         Date.prototype.setMonth = function(num){
1812                 if(num <= -1){
1813                         var n = Math.ceil(-num);
1814                         var back_year = Math.ceil(n/12);
1815                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1816                         this.setFullYear(this.getFullYear() - back_year);
1817                         return Date.brokenSetMonth.call(this, month);
1818                 } else {
1819                         return Date.brokenSetMonth.apply(this, arguments);
1820                 }
1821         };
1822 }
1823
1824 /** Date interval constant 
1825 * @static 
1826 * @type String */
1827 Date.MILLI = "ms";
1828 /** Date interval constant 
1829 * @static 
1830 * @type String */
1831 Date.SECOND = "s";
1832 /** Date interval constant 
1833 * @static 
1834 * @type String */
1835 Date.MINUTE = "mi";
1836 /** Date interval constant 
1837 * @static 
1838 * @type String */
1839 Date.HOUR = "h";
1840 /** Date interval constant 
1841 * @static 
1842 * @type String */
1843 Date.DAY = "d";
1844 /** Date interval constant 
1845 * @static 
1846 * @type String */
1847 Date.MONTH = "mo";
1848 /** Date interval constant 
1849 * @static 
1850 * @type String */
1851 Date.YEAR = "y";
1852
1853 /**
1854  * Provides a convenient method of performing basic date arithmetic.  This method
1855  * does not modify the Date instance being called - it creates and returns
1856  * a new Date instance containing the resulting date value.
1857  *
1858  * Examples:
1859  * <pre><code>
1860 //Basic usage:
1861 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1862 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1863
1864 //Negative values will subtract correctly:
1865 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1866 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1867
1868 //You can even chain several calls together in one line!
1869 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1870 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1871  </code></pre>
1872  *
1873  * @param {String} interval   A valid date interval enum value
1874  * @param {Number} value      The amount to add to the current date
1875  * @return {Date} The new Date instance
1876  */
1877 Date.prototype.add = function(interval, value){
1878   var d = this.clone();
1879   if (!interval || value === 0) { return d; }
1880   switch(interval.toLowerCase()){
1881     case Date.MILLI:
1882       d.setMilliseconds(this.getMilliseconds() + value);
1883       break;
1884     case Date.SECOND:
1885       d.setSeconds(this.getSeconds() + value);
1886       break;
1887     case Date.MINUTE:
1888       d.setMinutes(this.getMinutes() + value);
1889       break;
1890     case Date.HOUR:
1891       d.setHours(this.getHours() + value);
1892       break;
1893     case Date.DAY:
1894       d.setDate(this.getDate() + value);
1895       break;
1896     case Date.MONTH:
1897       var day = this.getDate();
1898       if(day > 28){
1899           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1900       }
1901       d.setDate(day);
1902       d.setMonth(this.getMonth() + value);
1903       break;
1904     case Date.YEAR:
1905       d.setFullYear(this.getFullYear() + value);
1906       break;
1907   }
1908   return d;
1909 };
1910 /**
1911  * @class Roo.lib.Dom
1912  * @licence LGPL
1913  * @static
1914  * 
1915  * Dom utils (from YIU afaik)
1916  *
1917  * 
1918  **/
1919 Roo.lib.Dom = {
1920     /**
1921      * Get the view width
1922      * @param {Boolean} full True will get the full document, otherwise it's the view width
1923      * @return {Number} The width
1924      */
1925      
1926     getViewWidth : function(full) {
1927         return full ? this.getDocumentWidth() : this.getViewportWidth();
1928     },
1929     /**
1930      * Get the view height
1931      * @param {Boolean} full True will get the full document, otherwise it's the view height
1932      * @return {Number} The height
1933      */
1934     getViewHeight : function(full) {
1935         return full ? this.getDocumentHeight() : this.getViewportHeight();
1936     },
1937     /**
1938      * Get the Full Document height 
1939      * @return {Number} The height
1940      */
1941     getDocumentHeight: function() {
1942         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1943         return Math.max(scrollHeight, this.getViewportHeight());
1944     },
1945     /**
1946      * Get the Full Document width
1947      * @return {Number} The width
1948      */
1949     getDocumentWidth: function() {
1950         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1951         return Math.max(scrollWidth, this.getViewportWidth());
1952     },
1953     /**
1954      * Get the Window Viewport height
1955      * @return {Number} The height
1956      */
1957     getViewportHeight: function() {
1958         var height = self.innerHeight;
1959         var mode = document.compatMode;
1960
1961         if ((mode || Roo.isIE) && !Roo.isOpera) {
1962             height = (mode == "CSS1Compat") ?
1963                      document.documentElement.clientHeight :
1964                      document.body.clientHeight;
1965         }
1966
1967         return height;
1968     },
1969     /**
1970      * Get the Window Viewport width
1971      * @return {Number} The width
1972      */
1973     getViewportWidth: function() {
1974         var width = self.innerWidth;
1975         var mode = document.compatMode;
1976
1977         if (mode || Roo.isIE) {
1978             width = (mode == "CSS1Compat") ?
1979                     document.documentElement.clientWidth :
1980                     document.body.clientWidth;
1981         }
1982         return width;
1983     },
1984
1985     isAncestor : function(p, c) {
1986         p = Roo.getDom(p);
1987         c = Roo.getDom(c);
1988         if (!p || !c) {
1989             return false;
1990         }
1991
1992         if (p.contains && !Roo.isSafari) {
1993             return p.contains(c);
1994         } else if (p.compareDocumentPosition) {
1995             return !!(p.compareDocumentPosition(c) & 16);
1996         } else {
1997             var parent = c.parentNode;
1998             while (parent) {
1999                 if (parent == p) {
2000                     return true;
2001                 }
2002                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
2003                     return false;
2004                 }
2005                 parent = parent.parentNode;
2006             }
2007             return false;
2008         }
2009     },
2010
2011     getRegion : function(el) {
2012         return Roo.lib.Region.getRegion(el);
2013     },
2014
2015     getY : function(el) {
2016         return this.getXY(el)[1];
2017     },
2018
2019     getX : function(el) {
2020         return this.getXY(el)[0];
2021     },
2022
2023     getXY : function(el) {
2024         var p, pe, b, scroll, bd = document.body;
2025         el = Roo.getDom(el);
2026         var fly = Roo.lib.AnimBase.fly;
2027         if (el.getBoundingClientRect) {
2028             b = el.getBoundingClientRect();
2029             scroll = fly(document).getScroll();
2030             return [b.left + scroll.left, b.top + scroll.top];
2031         }
2032         var x = 0, y = 0;
2033
2034         p = el;
2035
2036         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2037
2038         while (p) {
2039
2040             x += p.offsetLeft;
2041             y += p.offsetTop;
2042
2043             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2044                 hasAbsolute = true;
2045             }
2046
2047             if (Roo.isGecko) {
2048                 pe = fly(p);
2049
2050                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2051                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2052
2053
2054                 x += bl;
2055                 y += bt;
2056
2057
2058                 if (p != el && pe.getStyle('overflow') != 'visible') {
2059                     x += bl;
2060                     y += bt;
2061                 }
2062             }
2063             p = p.offsetParent;
2064         }
2065
2066         if (Roo.isSafari && hasAbsolute) {
2067             x -= bd.offsetLeft;
2068             y -= bd.offsetTop;
2069         }
2070
2071         if (Roo.isGecko && !hasAbsolute) {
2072             var dbd = fly(bd);
2073             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2074             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2075         }
2076
2077         p = el.parentNode;
2078         while (p && p != bd) {
2079             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2080                 x -= p.scrollLeft;
2081                 y -= p.scrollTop;
2082             }
2083             p = p.parentNode;
2084         }
2085         return [x, y];
2086     },
2087  
2088   
2089
2090
2091     setXY : function(el, xy) {
2092         el = Roo.fly(el, '_setXY');
2093         el.position();
2094         var pts = el.translatePoints(xy);
2095         if (xy[0] !== false) {
2096             el.dom.style.left = pts.left + "px";
2097         }
2098         if (xy[1] !== false) {
2099             el.dom.style.top = pts.top + "px";
2100         }
2101     },
2102
2103     setX : function(el, x) {
2104         this.setXY(el, [x, false]);
2105     },
2106
2107     setY : function(el, y) {
2108         this.setXY(el, [false, y]);
2109     }
2110 };
2111 /*
2112  * Portions of this file are based on pieces of Yahoo User Interface Library
2113  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2114  * YUI licensed under the BSD License:
2115  * http://developer.yahoo.net/yui/license.txt
2116  * <script type="text/javascript">
2117  *
2118  */
2119
2120 Roo.lib.Event = function() {
2121     var loadComplete = false;
2122     var listeners = [];
2123     var unloadListeners = [];
2124     var retryCount = 0;
2125     var onAvailStack = [];
2126     var counter = 0;
2127     var lastError = null;
2128
2129     return {
2130         POLL_RETRYS: 200,
2131         POLL_INTERVAL: 20,
2132         EL: 0,
2133         TYPE: 1,
2134         FN: 2,
2135         WFN: 3,
2136         OBJ: 3,
2137         ADJ_SCOPE: 4,
2138         _interval: null,
2139
2140         startInterval: function() {
2141             if (!this._interval) {
2142                 var self = this;
2143                 var callback = function() {
2144                     self._tryPreloadAttach();
2145                 };
2146                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2147
2148             }
2149         },
2150
2151         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2152             onAvailStack.push({ id:         p_id,
2153                 fn:         p_fn,
2154                 obj:        p_obj,
2155                 override:   p_override,
2156                 checkReady: false    });
2157
2158             retryCount = this.POLL_RETRYS;
2159             this.startInterval();
2160         },
2161
2162
2163         addListener: function(el, eventName, fn) {
2164             el = Roo.getDom(el);
2165             if (!el || !fn) {
2166                 return false;
2167             }
2168
2169             if ("unload" == eventName) {
2170                 unloadListeners[unloadListeners.length] =
2171                 [el, eventName, fn];
2172                 return true;
2173             }
2174
2175             var wrappedFn = function(e) {
2176                 return fn(Roo.lib.Event.getEvent(e));
2177             };
2178
2179             var li = [el, eventName, fn, wrappedFn];
2180
2181             var index = listeners.length;
2182             listeners[index] = li;
2183
2184             this.doAdd(el, eventName, wrappedFn, false);
2185             return true;
2186
2187         },
2188
2189
2190         removeListener: function(el, eventName, fn) {
2191             var i, len;
2192
2193             el = Roo.getDom(el);
2194
2195             if(!fn) {
2196                 return this.purgeElement(el, false, eventName);
2197             }
2198
2199
2200             if ("unload" == eventName) {
2201
2202                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2203                     var li = unloadListeners[i];
2204                     if (li &&
2205                         li[0] == el &&
2206                         li[1] == eventName &&
2207                         li[2] == fn) {
2208                         unloadListeners.splice(i, 1);
2209                         return true;
2210                     }
2211                 }
2212
2213                 return false;
2214             }
2215
2216             var cacheItem = null;
2217
2218
2219             var index = arguments[3];
2220
2221             if ("undefined" == typeof index) {
2222                 index = this._getCacheIndex(el, eventName, fn);
2223             }
2224
2225             if (index >= 0) {
2226                 cacheItem = listeners[index];
2227             }
2228
2229             if (!el || !cacheItem) {
2230                 return false;
2231             }
2232
2233             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2234
2235             delete listeners[index][this.WFN];
2236             delete listeners[index][this.FN];
2237             listeners.splice(index, 1);
2238
2239             return true;
2240
2241         },
2242
2243
2244         getTarget: function(ev, resolveTextNode) {
2245             ev = ev.browserEvent || ev;
2246             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2247             var t = ev.target || ev.srcElement;
2248             return this.resolveTextNode(t);
2249         },
2250
2251
2252         resolveTextNode: function(node) {
2253             if (Roo.isSafari && node && 3 == node.nodeType) {
2254                 return node.parentNode;
2255             } else {
2256                 return node;
2257             }
2258         },
2259
2260
2261         getPageX: function(ev) {
2262             ev = ev.browserEvent || ev;
2263             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2264             var x = ev.pageX;
2265             if (!x && 0 !== x) {
2266                 x = ev.clientX || 0;
2267
2268                 if (Roo.isIE) {
2269                     x += this.getScroll()[1];
2270                 }
2271             }
2272
2273             return x;
2274         },
2275
2276
2277         getPageY: function(ev) {
2278             ev = ev.browserEvent || ev;
2279             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2280             var y = ev.pageY;
2281             if (!y && 0 !== y) {
2282                 y = ev.clientY || 0;
2283
2284                 if (Roo.isIE) {
2285                     y += this.getScroll()[0];
2286                 }
2287             }
2288
2289
2290             return y;
2291         },
2292
2293
2294         getXY: function(ev) {
2295             ev = ev.browserEvent || ev;
2296             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2297             return [this.getPageX(ev), this.getPageY(ev)];
2298         },
2299
2300
2301         getRelatedTarget: function(ev) {
2302             ev = ev.browserEvent || ev;
2303             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2304             var t = ev.relatedTarget;
2305             if (!t) {
2306                 if (ev.type == "mouseout") {
2307                     t = ev.toElement;
2308                 } else if (ev.type == "mouseover") {
2309                     t = ev.fromElement;
2310                 }
2311             }
2312
2313             return this.resolveTextNode(t);
2314         },
2315
2316
2317         getTime: function(ev) {
2318             ev = ev.browserEvent || ev;
2319             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2320             if (!ev.time) {
2321                 var t = new Date().getTime();
2322                 try {
2323                     ev.time = t;
2324                 } catch(ex) {
2325                     this.lastError = ex;
2326                     return t;
2327                 }
2328             }
2329
2330             return ev.time;
2331         },
2332
2333
2334         stopEvent: function(ev) {
2335             this.stopPropagation(ev);
2336             this.preventDefault(ev);
2337         },
2338
2339
2340         stopPropagation: function(ev) {
2341             ev = ev.browserEvent || ev;
2342             if (ev.stopPropagation) {
2343                 ev.stopPropagation();
2344             } else {
2345                 ev.cancelBubble = true;
2346             }
2347         },
2348
2349
2350         preventDefault: function(ev) {
2351             ev = ev.browserEvent || ev;
2352             if(ev.preventDefault) {
2353                 ev.preventDefault();
2354             } else {
2355                 ev.returnValue = false;
2356             }
2357         },
2358
2359
2360         getEvent: function(e) {
2361             var ev = e || window.event;
2362             if (!ev) {
2363                 var c = this.getEvent.caller;
2364                 while (c) {
2365                     ev = c.arguments[0];
2366                     if (ev && Event == ev.constructor) {
2367                         break;
2368                     }
2369                     c = c.caller;
2370                 }
2371             }
2372             return ev;
2373         },
2374
2375
2376         getCharCode: function(ev) {
2377             ev = ev.browserEvent || ev;
2378             return ev.charCode || ev.keyCode || 0;
2379         },
2380
2381
2382         _getCacheIndex: function(el, eventName, fn) {
2383             for (var i = 0,len = listeners.length; i < len; ++i) {
2384                 var li = listeners[i];
2385                 if (li &&
2386                     li[this.FN] == fn &&
2387                     li[this.EL] == el &&
2388                     li[this.TYPE] == eventName) {
2389                     return i;
2390                 }
2391             }
2392
2393             return -1;
2394         },
2395
2396
2397         elCache: {},
2398
2399
2400         getEl: function(id) {
2401             return document.getElementById(id);
2402         },
2403
2404
2405         clearCache: function() {
2406         },
2407
2408
2409         _load: function(e) {
2410             loadComplete = true;
2411             var EU = Roo.lib.Event;
2412
2413
2414             if (Roo.isIE) {
2415                 EU.doRemove(window, "load", EU._load);
2416             }
2417         },
2418
2419
2420         _tryPreloadAttach: function() {
2421
2422             if (this.locked) {
2423                 return false;
2424             }
2425
2426             this.locked = true;
2427
2428
2429             var tryAgain = !loadComplete;
2430             if (!tryAgain) {
2431                 tryAgain = (retryCount > 0);
2432             }
2433
2434
2435             var notAvail = [];
2436             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2437                 var item = onAvailStack[i];
2438                 if (item) {
2439                     var el = this.getEl(item.id);
2440
2441                     if (el) {
2442                         if (!item.checkReady ||
2443                             loadComplete ||
2444                             el.nextSibling ||
2445                             (document && document.body)) {
2446
2447                             var scope = el;
2448                             if (item.override) {
2449                                 if (item.override === true) {
2450                                     scope = item.obj;
2451                                 } else {
2452                                     scope = item.override;
2453                                 }
2454                             }
2455                             item.fn.call(scope, item.obj);
2456                             onAvailStack[i] = null;
2457                         }
2458                     } else {
2459                         notAvail.push(item);
2460                     }
2461                 }
2462             }
2463
2464             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2465
2466             if (tryAgain) {
2467
2468                 this.startInterval();
2469             } else {
2470                 clearInterval(this._interval);
2471                 this._interval = null;
2472             }
2473
2474             this.locked = false;
2475
2476             return true;
2477
2478         },
2479
2480
2481         purgeElement: function(el, recurse, eventName) {
2482             var elListeners = this.getListeners(el, eventName);
2483             if (elListeners) {
2484                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2485                     var l = elListeners[i];
2486                     this.removeListener(el, l.type, l.fn);
2487                 }
2488             }
2489
2490             if (recurse && el && el.childNodes) {
2491                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2492                     this.purgeElement(el.childNodes[i], recurse, eventName);
2493                 }
2494             }
2495         },
2496
2497
2498         getListeners: function(el, eventName) {
2499             var results = [], searchLists;
2500             if (!eventName) {
2501                 searchLists = [listeners, unloadListeners];
2502             } else if (eventName == "unload") {
2503                 searchLists = [unloadListeners];
2504             } else {
2505                 searchLists = [listeners];
2506             }
2507
2508             for (var j = 0; j < searchLists.length; ++j) {
2509                 var searchList = searchLists[j];
2510                 if (searchList && searchList.length > 0) {
2511                     for (var i = 0,len = searchList.length; i < len; ++i) {
2512                         var l = searchList[i];
2513                         if (l && l[this.EL] === el &&
2514                             (!eventName || eventName === l[this.TYPE])) {
2515                             results.push({
2516                                 type:   l[this.TYPE],
2517                                 fn:     l[this.FN],
2518                                 obj:    l[this.OBJ],
2519                                 adjust: l[this.ADJ_SCOPE],
2520                                 index:  i
2521                             });
2522                         }
2523                     }
2524                 }
2525             }
2526
2527             return (results.length) ? results : null;
2528         },
2529
2530
2531         _unload: function(e) {
2532
2533             var EU = Roo.lib.Event, i, j, l, len, index;
2534
2535             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2536                 l = unloadListeners[i];
2537                 if (l) {
2538                     var scope = window;
2539                     if (l[EU.ADJ_SCOPE]) {
2540                         if (l[EU.ADJ_SCOPE] === true) {
2541                             scope = l[EU.OBJ];
2542                         } else {
2543                             scope = l[EU.ADJ_SCOPE];
2544                         }
2545                     }
2546                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2547                     unloadListeners[i] = null;
2548                     l = null;
2549                     scope = null;
2550                 }
2551             }
2552
2553             unloadListeners = null;
2554
2555             if (listeners && listeners.length > 0) {
2556                 j = listeners.length;
2557                 while (j) {
2558                     index = j - 1;
2559                     l = listeners[index];
2560                     if (l) {
2561                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2562                                 l[EU.FN], index);
2563                     }
2564                     j = j - 1;
2565                 }
2566                 l = null;
2567
2568                 EU.clearCache();
2569             }
2570
2571             EU.doRemove(window, "unload", EU._unload);
2572
2573         },
2574
2575
2576         getScroll: function() {
2577             var dd = document.documentElement, db = document.body;
2578             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2579                 return [dd.scrollTop, dd.scrollLeft];
2580             } else if (db) {
2581                 return [db.scrollTop, db.scrollLeft];
2582             } else {
2583                 return [0, 0];
2584             }
2585         },
2586
2587
2588         doAdd: function () {
2589             if (window.addEventListener) {
2590                 return function(el, eventName, fn, capture) {
2591                     el.addEventListener(eventName, fn, (capture));
2592                 };
2593             } else if (window.attachEvent) {
2594                 return function(el, eventName, fn, capture) {
2595                     el.attachEvent("on" + eventName, fn);
2596                 };
2597             } else {
2598                 return function() {
2599                 };
2600             }
2601         }(),
2602
2603
2604         doRemove: function() {
2605             if (window.removeEventListener) {
2606                 return function (el, eventName, fn, capture) {
2607                     el.removeEventListener(eventName, fn, (capture));
2608                 };
2609             } else if (window.detachEvent) {
2610                 return function (el, eventName, fn) {
2611                     el.detachEvent("on" + eventName, fn);
2612                 };
2613             } else {
2614                 return function() {
2615                 };
2616             }
2617         }()
2618     };
2619     
2620 }();
2621 (function() {     
2622    
2623     var E = Roo.lib.Event;
2624     E.on = E.addListener;
2625     E.un = E.removeListener;
2626
2627     if (document && document.body) {
2628         E._load();
2629     } else {
2630         E.doAdd(window, "load", E._load);
2631     }
2632     E.doAdd(window, "unload", E._unload);
2633     E._tryPreloadAttach();
2634 })();
2635
2636  
2637
2638 (function() {
2639     /**
2640      * @class Roo.lib.Ajax
2641      *
2642      * provide a simple Ajax request utility functions
2643      * 
2644      * Portions of this file are based on pieces of Yahoo User Interface Library
2645     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2646     * YUI licensed under the BSD License:
2647     * http://developer.yahoo.net/yui/license.txt
2648     * <script type="text/javascript">
2649     *
2650      *
2651      */
2652     Roo.lib.Ajax = {
2653         /**
2654          * @static 
2655          */
2656         request : function(method, uri, cb, data, options) {
2657             if(options){
2658                 var hs = options.headers;
2659                 if(hs){
2660                     for(var h in hs){
2661                         if(hs.hasOwnProperty(h)){
2662                             this.initHeader(h, hs[h], false);
2663                         }
2664                     }
2665                 }
2666                 if(options.xmlData){
2667                     this.initHeader('Content-Type', 'text/xml', false);
2668                     method = 'POST';
2669                     data = options.xmlData;
2670                 }
2671             }
2672
2673             return this.asyncRequest(method, uri, cb, data);
2674         },
2675         /**
2676          * serialize a form
2677          *
2678          * @static
2679          * @param {DomForm} form element
2680          * @return {String} urlencode form output.
2681          */
2682         serializeForm : function(form) {
2683             if(typeof form == 'string') {
2684                 form = (document.getElementById(form) || document.forms[form]);
2685             }
2686
2687             var el, name, val, disabled, data = '', hasSubmit = false;
2688             for (var i = 0; i < form.elements.length; i++) {
2689                 el = form.elements[i];
2690                 disabled = form.elements[i].disabled;
2691                 name = form.elements[i].name;
2692                 val = form.elements[i].value;
2693
2694                 if (!disabled && name){
2695                     switch (el.type)
2696                             {
2697                         case 'select-one':
2698                         case 'select-multiple':
2699                             for (var j = 0; j < el.options.length; j++) {
2700                                 if (el.options[j].selected) {
2701                                     if (Roo.isIE) {
2702                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2703                                     }
2704                                     else {
2705                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2706                                     }
2707                                 }
2708                             }
2709                             break;
2710                         case 'radio':
2711                         case 'checkbox':
2712                             if (el.checked) {
2713                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2714                             }
2715                             break;
2716                         case 'file':
2717
2718                         case undefined:
2719
2720                         case 'reset':
2721
2722                         case 'button':
2723
2724                             break;
2725                         case 'submit':
2726                             if(hasSubmit == false) {
2727                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2728                                 hasSubmit = true;
2729                             }
2730                             break;
2731                         default:
2732                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2733                             break;
2734                     }
2735                 }
2736             }
2737             data = data.substr(0, data.length - 1);
2738             return data;
2739         },
2740
2741         headers:{},
2742
2743         hasHeaders:false,
2744
2745         useDefaultHeader:true,
2746
2747         defaultPostHeader:'application/x-www-form-urlencoded',
2748
2749         useDefaultXhrHeader:true,
2750
2751         defaultXhrHeader:'XMLHttpRequest',
2752
2753         hasDefaultHeaders:true,
2754
2755         defaultHeaders:{},
2756
2757         poll:{},
2758
2759         timeout:{},
2760
2761         pollInterval:50,
2762
2763         transactionId:0,
2764
2765         setProgId:function(id)
2766         {
2767             this.activeX.unshift(id);
2768         },
2769
2770         setDefaultPostHeader:function(b)
2771         {
2772             this.useDefaultHeader = b;
2773         },
2774
2775         setDefaultXhrHeader:function(b)
2776         {
2777             this.useDefaultXhrHeader = b;
2778         },
2779
2780         setPollingInterval:function(i)
2781         {
2782             if (typeof i == 'number' && isFinite(i)) {
2783                 this.pollInterval = i;
2784             }
2785         },
2786
2787         createXhrObject:function(transactionId)
2788         {
2789             var obj,http;
2790             try
2791             {
2792
2793                 http = new XMLHttpRequest();
2794
2795                 obj = { conn:http, tId:transactionId };
2796             }
2797             catch(e)
2798             {
2799                 for (var i = 0; i < this.activeX.length; ++i) {
2800                     try
2801                     {
2802
2803                         http = new ActiveXObject(this.activeX[i]);
2804
2805                         obj = { conn:http, tId:transactionId };
2806                         break;
2807                     }
2808                     catch(e) {
2809                     }
2810                 }
2811             }
2812             finally
2813             {
2814                 return obj;
2815             }
2816         },
2817
2818         getConnectionObject:function()
2819         {
2820             var o;
2821             var tId = this.transactionId;
2822
2823             try
2824             {
2825                 o = this.createXhrObject(tId);
2826                 if (o) {
2827                     this.transactionId++;
2828                 }
2829             }
2830             catch(e) {
2831             }
2832             finally
2833             {
2834                 return o;
2835             }
2836         },
2837
2838         asyncRequest:function(method, uri, callback, postData)
2839         {
2840             var o = this.getConnectionObject();
2841
2842             if (!o) {
2843                 return null;
2844             }
2845             else {
2846                 o.conn.open(method, uri, true);
2847
2848                 if (this.useDefaultXhrHeader) {
2849                     if (!this.defaultHeaders['X-Requested-With']) {
2850                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2851                     }
2852                 }
2853
2854                 if(postData && this.useDefaultHeader){
2855                     this.initHeader('Content-Type', this.defaultPostHeader);
2856                 }
2857
2858                  if (this.hasDefaultHeaders || this.hasHeaders) {
2859                     this.setHeader(o);
2860                 }
2861
2862                 this.handleReadyState(o, callback);
2863                 o.conn.send(postData || null);
2864
2865                 return o;
2866             }
2867         },
2868
2869         handleReadyState:function(o, callback)
2870         {
2871             var oConn = this;
2872
2873             if (callback && callback.timeout) {
2874                 
2875                 this.timeout[o.tId] = window.setTimeout(function() {
2876                     oConn.abort(o, callback, true);
2877                 }, callback.timeout);
2878             }
2879
2880             this.poll[o.tId] = window.setInterval(
2881                     function() {
2882                         if (o.conn && o.conn.readyState == 4) {
2883                             window.clearInterval(oConn.poll[o.tId]);
2884                             delete oConn.poll[o.tId];
2885
2886                             if(callback && callback.timeout) {
2887                                 window.clearTimeout(oConn.timeout[o.tId]);
2888                                 delete oConn.timeout[o.tId];
2889                             }
2890
2891                             oConn.handleTransactionResponse(o, callback);
2892                         }
2893                     }
2894                     , this.pollInterval);
2895         },
2896
2897         handleTransactionResponse:function(o, callback, isAbort)
2898         {
2899
2900             if (!callback) {
2901                 this.releaseObject(o);
2902                 return;
2903             }
2904
2905             var httpStatus, responseObject;
2906
2907             try
2908             {
2909                 if (o.conn.status !== undefined && o.conn.status != 0) {
2910                     httpStatus = o.conn.status;
2911                 }
2912                 else {
2913                     httpStatus = 13030;
2914                 }
2915             }
2916             catch(e) {
2917
2918
2919                 httpStatus = 13030;
2920             }
2921
2922             if (httpStatus >= 200 && httpStatus < 300) {
2923                 responseObject = this.createResponseObject(o, callback.argument);
2924                 if (callback.success) {
2925                     if (!callback.scope) {
2926                         callback.success(responseObject);
2927                     }
2928                     else {
2929
2930
2931                         callback.success.apply(callback.scope, [responseObject]);
2932                     }
2933                 }
2934             }
2935             else {
2936                 switch (httpStatus) {
2937
2938                     case 12002:
2939                     case 12029:
2940                     case 12030:
2941                     case 12031:
2942                     case 12152:
2943                     case 13030:
2944                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2945                         if (callback.failure) {
2946                             if (!callback.scope) {
2947                                 callback.failure(responseObject);
2948                             }
2949                             else {
2950                                 callback.failure.apply(callback.scope, [responseObject]);
2951                             }
2952                         }
2953                         break;
2954                     default:
2955                         responseObject = this.createResponseObject(o, callback.argument);
2956                         if (callback.failure) {
2957                             if (!callback.scope) {
2958                                 callback.failure(responseObject);
2959                             }
2960                             else {
2961                                 callback.failure.apply(callback.scope, [responseObject]);
2962                             }
2963                         }
2964                 }
2965             }
2966
2967             this.releaseObject(o);
2968             responseObject = null;
2969         },
2970
2971         createResponseObject:function(o, callbackArg)
2972         {
2973             var obj = {};
2974             var headerObj = {};
2975
2976             try
2977             {
2978                 var headerStr = o.conn.getAllResponseHeaders();
2979                 var header = headerStr.split('\n');
2980                 for (var i = 0; i < header.length; i++) {
2981                     var delimitPos = header[i].indexOf(':');
2982                     if (delimitPos != -1) {
2983                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2984                     }
2985                 }
2986             }
2987             catch(e) {
2988             }
2989
2990             obj.tId = o.tId;
2991             obj.status = o.conn.status;
2992             obj.statusText = o.conn.statusText;
2993             obj.getResponseHeader = headerObj;
2994             obj.getAllResponseHeaders = headerStr;
2995             obj.responseText = o.conn.responseText;
2996             obj.responseXML = o.conn.responseXML;
2997
2998             if (typeof callbackArg !== undefined) {
2999                 obj.argument = callbackArg;
3000             }
3001
3002             return obj;
3003         },
3004
3005         createExceptionObject:function(tId, callbackArg, isAbort)
3006         {
3007             var COMM_CODE = 0;
3008             var COMM_ERROR = 'communication failure';
3009             var ABORT_CODE = -1;
3010             var ABORT_ERROR = 'transaction aborted';
3011
3012             var obj = {};
3013
3014             obj.tId = tId;
3015             if (isAbort) {
3016                 obj.status = ABORT_CODE;
3017                 obj.statusText = ABORT_ERROR;
3018             }
3019             else {
3020                 obj.status = COMM_CODE;
3021                 obj.statusText = COMM_ERROR;
3022             }
3023
3024             if (callbackArg) {
3025                 obj.argument = callbackArg;
3026             }
3027
3028             return obj;
3029         },
3030
3031         initHeader:function(label, value, isDefault)
3032         {
3033             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3034
3035             if (headerObj[label] === undefined) {
3036                 headerObj[label] = value;
3037             }
3038             else {
3039
3040
3041                 headerObj[label] = value + "," + headerObj[label];
3042             }
3043
3044             if (isDefault) {
3045                 this.hasDefaultHeaders = true;
3046             }
3047             else {
3048                 this.hasHeaders = true;
3049             }
3050         },
3051
3052
3053         setHeader:function(o)
3054         {
3055             if (this.hasDefaultHeaders) {
3056                 for (var prop in this.defaultHeaders) {
3057                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3058                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3059                     }
3060                 }
3061             }
3062
3063             if (this.hasHeaders) {
3064                 for (var prop in this.headers) {
3065                     if (this.headers.hasOwnProperty(prop)) {
3066                         o.conn.setRequestHeader(prop, this.headers[prop]);
3067                     }
3068                 }
3069                 this.headers = {};
3070                 this.hasHeaders = false;
3071             }
3072         },
3073
3074         resetDefaultHeaders:function() {
3075             delete this.defaultHeaders;
3076             this.defaultHeaders = {};
3077             this.hasDefaultHeaders = false;
3078         },
3079
3080         abort:function(o, callback, isTimeout)
3081         {
3082             if(this.isCallInProgress(o)) {
3083                 o.conn.abort();
3084                 window.clearInterval(this.poll[o.tId]);
3085                 delete this.poll[o.tId];
3086                 if (isTimeout) {
3087                     delete this.timeout[o.tId];
3088                 }
3089
3090                 this.handleTransactionResponse(o, callback, true);
3091
3092                 return true;
3093             }
3094             else {
3095                 return false;
3096             }
3097         },
3098
3099
3100         isCallInProgress:function(o)
3101         {
3102             if (o && o.conn) {
3103                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3104             }
3105             else {
3106
3107                 return false;
3108             }
3109         },
3110
3111
3112         releaseObject:function(o)
3113         {
3114
3115             o.conn = null;
3116
3117             o = null;
3118         },
3119
3120         activeX:[
3121         'MSXML2.XMLHTTP.3.0',
3122         'MSXML2.XMLHTTP',
3123         'Microsoft.XMLHTTP'
3124         ]
3125
3126
3127     };
3128 })();/*
3129  * Portions of this file are based on pieces of Yahoo User Interface Library
3130  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3131  * YUI licensed under the BSD License:
3132  * http://developer.yahoo.net/yui/license.txt
3133  * <script type="text/javascript">
3134  *
3135  */
3136
3137 Roo.lib.Region = function(t, r, b, l) {
3138     this.top = t;
3139     this[1] = t;
3140     this.right = r;
3141     this.bottom = b;
3142     this.left = l;
3143     this[0] = l;
3144 };
3145
3146
3147 Roo.lib.Region.prototype = {
3148     contains : function(region) {
3149         return ( region.left >= this.left &&
3150                  region.right <= this.right &&
3151                  region.top >= this.top &&
3152                  region.bottom <= this.bottom    );
3153
3154     },
3155
3156     getArea : function() {
3157         return ( (this.bottom - this.top) * (this.right - this.left) );
3158     },
3159
3160     intersect : function(region) {
3161         var t = Math.max(this.top, region.top);
3162         var r = Math.min(this.right, region.right);
3163         var b = Math.min(this.bottom, region.bottom);
3164         var l = Math.max(this.left, region.left);
3165
3166         if (b >= t && r >= l) {
3167             return new Roo.lib.Region(t, r, b, l);
3168         } else {
3169             return null;
3170         }
3171     },
3172     union : function(region) {
3173         var t = Math.min(this.top, region.top);
3174         var r = Math.max(this.right, region.right);
3175         var b = Math.max(this.bottom, region.bottom);
3176         var l = Math.min(this.left, region.left);
3177
3178         return new Roo.lib.Region(t, r, b, l);
3179     },
3180
3181     adjust : function(t, l, b, r) {
3182         this.top += t;
3183         this.left += l;
3184         this.right += r;
3185         this.bottom += b;
3186         return this;
3187     }
3188 };
3189
3190 Roo.lib.Region.getRegion = function(el) {
3191     var p = Roo.lib.Dom.getXY(el);
3192
3193     var t = p[1];
3194     var r = p[0] + el.offsetWidth;
3195     var b = p[1] + el.offsetHeight;
3196     var l = p[0];
3197
3198     return new Roo.lib.Region(t, r, b, l);
3199 };
3200 /*
3201  * Portions of this file are based on pieces of Yahoo User Interface Library
3202  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3203  * YUI licensed under the BSD License:
3204  * http://developer.yahoo.net/yui/license.txt
3205  * <script type="text/javascript">
3206  *
3207  */
3208 //@@dep Roo.lib.Region
3209
3210
3211 Roo.lib.Point = function(x, y) {
3212     if (x instanceof Array) {
3213         y = x[1];
3214         x = x[0];
3215     }
3216     this.x = this.right = this.left = this[0] = x;
3217     this.y = this.top = this.bottom = this[1] = y;
3218 };
3219
3220 Roo.lib.Point.prototype = new Roo.lib.Region();
3221 /*
3222  * Portions of this file are based on pieces of Yahoo User Interface Library
3223  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3224  * YUI licensed under the BSD License:
3225  * http://developer.yahoo.net/yui/license.txt
3226  * <script type="text/javascript">
3227  *
3228  */
3229  
3230 (function() {   
3231
3232     Roo.lib.Anim = {
3233         scroll : function(el, args, duration, easing, cb, scope) {
3234             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3235         },
3236
3237         motion : function(el, args, duration, easing, cb, scope) {
3238             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3239         },
3240
3241         color : function(el, args, duration, easing, cb, scope) {
3242             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3243         },
3244
3245         run : function(el, args, duration, easing, cb, scope, type) {
3246             type = type || Roo.lib.AnimBase;
3247             if (typeof easing == "string") {
3248                 easing = Roo.lib.Easing[easing];
3249             }
3250             var anim = new type(el, args, duration, easing);
3251             anim.animateX(function() {
3252                 Roo.callback(cb, scope);
3253             });
3254             return anim;
3255         }
3256     };
3257 })();/*
3258  * Portions of this file are based on pieces of Yahoo User Interface Library
3259  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3260  * YUI licensed under the BSD License:
3261  * http://developer.yahoo.net/yui/license.txt
3262  * <script type="text/javascript">
3263  *
3264  */
3265
3266 (function() {    
3267     var libFlyweight;
3268     
3269     function fly(el) {
3270         if (!libFlyweight) {
3271             libFlyweight = new Roo.Element.Flyweight();
3272         }
3273         libFlyweight.dom = el;
3274         return libFlyweight;
3275     }
3276
3277     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3278     
3279    
3280     
3281     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3282         if (el) {
3283             this.init(el, attributes, duration, method);
3284         }
3285     };
3286
3287     Roo.lib.AnimBase.fly = fly;
3288     
3289     
3290     
3291     Roo.lib.AnimBase.prototype = {
3292
3293         toString: function() {
3294             var el = this.getEl();
3295             var id = el.id || el.tagName;
3296             return ("Anim " + id);
3297         },
3298
3299         patterns: {
3300             noNegatives:        /width|height|opacity|padding/i,
3301             offsetAttribute:  /^((width|height)|(top|left))$/,
3302             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3303             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3304         },
3305
3306
3307         doMethod: function(attr, start, end) {
3308             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3309         },
3310
3311
3312         setAttribute: function(attr, val, unit) {
3313             if (this.patterns.noNegatives.test(attr)) {
3314                 val = (val > 0) ? val : 0;
3315             }
3316
3317             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3318         },
3319
3320
3321         getAttribute: function(attr) {
3322             var el = this.getEl();
3323             var val = fly(el).getStyle(attr);
3324
3325             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3326                 return parseFloat(val);
3327             }
3328
3329             var a = this.patterns.offsetAttribute.exec(attr) || [];
3330             var pos = !!( a[3] );
3331             var box = !!( a[2] );
3332
3333
3334             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3335                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3336             } else {
3337                 val = 0;
3338             }
3339
3340             return val;
3341         },
3342
3343
3344         getDefaultUnit: function(attr) {
3345             if (this.patterns.defaultUnit.test(attr)) {
3346                 return 'px';
3347             }
3348
3349             return '';
3350         },
3351
3352         animateX : function(callback, scope) {
3353             var f = function() {
3354                 this.onComplete.removeListener(f);
3355                 if (typeof callback == "function") {
3356                     callback.call(scope || this, this);
3357                 }
3358             };
3359             this.onComplete.addListener(f, this);
3360             this.animate();
3361         },
3362
3363
3364         setRuntimeAttribute: function(attr) {
3365             var start;
3366             var end;
3367             var attributes = this.attributes;
3368
3369             this.runtimeAttributes[attr] = {};
3370
3371             var isset = function(prop) {
3372                 return (typeof prop !== 'undefined');
3373             };
3374
3375             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3376                 return false;
3377             }
3378
3379             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3380
3381
3382             if (isset(attributes[attr]['to'])) {
3383                 end = attributes[attr]['to'];
3384             } else if (isset(attributes[attr]['by'])) {
3385                 if (start.constructor == Array) {
3386                     end = [];
3387                     for (var i = 0, len = start.length; i < len; ++i) {
3388                         end[i] = start[i] + attributes[attr]['by'][i];
3389                     }
3390                 } else {
3391                     end = start + attributes[attr]['by'];
3392                 }
3393             }
3394
3395             this.runtimeAttributes[attr].start = start;
3396             this.runtimeAttributes[attr].end = end;
3397
3398
3399             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3400         },
3401
3402
3403         init: function(el, attributes, duration, method) {
3404
3405             var isAnimated = false;
3406
3407
3408             var startTime = null;
3409
3410
3411             var actualFrames = 0;
3412
3413
3414             el = Roo.getDom(el);
3415
3416
3417             this.attributes = attributes || {};
3418
3419
3420             this.duration = duration || 1;
3421
3422
3423             this.method = method || Roo.lib.Easing.easeNone;
3424
3425
3426             this.useSeconds = true;
3427
3428
3429             this.currentFrame = 0;
3430
3431
3432             this.totalFrames = Roo.lib.AnimMgr.fps;
3433
3434
3435             this.getEl = function() {
3436                 return el;
3437             };
3438
3439
3440             this.isAnimated = function() {
3441                 return isAnimated;
3442             };
3443
3444
3445             this.getStartTime = function() {
3446                 return startTime;
3447             };
3448
3449             this.runtimeAttributes = {};
3450
3451
3452             this.animate = function() {
3453                 if (this.isAnimated()) {
3454                     return false;
3455                 }
3456
3457                 this.currentFrame = 0;
3458
3459                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3460
3461                 Roo.lib.AnimMgr.registerElement(this);
3462             };
3463
3464
3465             this.stop = function(finish) {
3466                 if (finish) {
3467                     this.currentFrame = this.totalFrames;
3468                     this._onTween.fire();
3469                 }
3470                 Roo.lib.AnimMgr.stop(this);
3471             };
3472
3473             var onStart = function() {
3474                 this.onStart.fire();
3475
3476                 this.runtimeAttributes = {};
3477                 for (var attr in this.attributes) {
3478                     this.setRuntimeAttribute(attr);
3479                 }
3480
3481                 isAnimated = true;
3482                 actualFrames = 0;
3483                 startTime = new Date();
3484             };
3485
3486
3487             var onTween = function() {
3488                 var data = {
3489                     duration: new Date() - this.getStartTime(),
3490                     currentFrame: this.currentFrame
3491                 };
3492
3493                 data.toString = function() {
3494                     return (
3495                             'duration: ' + data.duration +
3496                             ', currentFrame: ' + data.currentFrame
3497                             );
3498                 };
3499
3500                 this.onTween.fire(data);
3501
3502                 var runtimeAttributes = this.runtimeAttributes;
3503
3504                 for (var attr in runtimeAttributes) {
3505                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3506                 }
3507
3508                 actualFrames += 1;
3509             };
3510
3511             var onComplete = function() {
3512                 var actual_duration = (new Date() - startTime) / 1000 ;
3513
3514                 var data = {
3515                     duration: actual_duration,
3516                     frames: actualFrames,
3517                     fps: actualFrames / actual_duration
3518                 };
3519
3520                 data.toString = function() {
3521                     return (
3522                             'duration: ' + data.duration +
3523                             ', frames: ' + data.frames +
3524                             ', fps: ' + data.fps
3525                             );
3526                 };
3527
3528                 isAnimated = false;
3529                 actualFrames = 0;
3530                 this.onComplete.fire(data);
3531             };
3532
3533
3534             this._onStart = new Roo.util.Event(this);
3535             this.onStart = new Roo.util.Event(this);
3536             this.onTween = new Roo.util.Event(this);
3537             this._onTween = new Roo.util.Event(this);
3538             this.onComplete = new Roo.util.Event(this);
3539             this._onComplete = new Roo.util.Event(this);
3540             this._onStart.addListener(onStart);
3541             this._onTween.addListener(onTween);
3542             this._onComplete.addListener(onComplete);
3543         }
3544     };
3545 })();
3546 /*
3547  * Portions of this file are based on pieces of Yahoo User Interface Library
3548  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3549  * YUI licensed under the BSD License:
3550  * http://developer.yahoo.net/yui/license.txt
3551  * <script type="text/javascript">
3552  *
3553  */
3554
3555 Roo.lib.AnimMgr = new function() {
3556
3557     var thread = null;
3558
3559
3560     var queue = [];
3561
3562
3563     var tweenCount = 0;
3564
3565
3566     this.fps = 1000;
3567
3568
3569     this.delay = 1;
3570
3571
3572     this.registerElement = function(tween) {
3573         queue[queue.length] = tween;
3574         tweenCount += 1;
3575         tween._onStart.fire();
3576         this.start();
3577     };
3578
3579
3580     this.unRegister = function(tween, index) {
3581         tween._onComplete.fire();
3582         index = index || getIndex(tween);
3583         if (index != -1) {
3584             queue.splice(index, 1);
3585         }
3586
3587         tweenCount -= 1;
3588         if (tweenCount <= 0) {
3589             this.stop();
3590         }
3591     };
3592
3593
3594     this.start = function() {
3595         if (thread === null) {
3596             thread = setInterval(this.run, this.delay);
3597         }
3598     };
3599
3600
3601     this.stop = function(tween) {
3602         if (!tween) {
3603             clearInterval(thread);
3604
3605             for (var i = 0, len = queue.length; i < len; ++i) {
3606                 if (queue[0].isAnimated()) {
3607                     this.unRegister(queue[0], 0);
3608                 }
3609             }
3610
3611             queue = [];
3612             thread = null;
3613             tweenCount = 0;
3614         }
3615         else {
3616             this.unRegister(tween);
3617         }
3618     };
3619
3620
3621     this.run = function() {
3622         for (var i = 0, len = queue.length; i < len; ++i) {
3623             var tween = queue[i];
3624             if (!tween || !tween.isAnimated()) {
3625                 continue;
3626             }
3627
3628             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3629             {
3630                 tween.currentFrame += 1;
3631
3632                 if (tween.useSeconds) {
3633                     correctFrame(tween);
3634                 }
3635                 tween._onTween.fire();
3636             }
3637             else {
3638                 Roo.lib.AnimMgr.stop(tween, i);
3639             }
3640         }
3641     };
3642
3643     var getIndex = function(anim) {
3644         for (var i = 0, len = queue.length; i < len; ++i) {
3645             if (queue[i] == anim) {
3646                 return i;
3647             }
3648         }
3649         return -1;
3650     };
3651
3652
3653     var correctFrame = function(tween) {
3654         var frames = tween.totalFrames;
3655         var frame = tween.currentFrame;
3656         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3657         var elapsed = (new Date() - tween.getStartTime());
3658         var tweak = 0;
3659
3660         if (elapsed < tween.duration * 1000) {
3661             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3662         } else {
3663             tweak = frames - (frame + 1);
3664         }
3665         if (tweak > 0 && isFinite(tweak)) {
3666             if (tween.currentFrame + tweak >= frames) {
3667                 tweak = frames - (frame + 1);
3668             }
3669
3670             tween.currentFrame += tweak;
3671         }
3672     };
3673 };
3674
3675     /*
3676  * Portions of this file are based on pieces of Yahoo User Interface Library
3677  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3678  * YUI licensed under the BSD License:
3679  * http://developer.yahoo.net/yui/license.txt
3680  * <script type="text/javascript">
3681  *
3682  */
3683 Roo.lib.Bezier = new function() {
3684
3685         this.getPosition = function(points, t) {
3686             var n = points.length;
3687             var tmp = [];
3688
3689             for (var i = 0; i < n; ++i) {
3690                 tmp[i] = [points[i][0], points[i][1]];
3691             }
3692
3693             for (var j = 1; j < n; ++j) {
3694                 for (i = 0; i < n - j; ++i) {
3695                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3696                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3697                 }
3698             }
3699
3700             return [ tmp[0][0], tmp[0][1] ];
3701
3702         };
3703     }; 
3704
3705 /**
3706  * @class Roo.lib.Color
3707  * @constructor
3708  * An abstract Color implementation. Concrete Color implementations should use
3709  * an instance of this function as their prototype, and implement the getRGB and
3710  * getHSL functions. getRGB should return an object representing the RGB
3711  * components of this Color, with the red, green, and blue components in the
3712  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3713  * return an object representing the HSL components of this Color, with the hue
3714  * component in the range [0,360), the saturation and lightness components in
3715  * the range [0,100], and the alpha component in the range [0,1].
3716  *
3717  *
3718  * Color.js
3719  *
3720  * Functions for Color handling and processing.
3721  *
3722  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3723  *
3724  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3725  * rights to this program, with the intention of it becoming part of the public
3726  * domain. Because this program is released into the public domain, it comes with
3727  * no warranty either expressed or implied, to the extent permitted by law.
3728  * 
3729  * For more free and public domain JavaScript code by the same author, visit:
3730  * http://www.safalra.com/web-design/javascript/
3731  * 
3732  */
3733 Roo.lib.Color = function() { }
3734
3735
3736 Roo.apply(Roo.lib.Color.prototype, {
3737   
3738   rgb : null,
3739   hsv : null,
3740   hsl : null,
3741   
3742   /**
3743    * getIntegerRGB
3744    * @return {Object} an object representing the RGBA components of this Color. The red,
3745    * green, and blue components are converted to integers in the range [0,255].
3746    * The alpha is a value in the range [0,1].
3747    */
3748   getIntegerRGB : function(){
3749
3750     // get the RGB components of this Color
3751     var rgb = this.getRGB();
3752
3753     // return the integer components
3754     return {
3755       'r' : Math.round(rgb.r),
3756       'g' : Math.round(rgb.g),
3757       'b' : Math.round(rgb.b),
3758       'a' : rgb.a
3759     };
3760
3761   },
3762
3763   /**
3764    * getPercentageRGB
3765    * @return {Object} an object representing the RGBA components of this Color. The red,
3766    * green, and blue components are converted to numbers in the range [0,100].
3767    * The alpha is a value in the range [0,1].
3768    */
3769   getPercentageRGB : function(){
3770
3771     // get the RGB components of this Color
3772     var rgb = this.getRGB();
3773
3774     // return the percentage components
3775     return {
3776       'r' : 100 * rgb.r / 255,
3777       'g' : 100 * rgb.g / 255,
3778       'b' : 100 * rgb.b / 255,
3779       'a' : rgb.a
3780     };
3781
3782   },
3783
3784   /**
3785    * getCSSHexadecimalRGB
3786    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3787    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3788    * are two-digit hexadecimal numbers.
3789    */
3790   getCSSHexadecimalRGB : function()
3791   {
3792
3793     // get the integer RGB components
3794     var rgb = this.getIntegerRGB();
3795
3796     // determine the hexadecimal equivalents
3797     var r16 = rgb.r.toString(16);
3798     var g16 = rgb.g.toString(16);
3799     var b16 = rgb.b.toString(16);
3800
3801     // return the CSS RGB Color value
3802     return '#'
3803         + (r16.length == 2 ? r16 : '0' + r16)
3804         + (g16.length == 2 ? g16 : '0' + g16)
3805         + (b16.length == 2 ? b16 : '0' + b16);
3806
3807   },
3808
3809   /**
3810    * getCSSIntegerRGB
3811    * @return {String} a string representing this Color as a CSS integer RGB Color
3812    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3813    * are integers in the range [0,255].
3814    */
3815   getCSSIntegerRGB : function(){
3816
3817     // get the integer RGB components
3818     var rgb = this.getIntegerRGB();
3819
3820     // return the CSS RGB Color value
3821     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3822
3823   },
3824
3825   /**
3826    * getCSSIntegerRGBA
3827    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3828    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3829    * b are integers in the range [0,255] and a is in the range [0,1].
3830    */
3831   getCSSIntegerRGBA : function(){
3832
3833     // get the integer RGB components
3834     var rgb = this.getIntegerRGB();
3835
3836     // return the CSS integer RGBA Color value
3837     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3838
3839   },
3840
3841   /**
3842    * getCSSPercentageRGB
3843    * @return {String} a string representing this Color as a CSS percentage RGB Color
3844    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3845    * b are in the range [0,100].
3846    */
3847   getCSSPercentageRGB : function(){
3848
3849     // get the percentage RGB components
3850     var rgb = this.getPercentageRGB();
3851
3852     // return the CSS RGB Color value
3853     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3854
3855   },
3856
3857   /**
3858    * getCSSPercentageRGBA
3859    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3860    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3861    * and b are in the range [0,100] and a is in the range [0,1].
3862    */
3863   getCSSPercentageRGBA : function(){
3864
3865     // get the percentage RGB components
3866     var rgb = this.getPercentageRGB();
3867
3868     // return the CSS percentage RGBA Color value
3869     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3870
3871   },
3872
3873   /**
3874    * getCSSHSL
3875    * @return {String} a string representing this Color as a CSS HSL Color value - that
3876    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3877    * s and l are in the range [0,100].
3878    */
3879   getCSSHSL : function(){
3880
3881     // get the HSL components
3882     var hsl = this.getHSL();
3883
3884     // return the CSS HSL Color value
3885     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3886
3887   },
3888
3889   /**
3890    * getCSSHSLA
3891    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3892    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3893    * s and l are in the range [0,100], and a is in the range [0,1].
3894    */
3895   getCSSHSLA : function(){
3896
3897     // get the HSL components
3898     var hsl = this.getHSL();
3899
3900     // return the CSS HSL Color value
3901     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3902
3903   },
3904
3905   /**
3906    * Sets the Color of the specified node to this Color. This functions sets
3907    * the CSS 'color' property for the node. The parameter is:
3908    * 
3909    * @param {DomElement} node - the node whose Color should be set
3910    */
3911   setNodeColor : function(node){
3912
3913     // set the Color of the node
3914     node.style.color = this.getCSSHexadecimalRGB();
3915
3916   },
3917
3918   /**
3919    * Sets the background Color of the specified node to this Color. This
3920    * functions sets the CSS 'background-color' property for the node. The
3921    * parameter is:
3922    *
3923    * @param {DomElement} node - the node whose background Color should be set
3924    */
3925   setNodeBackgroundColor : function(node){
3926
3927     // set the background Color of the node
3928     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3929
3930   },
3931   // convert between formats..
3932   toRGB: function()
3933   {
3934     var r = this.getIntegerRGB();
3935     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3936     
3937   },
3938   toHSL : function()
3939   {
3940      var hsl = this.getHSL();
3941   // return the CSS HSL Color value
3942     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3943     
3944   },
3945   
3946   toHSV : function()
3947   {
3948     var rgb = this.toRGB();
3949     var hsv = rgb.getHSV();
3950    // return the CSS HSL Color value
3951     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3952     
3953   },
3954   
3955   // modify  v = 0 ... 1 (eg. 0.5)
3956   saturate : function(v)
3957   {
3958       var rgb = this.toRGB();
3959       var hsv = rgb.getHSV();
3960       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3961       
3962   
3963   },
3964   
3965    
3966   /**
3967    * getRGB
3968    * @return {Object} the RGB and alpha components of this Color as an object with r,
3969    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3970    * the range [0,1].
3971    */
3972   getRGB: function(){
3973    
3974     // return the RGB components
3975     return {
3976       'r' : this.rgb.r,
3977       'g' : this.rgb.g,
3978       'b' : this.rgb.b,
3979       'a' : this.alpha
3980     };
3981
3982   },
3983
3984   /**
3985    * getHSV
3986    * @return {Object} the HSV and alpha components of this Color as an object with h,
3987    * s, v, and a properties. h is in the range [0,360), s and v are in the range
3988    * [0,100], and a is in the range [0,1].
3989    */
3990   getHSV : function()
3991   {
3992     
3993     // calculate the HSV components if necessary
3994     if (this.hsv == null) {
3995       this.calculateHSV();
3996     }
3997
3998     // return the HSV components
3999     return {
4000       'h' : this.hsv.h,
4001       's' : this.hsv.s,
4002       'v' : this.hsv.v,
4003       'a' : this.alpha
4004     };
4005
4006   },
4007
4008   /**
4009    * getHSL
4010    * @return {Object} the HSL and alpha components of this Color as an object with h,
4011    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4012    * [0,100], and a is in the range [0,1].
4013    */
4014   getHSL : function(){
4015     
4016      
4017     // calculate the HSV components if necessary
4018     if (this.hsl == null) { this.calculateHSL(); }
4019
4020     // return the HSL components
4021     return {
4022       'h' : this.hsl.h,
4023       's' : this.hsl.s,
4024       'l' : this.hsl.l,
4025       'a' : this.alpha
4026     };
4027
4028   }
4029   
4030
4031 });
4032
4033
4034 /**
4035  * @class Roo.lib.RGBColor
4036  * @extends Roo.lib.Color
4037  * Creates a Color specified in the RGB Color space, with an optional alpha
4038  * component. The parameters are:
4039  * @constructor
4040  * 
4041
4042  * @param {Number} r - the red component, clipped to the range [0,255]
4043  * @param {Number} g - the green component, clipped to the range [0,255]
4044  * @param {Number} b - the blue component, clipped to the range [0,255]
4045  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4046  *     optional and defaults to 1
4047  */
4048 Roo.lib.RGBColor = function (r, g, b, a){
4049
4050   // store the alpha component after clipping it if necessary
4051   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4052
4053   // store the RGB components after clipping them if necessary
4054   this.rgb =
4055       {
4056         'r' : Math.max(0, Math.min(255, r)),
4057         'g' : Math.max(0, Math.min(255, g)),
4058         'b' : Math.max(0, Math.min(255, b))
4059       };
4060
4061   // initialise the HSV and HSL components to null
4062   
4063
4064   /* 
4065    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4066    * range [0,360). The parameters are:
4067    *
4068    * maximum - the maximum of the RGB component values
4069    * range   - the range of the RGB component values
4070    */
4071    
4072
4073 }
4074 // this does an 'exteds'
4075 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4076
4077   
4078     getHue  : function(maximum, range)
4079     {
4080       var rgb = this.rgb;
4081        
4082       // check whether the range is zero
4083       if (range == 0){
4084   
4085         // set the hue to zero (any hue is acceptable as the Color is grey)
4086         var hue = 0;
4087   
4088       }else{
4089   
4090         // determine which of the components has the highest value and set the hue
4091         switch (maximum){
4092   
4093           // red has the highest value
4094           case rgb.r:
4095             var hue = (rgb.g - rgb.b) / range * 60;
4096             if (hue < 0) { hue += 360; }
4097             break;
4098   
4099           // green has the highest value
4100           case rgb.g:
4101             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4102             break;
4103   
4104           // blue has the highest value
4105           case rgb.b:
4106             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4107             break;
4108   
4109         }
4110   
4111       }
4112   
4113       // return the hue
4114       return hue;
4115   
4116     },
4117
4118   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4119    * be returned be the getHSV function.
4120    */
4121    calculateHSV : function(){
4122     var rgb = this.rgb;
4123     // get the maximum and range of the RGB component values
4124     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4125     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4126
4127     // store the HSV components
4128     this.hsv =
4129         {
4130           'h' : this.getHue(maximum, range),
4131           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4132           'v' : maximum / 2.55
4133         };
4134
4135   },
4136
4137   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4138    * be returned be the getHSL function.
4139    */
4140    calculateHSL : function(){
4141     var rgb = this.rgb;
4142     // get the maximum and range of the RGB component values
4143     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4144     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4145
4146     // determine the lightness in the range [0,1]
4147     var l = maximum / 255 - range / 510;
4148
4149     // store the HSL components
4150     this.hsl =
4151         {
4152           'h' : this.getHue(maximum, range),
4153           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4154           'l' : 100 * l
4155         };
4156
4157   }
4158
4159 });
4160
4161 /**
4162  * @class Roo.lib.HSVColor
4163  * @extends Roo.lib.Color
4164  * Creates a Color specified in the HSV Color space, with an optional alpha
4165  * component. The parameters are:
4166  * @constructor
4167  *
4168  * @param {Number} h - the hue component, wrapped to the range [0,360)
4169  * @param {Number} s - the saturation component, clipped to the range [0,100]
4170  * @param {Number} v - the value component, clipped to the range [0,100]
4171  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4172  *     optional and defaults to 1
4173  */
4174 Roo.lib.HSVColor = function (h, s, v, a){
4175
4176   // store the alpha component after clipping it if necessary
4177   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4178
4179   // store the HSV components after clipping or wrapping them if necessary
4180   this.hsv =
4181       {
4182         'h' : (h % 360 + 360) % 360,
4183         's' : Math.max(0, Math.min(100, s)),
4184         'v' : Math.max(0, Math.min(100, v))
4185       };
4186
4187   // initialise the RGB and HSL components to null
4188   this.rgb = null;
4189   this.hsl = null;
4190 }
4191
4192 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4193   /* Calculates and stores the RGB components of this HSVColor so that they can
4194    * be returned be the getRGB function.
4195    */
4196   calculateRGB: function ()
4197   {
4198     var hsv = this.hsv;
4199     // check whether the saturation is zero
4200     if (hsv.s == 0){
4201
4202       // set the Color to the appropriate shade of grey
4203       var r = hsv.v;
4204       var g = hsv.v;
4205       var b = hsv.v;
4206
4207     }else{
4208
4209       // set some temporary values
4210       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4211       var p  = hsv.v * (1 - hsv.s / 100);
4212       var q  = hsv.v * (1 - hsv.s / 100 * f);
4213       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4214
4215       // set the RGB Color components to their temporary values
4216       switch (Math.floor(hsv.h / 60)){
4217         case 0: var r = hsv.v; var g = t; var b = p; break;
4218         case 1: var r = q; var g = hsv.v; var b = p; break;
4219         case 2: var r = p; var g = hsv.v; var b = t; break;
4220         case 3: var r = p; var g = q; var b = hsv.v; break;
4221         case 4: var r = t; var g = p; var b = hsv.v; break;
4222         case 5: var r = hsv.v; var g = p; var b = q; break;
4223       }
4224
4225     }
4226
4227     // store the RGB components
4228     this.rgb =
4229         {
4230           'r' : r * 2.55,
4231           'g' : g * 2.55,
4232           'b' : b * 2.55
4233         };
4234
4235   },
4236
4237   /* Calculates and stores the HSL components of this HSVColor so that they can
4238    * be returned be the getHSL function.
4239    */
4240   calculateHSL : function (){
4241
4242     var hsv = this.hsv;
4243     // determine the lightness in the range [0,100]
4244     var l = (2 - hsv.s / 100) * hsv.v / 2;
4245
4246     // store the HSL components
4247     this.hsl =
4248         {
4249           'h' : hsv.h,
4250           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4251           'l' : l
4252         };
4253
4254     // correct a division-by-zero error
4255     if (isNaN(hsl.s)) { hsl.s = 0; }
4256
4257   } 
4258  
4259
4260 });
4261  
4262
4263 /**
4264  * @class Roo.lib.HSLColor
4265  * @extends Roo.lib.Color
4266  *
4267  * @constructor
4268  * Creates a Color specified in the HSL Color space, with an optional alpha
4269  * component. The parameters are:
4270  *
4271  * @param {Number} h - the hue component, wrapped to the range [0,360)
4272  * @param {Number} s - the saturation component, clipped to the range [0,100]
4273  * @param {Number} l - the lightness component, clipped to the range [0,100]
4274  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4275  *     optional and defaults to 1
4276  */
4277
4278 Roo.lib.HSLColor = function(h, s, l, a){
4279
4280   // store the alpha component after clipping it if necessary
4281   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4282
4283   // store the HSL components after clipping or wrapping them if necessary
4284   this.hsl =
4285       {
4286         'h' : (h % 360 + 360) % 360,
4287         's' : Math.max(0, Math.min(100, s)),
4288         'l' : Math.max(0, Math.min(100, l))
4289       };
4290
4291   // initialise the RGB and HSV components to null
4292 }
4293
4294 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4295
4296   /* Calculates and stores the RGB components of this HSLColor so that they can
4297    * be returned be the getRGB function.
4298    */
4299   calculateRGB: function (){
4300
4301     // check whether the saturation is zero
4302     if (this.hsl.s == 0){
4303
4304       // store the RGB components representing the appropriate shade of grey
4305       this.rgb =
4306           {
4307             'r' : this.hsl.l * 2.55,
4308             'g' : this.hsl.l * 2.55,
4309             'b' : this.hsl.l * 2.55
4310           };
4311
4312     }else{
4313
4314       // set some temporary values
4315       var p = this.hsl.l < 50
4316             ? this.hsl.l * (1 + hsl.s / 100)
4317             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4318       var q = 2 * hsl.l - p;
4319
4320       // initialise the RGB components
4321       this.rgb =
4322           {
4323             'r' : (h + 120) / 60 % 6,
4324             'g' : h / 60,
4325             'b' : (h + 240) / 60 % 6
4326           };
4327
4328       // loop over the RGB components
4329       for (var key in this.rgb){
4330
4331         // ensure that the property is not inherited from the root object
4332         if (this.rgb.hasOwnProperty(key)){
4333
4334           // set the component to its value in the range [0,100]
4335           if (this.rgb[key] < 1){
4336             this.rgb[key] = q + (p - q) * this.rgb[key];
4337           }else if (this.rgb[key] < 3){
4338             this.rgb[key] = p;
4339           }else if (this.rgb[key] < 4){
4340             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4341           }else{
4342             this.rgb[key] = q;
4343           }
4344
4345           // set the component to its value in the range [0,255]
4346           this.rgb[key] *= 2.55;
4347
4348         }
4349
4350       }
4351
4352     }
4353
4354   },
4355
4356   /* Calculates and stores the HSV components of this HSLColor so that they can
4357    * be returned be the getHSL function.
4358    */
4359    calculateHSV : function(){
4360
4361     // set a temporary value
4362     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4363
4364     // store the HSV components
4365     this.hsv =
4366         {
4367           'h' : this.hsl.h,
4368           's' : 200 * t / (this.hsl.l + t),
4369           'v' : t + this.hsl.l
4370         };
4371
4372     // correct a division-by-zero error
4373     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4374
4375   }
4376  
4377
4378 });
4379 /*
4380  * Portions of this file are based on pieces of Yahoo User Interface Library
4381  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4382  * YUI licensed under the BSD License:
4383  * http://developer.yahoo.net/yui/license.txt
4384  * <script type="text/javascript">
4385  *
4386  */
4387 (function() {
4388
4389     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4390         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4391     };
4392
4393     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4394
4395     var fly = Roo.lib.AnimBase.fly;
4396     var Y = Roo.lib;
4397     var superclass = Y.ColorAnim.superclass;
4398     var proto = Y.ColorAnim.prototype;
4399
4400     proto.toString = function() {
4401         var el = this.getEl();
4402         var id = el.id || el.tagName;
4403         return ("ColorAnim " + id);
4404     };
4405
4406     proto.patterns.color = /color$/i;
4407     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4408     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4409     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4410     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4411
4412
4413     proto.parseColor = function(s) {
4414         if (s.length == 3) {
4415             return s;
4416         }
4417
4418         var c = this.patterns.hex.exec(s);
4419         if (c && c.length == 4) {
4420             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4421         }
4422
4423         c = this.patterns.rgb.exec(s);
4424         if (c && c.length == 4) {
4425             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4426         }
4427
4428         c = this.patterns.hex3.exec(s);
4429         if (c && c.length == 4) {
4430             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4431         }
4432
4433         return null;
4434     };
4435     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4436     proto.getAttribute = function(attr) {
4437         var el = this.getEl();
4438         if (this.patterns.color.test(attr)) {
4439             var val = fly(el).getStyle(attr);
4440
4441             if (this.patterns.transparent.test(val)) {
4442                 var parent = el.parentNode;
4443                 val = fly(parent).getStyle(attr);
4444
4445                 while (parent && this.patterns.transparent.test(val)) {
4446                     parent = parent.parentNode;
4447                     val = fly(parent).getStyle(attr);
4448                     if (parent.tagName.toUpperCase() == 'HTML') {
4449                         val = '#fff';
4450                     }
4451                 }
4452             }
4453         } else {
4454             val = superclass.getAttribute.call(this, attr);
4455         }
4456
4457         return val;
4458     };
4459     proto.getAttribute = function(attr) {
4460         var el = this.getEl();
4461         if (this.patterns.color.test(attr)) {
4462             var val = fly(el).getStyle(attr);
4463
4464             if (this.patterns.transparent.test(val)) {
4465                 var parent = el.parentNode;
4466                 val = fly(parent).getStyle(attr);
4467
4468                 while (parent && this.patterns.transparent.test(val)) {
4469                     parent = parent.parentNode;
4470                     val = fly(parent).getStyle(attr);
4471                     if (parent.tagName.toUpperCase() == 'HTML') {
4472                         val = '#fff';
4473                     }
4474                 }
4475             }
4476         } else {
4477             val = superclass.getAttribute.call(this, attr);
4478         }
4479
4480         return val;
4481     };
4482
4483     proto.doMethod = function(attr, start, end) {
4484         var val;
4485
4486         if (this.patterns.color.test(attr)) {
4487             val = [];
4488             for (var i = 0, len = start.length; i < len; ++i) {
4489                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4490             }
4491
4492             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4493         }
4494         else {
4495             val = superclass.doMethod.call(this, attr, start, end);
4496         }
4497
4498         return val;
4499     };
4500
4501     proto.setRuntimeAttribute = function(attr) {
4502         superclass.setRuntimeAttribute.call(this, attr);
4503
4504         if (this.patterns.color.test(attr)) {
4505             var attributes = this.attributes;
4506             var start = this.parseColor(this.runtimeAttributes[attr].start);
4507             var end = this.parseColor(this.runtimeAttributes[attr].end);
4508
4509             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4510                 end = this.parseColor(attributes[attr].by);
4511
4512                 for (var i = 0, len = start.length; i < len; ++i) {
4513                     end[i] = start[i] + end[i];
4514                 }
4515             }
4516
4517             this.runtimeAttributes[attr].start = start;
4518             this.runtimeAttributes[attr].end = end;
4519         }
4520     };
4521 })();
4522
4523 /*
4524  * Portions of this file are based on pieces of Yahoo User Interface Library
4525  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4526  * YUI licensed under the BSD License:
4527  * http://developer.yahoo.net/yui/license.txt
4528  * <script type="text/javascript">
4529  *
4530  */
4531 Roo.lib.Easing = {
4532
4533
4534     easeNone: function (t, b, c, d) {
4535         return c * t / d + b;
4536     },
4537
4538
4539     easeIn: function (t, b, c, d) {
4540         return c * (t /= d) * t + b;
4541     },
4542
4543
4544     easeOut: function (t, b, c, d) {
4545         return -c * (t /= d) * (t - 2) + b;
4546     },
4547
4548
4549     easeBoth: function (t, b, c, d) {
4550         if ((t /= d / 2) < 1) {
4551             return c / 2 * t * t + b;
4552         }
4553
4554         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4555     },
4556
4557
4558     easeInStrong: function (t, b, c, d) {
4559         return c * (t /= d) * t * t * t + b;
4560     },
4561
4562
4563     easeOutStrong: function (t, b, c, d) {
4564         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4565     },
4566
4567
4568     easeBothStrong: function (t, b, c, d) {
4569         if ((t /= d / 2) < 1) {
4570             return c / 2 * t * t * t * t + b;
4571         }
4572
4573         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4574     },
4575
4576
4577
4578     elasticIn: function (t, b, c, d, a, p) {
4579         if (t == 0) {
4580             return b;
4581         }
4582         if ((t /= d) == 1) {
4583             return b + c;
4584         }
4585         if (!p) {
4586             p = d * .3;
4587         }
4588
4589         if (!a || a < Math.abs(c)) {
4590             a = c;
4591             var s = p / 4;
4592         }
4593         else {
4594             var s = p / (2 * Math.PI) * Math.asin(c / a);
4595         }
4596
4597         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4598     },
4599
4600
4601     elasticOut: function (t, b, c, d, a, p) {
4602         if (t == 0) {
4603             return b;
4604         }
4605         if ((t /= d) == 1) {
4606             return b + c;
4607         }
4608         if (!p) {
4609             p = d * .3;
4610         }
4611
4612         if (!a || a < Math.abs(c)) {
4613             a = c;
4614             var s = p / 4;
4615         }
4616         else {
4617             var s = p / (2 * Math.PI) * Math.asin(c / a);
4618         }
4619
4620         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4621     },
4622
4623
4624     elasticBoth: function (t, b, c, d, a, p) {
4625         if (t == 0) {
4626             return b;
4627         }
4628
4629         if ((t /= d / 2) == 2) {
4630             return b + c;
4631         }
4632
4633         if (!p) {
4634             p = d * (.3 * 1.5);
4635         }
4636
4637         if (!a || a < Math.abs(c)) {
4638             a = c;
4639             var s = p / 4;
4640         }
4641         else {
4642             var s = p / (2 * Math.PI) * Math.asin(c / a);
4643         }
4644
4645         if (t < 1) {
4646             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4647                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4648         }
4649         return a * Math.pow(2, -10 * (t -= 1)) *
4650                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4651     },
4652
4653
4654
4655     backIn: function (t, b, c, d, s) {
4656         if (typeof s == 'undefined') {
4657             s = 1.70158;
4658         }
4659         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4660     },
4661
4662
4663     backOut: function (t, b, c, d, s) {
4664         if (typeof s == 'undefined') {
4665             s = 1.70158;
4666         }
4667         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4668     },
4669
4670
4671     backBoth: function (t, b, c, d, s) {
4672         if (typeof s == 'undefined') {
4673             s = 1.70158;
4674         }
4675
4676         if ((t /= d / 2 ) < 1) {
4677             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4678         }
4679         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4680     },
4681
4682
4683     bounceIn: function (t, b, c, d) {
4684         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4685     },
4686
4687
4688     bounceOut: function (t, b, c, d) {
4689         if ((t /= d) < (1 / 2.75)) {
4690             return c * (7.5625 * t * t) + b;
4691         } else if (t < (2 / 2.75)) {
4692             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4693         } else if (t < (2.5 / 2.75)) {
4694             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4695         }
4696         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4697     },
4698
4699
4700     bounceBoth: function (t, b, c, d) {
4701         if (t < d / 2) {
4702             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4703         }
4704         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4705     }
4706 };/*
4707  * Portions of this file are based on pieces of Yahoo User Interface Library
4708  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4709  * YUI licensed under the BSD License:
4710  * http://developer.yahoo.net/yui/license.txt
4711  * <script type="text/javascript">
4712  *
4713  */
4714     (function() {
4715         Roo.lib.Motion = function(el, attributes, duration, method) {
4716             if (el) {
4717                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4718             }
4719         };
4720
4721         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4722
4723
4724         var Y = Roo.lib;
4725         var superclass = Y.Motion.superclass;
4726         var proto = Y.Motion.prototype;
4727
4728         proto.toString = function() {
4729             var el = this.getEl();
4730             var id = el.id || el.tagName;
4731             return ("Motion " + id);
4732         };
4733
4734         proto.patterns.points = /^points$/i;
4735
4736         proto.setAttribute = function(attr, val, unit) {
4737             if (this.patterns.points.test(attr)) {
4738                 unit = unit || 'px';
4739                 superclass.setAttribute.call(this, 'left', val[0], unit);
4740                 superclass.setAttribute.call(this, 'top', val[1], unit);
4741             } else {
4742                 superclass.setAttribute.call(this, attr, val, unit);
4743             }
4744         };
4745
4746         proto.getAttribute = function(attr) {
4747             if (this.patterns.points.test(attr)) {
4748                 var val = [
4749                         superclass.getAttribute.call(this, 'left'),
4750                         superclass.getAttribute.call(this, 'top')
4751                         ];
4752             } else {
4753                 val = superclass.getAttribute.call(this, attr);
4754             }
4755
4756             return val;
4757         };
4758
4759         proto.doMethod = function(attr, start, end) {
4760             var val = null;
4761
4762             if (this.patterns.points.test(attr)) {
4763                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4764                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4765             } else {
4766                 val = superclass.doMethod.call(this, attr, start, end);
4767             }
4768             return val;
4769         };
4770
4771         proto.setRuntimeAttribute = function(attr) {
4772             if (this.patterns.points.test(attr)) {
4773                 var el = this.getEl();
4774                 var attributes = this.attributes;
4775                 var start;
4776                 var control = attributes['points']['control'] || [];
4777                 var end;
4778                 var i, len;
4779
4780                 if (control.length > 0 && !(control[0] instanceof Array)) {
4781                     control = [control];
4782                 } else {
4783                     var tmp = [];
4784                     for (i = 0,len = control.length; i < len; ++i) {
4785                         tmp[i] = control[i];
4786                     }
4787                     control = tmp;
4788                 }
4789
4790                 Roo.fly(el).position();
4791
4792                 if (isset(attributes['points']['from'])) {
4793                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4794                 }
4795                 else {
4796                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4797                 }
4798
4799                 start = this.getAttribute('points');
4800
4801
4802                 if (isset(attributes['points']['to'])) {
4803                     end = translateValues.call(this, attributes['points']['to'], start);
4804
4805                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4806                     for (i = 0,len = control.length; i < len; ++i) {
4807                         control[i] = translateValues.call(this, control[i], start);
4808                     }
4809
4810
4811                 } else if (isset(attributes['points']['by'])) {
4812                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4813
4814                     for (i = 0,len = control.length; i < len; ++i) {
4815                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4816                     }
4817                 }
4818
4819                 this.runtimeAttributes[attr] = [start];
4820
4821                 if (control.length > 0) {
4822                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4823                 }
4824
4825                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4826             }
4827             else {
4828                 superclass.setRuntimeAttribute.call(this, attr);
4829             }
4830         };
4831
4832         var translateValues = function(val, start) {
4833             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4834             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4835
4836             return val;
4837         };
4838
4839         var isset = function(prop) {
4840             return (typeof prop !== 'undefined');
4841         };
4842     })();
4843 /*
4844  * Portions of this file are based on pieces of Yahoo User Interface Library
4845  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4846  * YUI licensed under the BSD License:
4847  * http://developer.yahoo.net/yui/license.txt
4848  * <script type="text/javascript">
4849  *
4850  */
4851     (function() {
4852         Roo.lib.Scroll = function(el, attributes, duration, method) {
4853             if (el) {
4854                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4855             }
4856         };
4857
4858         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4859
4860
4861         var Y = Roo.lib;
4862         var superclass = Y.Scroll.superclass;
4863         var proto = Y.Scroll.prototype;
4864
4865         proto.toString = function() {
4866             var el = this.getEl();
4867             var id = el.id || el.tagName;
4868             return ("Scroll " + id);
4869         };
4870
4871         proto.doMethod = function(attr, start, end) {
4872             var val = null;
4873
4874             if (attr == 'scroll') {
4875                 val = [
4876                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4877                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4878                         ];
4879
4880             } else {
4881                 val = superclass.doMethod.call(this, attr, start, end);
4882             }
4883             return val;
4884         };
4885
4886         proto.getAttribute = function(attr) {
4887             var val = null;
4888             var el = this.getEl();
4889
4890             if (attr == 'scroll') {
4891                 val = [ el.scrollLeft, el.scrollTop ];
4892             } else {
4893                 val = superclass.getAttribute.call(this, attr);
4894             }
4895
4896             return val;
4897         };
4898
4899         proto.setAttribute = function(attr, val, unit) {
4900             var el = this.getEl();
4901
4902             if (attr == 'scroll') {
4903                 el.scrollLeft = val[0];
4904                 el.scrollTop = val[1];
4905             } else {
4906                 superclass.setAttribute.call(this, attr, val, unit);
4907             }
4908         };
4909     })();
4910 /*
4911  * Based on:
4912  * Ext JS Library 1.1.1
4913  * Copyright(c) 2006-2007, Ext JS, LLC.
4914  *
4915  * Originally Released Under LGPL - original licence link has changed is not relivant.
4916  *
4917  * Fork - LGPL
4918  * <script type="text/javascript">
4919  */
4920
4921
4922 // nasty IE9 hack - what a pile of crap that is..
4923
4924  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4925     Range.prototype.createContextualFragment = function (html) {
4926         var doc = window.document;
4927         var container = doc.createElement("div");
4928         container.innerHTML = html;
4929         var frag = doc.createDocumentFragment(), n;
4930         while ((n = container.firstChild)) {
4931             frag.appendChild(n);
4932         }
4933         return frag;
4934     };
4935 }
4936
4937 /**
4938  * @class Roo.DomHelper
4939  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4940  * 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>.
4941  * @static
4942  */
4943 Roo.DomHelper = function(){
4944     var tempTableEl = null;
4945     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4946     var tableRe = /^table|tbody|tr|td$/i;
4947     var xmlns = {};
4948     // build as innerHTML where available
4949     /** @ignore */
4950     var createHtml = function(o){
4951         if(typeof o == 'string'){
4952             return o;
4953         }
4954         var b = "";
4955         if(!o.tag){
4956             o.tag = "div";
4957         }
4958         b += "<" + o.tag;
4959         for(var attr in o){
4960             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4961             if(attr == "style"){
4962                 var s = o["style"];
4963                 if(typeof s == "function"){
4964                     s = s.call();
4965                 }
4966                 if(typeof s == "string"){
4967                     b += ' style="' + s + '"';
4968                 }else if(typeof s == "object"){
4969                     b += ' style="';
4970                     for(var key in s){
4971                         if(typeof s[key] != "function"){
4972                             b += key + ":" + s[key] + ";";
4973                         }
4974                     }
4975                     b += '"';
4976                 }
4977             }else{
4978                 if(attr == "cls"){
4979                     b += ' class="' + o["cls"] + '"';
4980                 }else if(attr == "htmlFor"){
4981                     b += ' for="' + o["htmlFor"] + '"';
4982                 }else{
4983                     b += " " + attr + '="' + o[attr] + '"';
4984                 }
4985             }
4986         }
4987         if(emptyTags.test(o.tag)){
4988             b += "/>";
4989         }else{
4990             b += ">";
4991             var cn = o.children || o.cn;
4992             if(cn){
4993                 //http://bugs.kde.org/show_bug.cgi?id=71506
4994                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4995                     for(var i = 0, len = cn.length; i < len; i++) {
4996                         b += createHtml(cn[i], b);
4997                     }
4998                 }else{
4999                     b += createHtml(cn, b);
5000                 }
5001             }
5002             if(o.html){
5003                 b += o.html;
5004             }
5005             b += "</" + o.tag + ">";
5006         }
5007         return b;
5008     };
5009
5010     // build as dom
5011     /** @ignore */
5012     var createDom = function(o, parentNode){
5013          
5014         // defininition craeted..
5015         var ns = false;
5016         if (o.ns && o.ns != 'html') {
5017                
5018             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5019                 xmlns[o.ns] = o.xmlns;
5020                 ns = o.xmlns;
5021             }
5022             if (typeof(xmlns[o.ns]) == 'undefined') {
5023                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5024             }
5025             ns = xmlns[o.ns];
5026         }
5027         
5028         
5029         if (typeof(o) == 'string') {
5030             return parentNode.appendChild(document.createTextNode(o));
5031         }
5032         o.tag = o.tag || div;
5033         if (o.ns && Roo.isIE) {
5034             ns = false;
5035             o.tag = o.ns + ':' + o.tag;
5036             
5037         }
5038         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5039         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5040         for(var attr in o){
5041             
5042             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5043                     attr == "style" || typeof o[attr] == "function") { continue; }
5044                     
5045             if(attr=="cls" && Roo.isIE){
5046                 el.className = o["cls"];
5047             }else{
5048                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5049                 else { 
5050                     el[attr] = o[attr];
5051                 }
5052             }
5053         }
5054         Roo.DomHelper.applyStyles(el, o.style);
5055         var cn = o.children || o.cn;
5056         if(cn){
5057             //http://bugs.kde.org/show_bug.cgi?id=71506
5058              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5059                 for(var i = 0, len = cn.length; i < len; i++) {
5060                     createDom(cn[i], el);
5061                 }
5062             }else{
5063                 createDom(cn, el);
5064             }
5065         }
5066         if(o.html){
5067             el.innerHTML = o.html;
5068         }
5069         if(parentNode){
5070            parentNode.appendChild(el);
5071         }
5072         return el;
5073     };
5074
5075     var ieTable = function(depth, s, h, e){
5076         tempTableEl.innerHTML = [s, h, e].join('');
5077         var i = -1, el = tempTableEl;
5078         while(++i < depth && el.firstChild){
5079             el = el.firstChild;
5080         }
5081         return el;
5082     };
5083
5084     // kill repeat to save bytes
5085     var ts = '<table>',
5086         te = '</table>',
5087         tbs = ts+'<tbody>',
5088         tbe = '</tbody>'+te,
5089         trs = tbs + '<tr>',
5090         tre = '</tr>'+tbe;
5091
5092     /**
5093      * @ignore
5094      * Nasty code for IE's broken table implementation
5095      */
5096     var insertIntoTable = function(tag, where, el, html){
5097         if(!tempTableEl){
5098             tempTableEl = document.createElement('div');
5099         }
5100         var node;
5101         var before = null;
5102         if(tag == 'td'){
5103             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5104                 return;
5105             }
5106             if(where == 'beforebegin'){
5107                 before = el;
5108                 el = el.parentNode;
5109             } else{
5110                 before = el.nextSibling;
5111                 el = el.parentNode;
5112             }
5113             node = ieTable(4, trs, html, tre);
5114         }
5115         else if(tag == 'tr'){
5116             if(where == 'beforebegin'){
5117                 before = el;
5118                 el = el.parentNode;
5119                 node = ieTable(3, tbs, html, tbe);
5120             } else if(where == 'afterend'){
5121                 before = el.nextSibling;
5122                 el = el.parentNode;
5123                 node = ieTable(3, tbs, html, tbe);
5124             } else{ // INTO a TR
5125                 if(where == 'afterbegin'){
5126                     before = el.firstChild;
5127                 }
5128                 node = ieTable(4, trs, html, tre);
5129             }
5130         } else if(tag == 'tbody'){
5131             if(where == 'beforebegin'){
5132                 before = el;
5133                 el = el.parentNode;
5134                 node = ieTable(2, ts, html, te);
5135             } else if(where == 'afterend'){
5136                 before = el.nextSibling;
5137                 el = el.parentNode;
5138                 node = ieTable(2, ts, html, te);
5139             } else{
5140                 if(where == 'afterbegin'){
5141                     before = el.firstChild;
5142                 }
5143                 node = ieTable(3, tbs, html, tbe);
5144             }
5145         } else{ // TABLE
5146             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5147                 return;
5148             }
5149             if(where == 'afterbegin'){
5150                 before = el.firstChild;
5151             }
5152             node = ieTable(2, ts, html, te);
5153         }
5154         el.insertBefore(node, before);
5155         return node;
5156     };
5157     
5158     // this is a bit like the react update code...
5159     // 
5160     
5161     var updateNode = function(from, to)
5162     {
5163         // should we handle non-standard elements?
5164         Roo.log(["UpdateNode" , from, to]);
5165         if (from.nodeType != to.nodeType) {
5166             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5167             from.parentNode.replaceChild(to, from);
5168         }
5169         
5170         if (from.nodeType == 3) {
5171             // assume it's text?!
5172             if (from.data == to.data) {
5173                 return;
5174             }
5175             from.data = to.data;
5176             return;
5177         }
5178         if (!from.parentNode) {
5179             // not sure why this is happening?
5180             return;
5181         }
5182         // assume 'to' doesnt have '1/3 nodetypes!
5183         // not sure why, by from, parent node might not exist?
5184         if (from.nodeType !=1 || from.tagName != to.tagName) {
5185             Roo.log(["ReplaceChild" , from, to ]);
5186             
5187             from.parentNode.replaceChild(to, from);
5188             return;
5189         }
5190         // compare attributes
5191         var ar = Array.from(from.attributes);
5192         for(var i = 0; i< ar.length;i++) {
5193             if (to.hasAttribute(ar[i].name)) {
5194                 continue;
5195             }
5196             if (ar[i].name == 'id') { // always keep ids?
5197                continue;
5198             }
5199             //if (ar[i].name == 'style') {
5200             //   throw "style removed?";
5201             //}
5202             Roo.log("removeAttribute" + ar[i].name);
5203             from.removeAttribute(ar[i].name);
5204         }
5205         ar = to.attributes;
5206         for(var i = 0; i< ar.length;i++) {
5207             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5208                 Roo.log("skipAttribute " + ar[i].name  + '=' + to.getAttribute(ar[i].name));
5209                 continue;
5210             }
5211             Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5212             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5213         }
5214         // children
5215         var far = Array.from(from.childNodes);
5216         var tar = Array.from(to.childNodes);
5217         // if the lengths are different.. then it's probably a editable content change, rather than
5218         // a change of the block definition..
5219         
5220         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5221          /*if (from.innerHTML == to.innerHTML) {
5222             return;
5223         }
5224         if (far.length != tar.length) {
5225             from.innerHTML = to.innerHTML;
5226             return;
5227         }
5228         */
5229         
5230         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5231             if (i >= far.length) {
5232                 from.appendChild(tar[i]);
5233                 Roo.log(["add", tar[i]]);
5234                 
5235             } else if ( i  >= tar.length) {
5236                 from.removeChild(far[i]);
5237                 Roo.log(["remove", far[i]]);
5238             } else {
5239                 
5240                 updateNode(far[i], tar[i]);
5241             }    
5242         }
5243         
5244         
5245         
5246         
5247     };
5248     
5249     
5250
5251     return {
5252         /** True to force the use of DOM instead of html fragments @type Boolean */
5253         useDom : false,
5254     
5255         /**
5256          * Returns the markup for the passed Element(s) config
5257          * @param {Object} o The Dom object spec (and children)
5258          * @return {String}
5259          */
5260         markup : function(o){
5261             return createHtml(o);
5262         },
5263     
5264         /**
5265          * Applies a style specification to an element
5266          * @param {String/HTMLElement} el The element to apply styles to
5267          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5268          * a function which returns such a specification.
5269          */
5270         applyStyles : function(el, styles){
5271             if(styles){
5272                el = Roo.fly(el);
5273                if(typeof styles == "string"){
5274                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5275                    var matches;
5276                    while ((matches = re.exec(styles)) != null){
5277                        el.setStyle(matches[1], matches[2]);
5278                    }
5279                }else if (typeof styles == "object"){
5280                    for (var style in styles){
5281                       el.setStyle(style, styles[style]);
5282                    }
5283                }else if (typeof styles == "function"){
5284                     Roo.DomHelper.applyStyles(el, styles.call());
5285                }
5286             }
5287         },
5288     
5289         /**
5290          * Inserts an HTML fragment into the Dom
5291          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5292          * @param {HTMLElement} el The context element
5293          * @param {String} html The HTML fragmenet
5294          * @return {HTMLElement} The new node
5295          */
5296         insertHtml : function(where, el, html){
5297             where = where.toLowerCase();
5298             if(el.insertAdjacentHTML){
5299                 if(tableRe.test(el.tagName)){
5300                     var rs;
5301                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5302                         return rs;
5303                     }
5304                 }
5305                 switch(where){
5306                     case "beforebegin":
5307                         el.insertAdjacentHTML('BeforeBegin', html);
5308                         return el.previousSibling;
5309                     case "afterbegin":
5310                         el.insertAdjacentHTML('AfterBegin', html);
5311                         return el.firstChild;
5312                     case "beforeend":
5313                         el.insertAdjacentHTML('BeforeEnd', html);
5314                         return el.lastChild;
5315                     case "afterend":
5316                         el.insertAdjacentHTML('AfterEnd', html);
5317                         return el.nextSibling;
5318                 }
5319                 throw 'Illegal insertion point -> "' + where + '"';
5320             }
5321             var range = el.ownerDocument.createRange();
5322             var frag;
5323             switch(where){
5324                  case "beforebegin":
5325                     range.setStartBefore(el);
5326                     frag = range.createContextualFragment(html);
5327                     el.parentNode.insertBefore(frag, el);
5328                     return el.previousSibling;
5329                  case "afterbegin":
5330                     if(el.firstChild){
5331                         range.setStartBefore(el.firstChild);
5332                         frag = range.createContextualFragment(html);
5333                         el.insertBefore(frag, el.firstChild);
5334                         return el.firstChild;
5335                     }else{
5336                         el.innerHTML = html;
5337                         return el.firstChild;
5338                     }
5339                 case "beforeend":
5340                     if(el.lastChild){
5341                         range.setStartAfter(el.lastChild);
5342                         frag = range.createContextualFragment(html);
5343                         el.appendChild(frag);
5344                         return el.lastChild;
5345                     }else{
5346                         el.innerHTML = html;
5347                         return el.lastChild;
5348                     }
5349                 case "afterend":
5350                     range.setStartAfter(el);
5351                     frag = range.createContextualFragment(html);
5352                     el.parentNode.insertBefore(frag, el.nextSibling);
5353                     return el.nextSibling;
5354                 }
5355                 throw 'Illegal insertion point -> "' + where + '"';
5356         },
5357     
5358         /**
5359          * Creates new Dom element(s) and inserts them before el
5360          * @param {String/HTMLElement/Element} el The context element
5361          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5362          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5363          * @return {HTMLElement/Roo.Element} The new node
5364          */
5365         insertBefore : function(el, o, returnElement){
5366             return this.doInsert(el, o, returnElement, "beforeBegin");
5367         },
5368     
5369         /**
5370          * Creates new Dom element(s) and inserts them after el
5371          * @param {String/HTMLElement/Element} el The context element
5372          * @param {Object} o The Dom object spec (and children)
5373          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5374          * @return {HTMLElement/Roo.Element} The new node
5375          */
5376         insertAfter : function(el, o, returnElement){
5377             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5378         },
5379     
5380         /**
5381          * Creates new Dom element(s) and inserts them as the first child of el
5382          * @param {String/HTMLElement/Element} el The context element
5383          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5384          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5385          * @return {HTMLElement/Roo.Element} The new node
5386          */
5387         insertFirst : function(el, o, returnElement){
5388             return this.doInsert(el, o, returnElement, "afterBegin");
5389         },
5390     
5391         // private
5392         doInsert : function(el, o, returnElement, pos, sibling){
5393             el = Roo.getDom(el);
5394             var newNode;
5395             if(this.useDom || o.ns){
5396                 newNode = createDom(o, null);
5397                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5398             }else{
5399                 var html = createHtml(o);
5400                 newNode = this.insertHtml(pos, el, html);
5401             }
5402             return returnElement ? Roo.get(newNode, true) : newNode;
5403         },
5404     
5405         /**
5406          * Creates new Dom element(s) and appends them to el
5407          * @param {String/HTMLElement/Element} el The context element
5408          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5409          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5410          * @return {HTMLElement/Roo.Element} The new node
5411          */
5412         append : function(el, o, returnElement){
5413             el = Roo.getDom(el);
5414             var newNode;
5415             if(this.useDom || o.ns){
5416                 newNode = createDom(o, null);
5417                 el.appendChild(newNode);
5418             }else{
5419                 var html = createHtml(o);
5420                 newNode = this.insertHtml("beforeEnd", el, html);
5421             }
5422             return returnElement ? Roo.get(newNode, true) : newNode;
5423         },
5424     
5425         /**
5426          * Creates new Dom element(s) and overwrites the contents of el with them
5427          * @param {String/HTMLElement/Element} el The context element
5428          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5429          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5430          * @return {HTMLElement/Roo.Element} The new node
5431          */
5432         overwrite : function(el, o, returnElement)
5433         {
5434             el = Roo.getDom(el);
5435             if (o.ns) {
5436               
5437                 while (el.childNodes.length) {
5438                     el.removeChild(el.firstChild);
5439                 }
5440                 createDom(o, el);
5441             } else {
5442                 el.innerHTML = createHtml(o);   
5443             }
5444             
5445             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5446         },
5447     
5448         /**
5449          * Creates a new Roo.DomHelper.Template from the Dom object spec
5450          * @param {Object} o The Dom object spec (and children)
5451          * @return {Roo.DomHelper.Template} The new template
5452          */
5453         createTemplate : function(o){
5454             var html = createHtml(o);
5455             return new Roo.Template(html);
5456         },
5457          /**
5458          * Updates the first element with the spec from the o (replacing if necessary)
5459          * This iterates through the children, and updates attributes / children etc..
5460          * @param {String/HTMLElement/Element} el The context element
5461          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5462          */
5463         
5464         update : function(el, o)
5465         {
5466             updateNode(Roo.getDom(el), createDom(o));
5467             
5468         }
5469         
5470         
5471     };
5472 }();
5473 /*
5474  * Based on:
5475  * Ext JS Library 1.1.1
5476  * Copyright(c) 2006-2007, Ext JS, LLC.
5477  *
5478  * Originally Released Under LGPL - original licence link has changed is not relivant.
5479  *
5480  * Fork - LGPL
5481  * <script type="text/javascript">
5482  */
5483  
5484 /**
5485 * @class Roo.Template
5486 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5487 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5488 * Usage:
5489 <pre><code>
5490 var t = new Roo.Template({
5491     html :  '&lt;div name="{id}"&gt;' + 
5492         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5493         '&lt;/div&gt;',
5494     myformat: function (value, allValues) {
5495         return 'XX' + value;
5496     }
5497 });
5498 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5499 </code></pre>
5500 * For more information see this blog post with examples:
5501 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5502      - Create Elements using DOM, HTML fragments and Templates</a>. 
5503 * @constructor
5504 * @param {Object} cfg - Configuration object.
5505 */
5506 Roo.Template = function(cfg){
5507     // BC!
5508     if(cfg instanceof Array){
5509         cfg = cfg.join("");
5510     }else if(arguments.length > 1){
5511         cfg = Array.prototype.join.call(arguments, "");
5512     }
5513     
5514     
5515     if (typeof(cfg) == 'object') {
5516         Roo.apply(this,cfg)
5517     } else {
5518         // bc
5519         this.html = cfg;
5520     }
5521     if (this.url) {
5522         this.load();
5523     }
5524     
5525 };
5526 Roo.Template.prototype = {
5527     
5528     /**
5529      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5530      */
5531     onLoad : false,
5532     
5533     
5534     /**
5535      * @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..
5536      *                    it should be fixed so that template is observable...
5537      */
5538     url : false,
5539     /**
5540      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5541      */
5542     html : '',
5543     
5544     
5545     compiled : false,
5546     loaded : false,
5547     /**
5548      * Returns an HTML fragment of this template with the specified values applied.
5549      * @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'})
5550      * @return {String} The HTML fragment
5551      */
5552     
5553    
5554     
5555     applyTemplate : function(values){
5556         //Roo.log(["applyTemplate", values]);
5557         try {
5558            
5559             if(this.compiled){
5560                 return this.compiled(values);
5561             }
5562             var useF = this.disableFormats !== true;
5563             var fm = Roo.util.Format, tpl = this;
5564             var fn = function(m, name, format, args){
5565                 if(format && useF){
5566                     if(format.substr(0, 5) == "this."){
5567                         return tpl.call(format.substr(5), values[name], values);
5568                     }else{
5569                         if(args){
5570                             // quoted values are required for strings in compiled templates, 
5571                             // but for non compiled we need to strip them
5572                             // quoted reversed for jsmin
5573                             var re = /^\s*['"](.*)["']\s*$/;
5574                             args = args.split(',');
5575                             for(var i = 0, len = args.length; i < len; i++){
5576                                 args[i] = args[i].replace(re, "$1");
5577                             }
5578                             args = [values[name]].concat(args);
5579                         }else{
5580                             args = [values[name]];
5581                         }
5582                         return fm[format].apply(fm, args);
5583                     }
5584                 }else{
5585                     return values[name] !== undefined ? values[name] : "";
5586                 }
5587             };
5588             return this.html.replace(this.re, fn);
5589         } catch (e) {
5590             Roo.log(e);
5591             throw e;
5592         }
5593          
5594     },
5595     
5596     loading : false,
5597       
5598     load : function ()
5599     {
5600          
5601         if (this.loading) {
5602             return;
5603         }
5604         var _t = this;
5605         
5606         this.loading = true;
5607         this.compiled = false;
5608         
5609         var cx = new Roo.data.Connection();
5610         cx.request({
5611             url : this.url,
5612             method : 'GET',
5613             success : function (response) {
5614                 _t.loading = false;
5615                 _t.url = false;
5616                 
5617                 _t.set(response.responseText,true);
5618                 _t.loaded = true;
5619                 if (_t.onLoad) {
5620                     _t.onLoad();
5621                 }
5622              },
5623             failure : function(response) {
5624                 Roo.log("Template failed to load from " + _t.url);
5625                 _t.loading = false;
5626             }
5627         });
5628     },
5629
5630     /**
5631      * Sets the HTML used as the template and optionally compiles it.
5632      * @param {String} html
5633      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5634      * @return {Roo.Template} this
5635      */
5636     set : function(html, compile){
5637         this.html = html;
5638         this.compiled = false;
5639         if(compile){
5640             this.compile();
5641         }
5642         return this;
5643     },
5644     
5645     /**
5646      * True to disable format functions (defaults to false)
5647      * @type Boolean
5648      */
5649     disableFormats : false,
5650     
5651     /**
5652     * The regular expression used to match template variables 
5653     * @type RegExp
5654     * @property 
5655     */
5656     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5657     
5658     /**
5659      * Compiles the template into an internal function, eliminating the RegEx overhead.
5660      * @return {Roo.Template} this
5661      */
5662     compile : function(){
5663         var fm = Roo.util.Format;
5664         var useF = this.disableFormats !== true;
5665         var sep = Roo.isGecko ? "+" : ",";
5666         var fn = function(m, name, format, args){
5667             if(format && useF){
5668                 args = args ? ',' + args : "";
5669                 if(format.substr(0, 5) != "this."){
5670                     format = "fm." + format + '(';
5671                 }else{
5672                     format = 'this.call("'+ format.substr(5) + '", ';
5673                     args = ", values";
5674                 }
5675             }else{
5676                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5677             }
5678             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5679         };
5680         var body;
5681         // branched to use + in gecko and [].join() in others
5682         if(Roo.isGecko){
5683             body = "this.compiled = function(values){ return '" +
5684                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5685                     "';};";
5686         }else{
5687             body = ["this.compiled = function(values){ return ['"];
5688             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5689             body.push("'].join('');};");
5690             body = body.join('');
5691         }
5692         /**
5693          * eval:var:values
5694          * eval:var:fm
5695          */
5696         eval(body);
5697         return this;
5698     },
5699     
5700     // private function used to call members
5701     call : function(fnName, value, allValues){
5702         return this[fnName](value, allValues);
5703     },
5704     
5705     /**
5706      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5707      * @param {String/HTMLElement/Roo.Element} el The context element
5708      * @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'})
5709      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5710      * @return {HTMLElement/Roo.Element} The new node or Element
5711      */
5712     insertFirst: function(el, values, returnElement){
5713         return this.doInsert('afterBegin', el, values, returnElement);
5714     },
5715
5716     /**
5717      * Applies the supplied values to the template and inserts the new node(s) before el.
5718      * @param {String/HTMLElement/Roo.Element} el The context element
5719      * @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'})
5720      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5721      * @return {HTMLElement/Roo.Element} The new node or Element
5722      */
5723     insertBefore: function(el, values, returnElement){
5724         return this.doInsert('beforeBegin', el, values, returnElement);
5725     },
5726
5727     /**
5728      * Applies the supplied values to the template and inserts the new node(s) after el.
5729      * @param {String/HTMLElement/Roo.Element} el The context element
5730      * @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'})
5731      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5732      * @return {HTMLElement/Roo.Element} The new node or Element
5733      */
5734     insertAfter : function(el, values, returnElement){
5735         return this.doInsert('afterEnd', el, values, returnElement);
5736     },
5737     
5738     /**
5739      * Applies the supplied values to the template and appends the new node(s) to el.
5740      * @param {String/HTMLElement/Roo.Element} el The context element
5741      * @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'})
5742      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5743      * @return {HTMLElement/Roo.Element} The new node or Element
5744      */
5745     append : function(el, values, returnElement){
5746         return this.doInsert('beforeEnd', el, values, returnElement);
5747     },
5748
5749     doInsert : function(where, el, values, returnEl){
5750         el = Roo.getDom(el);
5751         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5752         return returnEl ? Roo.get(newNode, true) : newNode;
5753     },
5754
5755     /**
5756      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5757      * @param {String/HTMLElement/Roo.Element} el The context element
5758      * @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'})
5759      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5760      * @return {HTMLElement/Roo.Element} The new node or Element
5761      */
5762     overwrite : function(el, values, returnElement){
5763         el = Roo.getDom(el);
5764         el.innerHTML = this.applyTemplate(values);
5765         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5766     }
5767 };
5768 /**
5769  * Alias for {@link #applyTemplate}
5770  * @method
5771  */
5772 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5773
5774 // backwards compat
5775 Roo.DomHelper.Template = Roo.Template;
5776
5777 /**
5778  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5779  * @param {String/HTMLElement} el A DOM element or its id
5780  * @returns {Roo.Template} The created template
5781  * @static
5782  */
5783 Roo.Template.from = function(el){
5784     el = Roo.getDom(el);
5785     return new Roo.Template(el.value || el.innerHTML);
5786 };/*
5787  * Based on:
5788  * Ext JS Library 1.1.1
5789  * Copyright(c) 2006-2007, Ext JS, LLC.
5790  *
5791  * Originally Released Under LGPL - original licence link has changed is not relivant.
5792  *
5793  * Fork - LGPL
5794  * <script type="text/javascript">
5795  */
5796  
5797
5798 /*
5799  * This is code is also distributed under MIT license for use
5800  * with jQuery and prototype JavaScript libraries.
5801  */
5802 /**
5803  * @class Roo.DomQuery
5804 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).
5805 <p>
5806 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>
5807
5808 <p>
5809 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.
5810 </p>
5811 <h4>Element Selectors:</h4>
5812 <ul class="list">
5813     <li> <b>*</b> any element</li>
5814     <li> <b>E</b> an element with the tag E</li>
5815     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5816     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5817     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5818     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5819 </ul>
5820 <h4>Attribute Selectors:</h4>
5821 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5822 <ul class="list">
5823     <li> <b>E[foo]</b> has an attribute "foo"</li>
5824     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5825     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5826     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5827     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5828     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5829     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5830 </ul>
5831 <h4>Pseudo Classes:</h4>
5832 <ul class="list">
5833     <li> <b>E:first-child</b> E is the first child of its parent</li>
5834     <li> <b>E:last-child</b> E is the last child of its parent</li>
5835     <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>
5836     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5837     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5838     <li> <b>E:only-child</b> E is the only child of its parent</li>
5839     <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>
5840     <li> <b>E:first</b> the first E in the resultset</li>
5841     <li> <b>E:last</b> the last E in the resultset</li>
5842     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5843     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5844     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5845     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5846     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5847     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5848     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5849     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5850     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5851 </ul>
5852 <h4>CSS Value Selectors:</h4>
5853 <ul class="list">
5854     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5855     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5856     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5857     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5858     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5859     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5860 </ul>
5861  * @static
5862  */
5863 Roo.DomQuery = function(){
5864     var cache = {}, simpleCache = {}, valueCache = {};
5865     var nonSpace = /\S/;
5866     var trimRe = /^\s+|\s+$/g;
5867     var tplRe = /\{(\d+)\}/g;
5868     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5869     var tagTokenRe = /^(#)?([\w-\*]+)/;
5870     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5871
5872     function child(p, index){
5873         var i = 0;
5874         var n = p.firstChild;
5875         while(n){
5876             if(n.nodeType == 1){
5877                if(++i == index){
5878                    return n;
5879                }
5880             }
5881             n = n.nextSibling;
5882         }
5883         return null;
5884     };
5885
5886     function next(n){
5887         while((n = n.nextSibling) && n.nodeType != 1);
5888         return n;
5889     };
5890
5891     function prev(n){
5892         while((n = n.previousSibling) && n.nodeType != 1);
5893         return n;
5894     };
5895
5896     function children(d){
5897         var n = d.firstChild, ni = -1;
5898             while(n){
5899                 var nx = n.nextSibling;
5900                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5901                     d.removeChild(n);
5902                 }else{
5903                     n.nodeIndex = ++ni;
5904                 }
5905                 n = nx;
5906             }
5907             return this;
5908         };
5909
5910     function byClassName(c, a, v){
5911         if(!v){
5912             return c;
5913         }
5914         var r = [], ri = -1, cn;
5915         for(var i = 0, ci; ci = c[i]; i++){
5916             
5917             
5918             if((' '+
5919                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5920                  +' ').indexOf(v) != -1){
5921                 r[++ri] = ci;
5922             }
5923         }
5924         return r;
5925     };
5926
5927     function attrValue(n, attr){
5928         if(!n.tagName && typeof n.length != "undefined"){
5929             n = n[0];
5930         }
5931         if(!n){
5932             return null;
5933         }
5934         if(attr == "for"){
5935             return n.htmlFor;
5936         }
5937         if(attr == "class" || attr == "className"){
5938             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5939         }
5940         return n.getAttribute(attr) || n[attr];
5941
5942     };
5943
5944     function getNodes(ns, mode, tagName){
5945         var result = [], ri = -1, cs;
5946         if(!ns){
5947             return result;
5948         }
5949         tagName = tagName || "*";
5950         if(typeof ns.getElementsByTagName != "undefined"){
5951             ns = [ns];
5952         }
5953         if(!mode){
5954             for(var i = 0, ni; ni = ns[i]; i++){
5955                 cs = ni.getElementsByTagName(tagName);
5956                 for(var j = 0, ci; ci = cs[j]; j++){
5957                     result[++ri] = ci;
5958                 }
5959             }
5960         }else if(mode == "/" || mode == ">"){
5961             var utag = tagName.toUpperCase();
5962             for(var i = 0, ni, cn; ni = ns[i]; i++){
5963                 cn = ni.children || ni.childNodes;
5964                 for(var j = 0, cj; cj = cn[j]; j++){
5965                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5966                         result[++ri] = cj;
5967                     }
5968                 }
5969             }
5970         }else if(mode == "+"){
5971             var utag = tagName.toUpperCase();
5972             for(var i = 0, n; n = ns[i]; i++){
5973                 while((n = n.nextSibling) && n.nodeType != 1);
5974                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5975                     result[++ri] = n;
5976                 }
5977             }
5978         }else if(mode == "~"){
5979             for(var i = 0, n; n = ns[i]; i++){
5980                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5981                 if(n){
5982                     result[++ri] = n;
5983                 }
5984             }
5985         }
5986         return result;
5987     };
5988
5989     function concat(a, b){
5990         if(b.slice){
5991             return a.concat(b);
5992         }
5993         for(var i = 0, l = b.length; i < l; i++){
5994             a[a.length] = b[i];
5995         }
5996         return a;
5997     }
5998
5999     function byTag(cs, tagName){
6000         if(cs.tagName || cs == document){
6001             cs = [cs];
6002         }
6003         if(!tagName){
6004             return cs;
6005         }
6006         var r = [], ri = -1;
6007         tagName = tagName.toLowerCase();
6008         for(var i = 0, ci; ci = cs[i]; i++){
6009             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6010                 r[++ri] = ci;
6011             }
6012         }
6013         return r;
6014     };
6015
6016     function byId(cs, attr, id){
6017         if(cs.tagName || cs == document){
6018             cs = [cs];
6019         }
6020         if(!id){
6021             return cs;
6022         }
6023         var r = [], ri = -1;
6024         for(var i = 0,ci; ci = cs[i]; i++){
6025             if(ci && ci.id == id){
6026                 r[++ri] = ci;
6027                 return r;
6028             }
6029         }
6030         return r;
6031     };
6032
6033     function byAttribute(cs, attr, value, op, custom){
6034         var r = [], ri = -1, st = custom=="{";
6035         var f = Roo.DomQuery.operators[op];
6036         for(var i = 0, ci; ci = cs[i]; i++){
6037             var a;
6038             if(st){
6039                 a = Roo.DomQuery.getStyle(ci, attr);
6040             }
6041             else if(attr == "class" || attr == "className"){
6042                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6043             }else if(attr == "for"){
6044                 a = ci.htmlFor;
6045             }else if(attr == "href"){
6046                 a = ci.getAttribute("href", 2);
6047             }else{
6048                 a = ci.getAttribute(attr);
6049             }
6050             if((f && f(a, value)) || (!f && a)){
6051                 r[++ri] = ci;
6052             }
6053         }
6054         return r;
6055     };
6056
6057     function byPseudo(cs, name, value){
6058         return Roo.DomQuery.pseudos[name](cs, value);
6059     };
6060
6061     // This is for IE MSXML which does not support expandos.
6062     // IE runs the same speed using setAttribute, however FF slows way down
6063     // and Safari completely fails so they need to continue to use expandos.
6064     var isIE = window.ActiveXObject ? true : false;
6065
6066     // this eval is stop the compressor from
6067     // renaming the variable to something shorter
6068     
6069     /** eval:var:batch */
6070     var batch = 30803; 
6071
6072     var key = 30803;
6073
6074     function nodupIEXml(cs){
6075         var d = ++key;
6076         cs[0].setAttribute("_nodup", d);
6077         var r = [cs[0]];
6078         for(var i = 1, len = cs.length; i < len; i++){
6079             var c = cs[i];
6080             if(!c.getAttribute("_nodup") != d){
6081                 c.setAttribute("_nodup", d);
6082                 r[r.length] = c;
6083             }
6084         }
6085         for(var i = 0, len = cs.length; i < len; i++){
6086             cs[i].removeAttribute("_nodup");
6087         }
6088         return r;
6089     }
6090
6091     function nodup(cs){
6092         if(!cs){
6093             return [];
6094         }
6095         var len = cs.length, c, i, r = cs, cj, ri = -1;
6096         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6097             return cs;
6098         }
6099         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6100             return nodupIEXml(cs);
6101         }
6102         var d = ++key;
6103         cs[0]._nodup = d;
6104         for(i = 1; c = cs[i]; i++){
6105             if(c._nodup != d){
6106                 c._nodup = d;
6107             }else{
6108                 r = [];
6109                 for(var j = 0; j < i; j++){
6110                     r[++ri] = cs[j];
6111                 }
6112                 for(j = i+1; cj = cs[j]; j++){
6113                     if(cj._nodup != d){
6114                         cj._nodup = d;
6115                         r[++ri] = cj;
6116                     }
6117                 }
6118                 return r;
6119             }
6120         }
6121         return r;
6122     }
6123
6124     function quickDiffIEXml(c1, c2){
6125         var d = ++key;
6126         for(var i = 0, len = c1.length; i < len; i++){
6127             c1[i].setAttribute("_qdiff", d);
6128         }
6129         var r = [];
6130         for(var i = 0, len = c2.length; i < len; i++){
6131             if(c2[i].getAttribute("_qdiff") != d){
6132                 r[r.length] = c2[i];
6133             }
6134         }
6135         for(var i = 0, len = c1.length; i < len; i++){
6136            c1[i].removeAttribute("_qdiff");
6137         }
6138         return r;
6139     }
6140
6141     function quickDiff(c1, c2){
6142         var len1 = c1.length;
6143         if(!len1){
6144             return c2;
6145         }
6146         if(isIE && c1[0].selectSingleNode){
6147             return quickDiffIEXml(c1, c2);
6148         }
6149         var d = ++key;
6150         for(var i = 0; i < len1; i++){
6151             c1[i]._qdiff = d;
6152         }
6153         var r = [];
6154         for(var i = 0, len = c2.length; i < len; i++){
6155             if(c2[i]._qdiff != d){
6156                 r[r.length] = c2[i];
6157             }
6158         }
6159         return r;
6160     }
6161
6162     function quickId(ns, mode, root, id){
6163         if(ns == root){
6164            var d = root.ownerDocument || root;
6165            return d.getElementById(id);
6166         }
6167         ns = getNodes(ns, mode, "*");
6168         return byId(ns, null, id);
6169     }
6170
6171     return {
6172         getStyle : function(el, name){
6173             return Roo.fly(el).getStyle(name);
6174         },
6175         /**
6176          * Compiles a selector/xpath query into a reusable function. The returned function
6177          * takes one parameter "root" (optional), which is the context node from where the query should start.
6178          * @param {String} selector The selector/xpath query
6179          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6180          * @return {Function}
6181          */
6182         compile : function(path, type){
6183             type = type || "select";
6184             
6185             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6186             var q = path, mode, lq;
6187             var tk = Roo.DomQuery.matchers;
6188             var tklen = tk.length;
6189             var mm;
6190
6191             // accept leading mode switch
6192             var lmode = q.match(modeRe);
6193             if(lmode && lmode[1]){
6194                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6195                 q = q.replace(lmode[1], "");
6196             }
6197             // strip leading slashes
6198             while(path.substr(0, 1)=="/"){
6199                 path = path.substr(1);
6200             }
6201
6202             while(q && lq != q){
6203                 lq = q;
6204                 var tm = q.match(tagTokenRe);
6205                 if(type == "select"){
6206                     if(tm){
6207                         if(tm[1] == "#"){
6208                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6209                         }else{
6210                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6211                         }
6212                         q = q.replace(tm[0], "");
6213                     }else if(q.substr(0, 1) != '@'){
6214                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6215                     }
6216                 }else{
6217                     if(tm){
6218                         if(tm[1] == "#"){
6219                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6220                         }else{
6221                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6222                         }
6223                         q = q.replace(tm[0], "");
6224                     }
6225                 }
6226                 while(!(mm = q.match(modeRe))){
6227                     var matched = false;
6228                     for(var j = 0; j < tklen; j++){
6229                         var t = tk[j];
6230                         var m = q.match(t.re);
6231                         if(m){
6232                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6233                                                     return m[i];
6234                                                 });
6235                             q = q.replace(m[0], "");
6236                             matched = true;
6237                             break;
6238                         }
6239                     }
6240                     // prevent infinite loop on bad selector
6241                     if(!matched){
6242                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6243                     }
6244                 }
6245                 if(mm[1]){
6246                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6247                     q = q.replace(mm[1], "");
6248                 }
6249             }
6250             fn[fn.length] = "return nodup(n);\n}";
6251             
6252              /** 
6253               * list of variables that need from compression as they are used by eval.
6254              *  eval:var:batch 
6255              *  eval:var:nodup
6256              *  eval:var:byTag
6257              *  eval:var:ById
6258              *  eval:var:getNodes
6259              *  eval:var:quickId
6260              *  eval:var:mode
6261              *  eval:var:root
6262              *  eval:var:n
6263              *  eval:var:byClassName
6264              *  eval:var:byPseudo
6265              *  eval:var:byAttribute
6266              *  eval:var:attrValue
6267              * 
6268              **/ 
6269             eval(fn.join(""));
6270             return f;
6271         },
6272
6273         /**
6274          * Selects a group of elements.
6275          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6276          * @param {Node} root (optional) The start of the query (defaults to document).
6277          * @return {Array}
6278          */
6279         select : function(path, root, type){
6280             if(!root || root == document){
6281                 root = document;
6282             }
6283             if(typeof root == "string"){
6284                 root = document.getElementById(root);
6285             }
6286             var paths = path.split(",");
6287             var results = [];
6288             for(var i = 0, len = paths.length; i < len; i++){
6289                 var p = paths[i].replace(trimRe, "");
6290                 if(!cache[p]){
6291                     cache[p] = Roo.DomQuery.compile(p);
6292                     if(!cache[p]){
6293                         throw p + " is not a valid selector";
6294                     }
6295                 }
6296                 var result = cache[p](root);
6297                 if(result && result != document){
6298                     results = results.concat(result);
6299                 }
6300             }
6301             if(paths.length > 1){
6302                 return nodup(results);
6303             }
6304             return results;
6305         },
6306
6307         /**
6308          * Selects a single element.
6309          * @param {String} selector The selector/xpath query
6310          * @param {Node} root (optional) The start of the query (defaults to document).
6311          * @return {Element}
6312          */
6313         selectNode : function(path, root){
6314             return Roo.DomQuery.select(path, root)[0];
6315         },
6316
6317         /**
6318          * Selects the value of a node, optionally replacing null with the defaultValue.
6319          * @param {String} selector The selector/xpath query
6320          * @param {Node} root (optional) The start of the query (defaults to document).
6321          * @param {String} defaultValue
6322          */
6323         selectValue : function(path, root, defaultValue){
6324             path = path.replace(trimRe, "");
6325             if(!valueCache[path]){
6326                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6327             }
6328             var n = valueCache[path](root);
6329             n = n[0] ? n[0] : n;
6330             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6331             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6332         },
6333
6334         /**
6335          * Selects the value of a node, parsing integers and floats.
6336          * @param {String} selector The selector/xpath query
6337          * @param {Node} root (optional) The start of the query (defaults to document).
6338          * @param {Number} defaultValue
6339          * @return {Number}
6340          */
6341         selectNumber : function(path, root, defaultValue){
6342             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6343             return parseFloat(v);
6344         },
6345
6346         /**
6347          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6348          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6349          * @param {String} selector The simple selector to test
6350          * @return {Boolean}
6351          */
6352         is : function(el, ss){
6353             if(typeof el == "string"){
6354                 el = document.getElementById(el);
6355             }
6356             var isArray = (el instanceof Array);
6357             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6358             return isArray ? (result.length == el.length) : (result.length > 0);
6359         },
6360
6361         /**
6362          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6363          * @param {Array} el An array of elements to filter
6364          * @param {String} selector The simple selector to test
6365          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6366          * the selector instead of the ones that match
6367          * @return {Array}
6368          */
6369         filter : function(els, ss, nonMatches){
6370             ss = ss.replace(trimRe, "");
6371             if(!simpleCache[ss]){
6372                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6373             }
6374             var result = simpleCache[ss](els);
6375             return nonMatches ? quickDiff(result, els) : result;
6376         },
6377
6378         /**
6379          * Collection of matching regular expressions and code snippets.
6380          */
6381         matchers : [{
6382                 re: /^\.([\w-]+)/,
6383                 select: 'n = byClassName(n, null, " {1} ");'
6384             }, {
6385                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6386                 select: 'n = byPseudo(n, "{1}", "{2}");'
6387             },{
6388                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6389                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6390             }, {
6391                 re: /^#([\w-]+)/,
6392                 select: 'n = byId(n, null, "{1}");'
6393             },{
6394                 re: /^@([\w-]+)/,
6395                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6396             }
6397         ],
6398
6399         /**
6400          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6401          * 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;.
6402          */
6403         operators : {
6404             "=" : function(a, v){
6405                 return a == v;
6406             },
6407             "!=" : function(a, v){
6408                 return a != v;
6409             },
6410             "^=" : function(a, v){
6411                 return a && a.substr(0, v.length) == v;
6412             },
6413             "$=" : function(a, v){
6414                 return a && a.substr(a.length-v.length) == v;
6415             },
6416             "*=" : function(a, v){
6417                 return a && a.indexOf(v) !== -1;
6418             },
6419             "%=" : function(a, v){
6420                 return (a % v) == 0;
6421             },
6422             "|=" : function(a, v){
6423                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6424             },
6425             "~=" : function(a, v){
6426                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6427             }
6428         },
6429
6430         /**
6431          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6432          * and the argument (if any) supplied in the selector.
6433          */
6434         pseudos : {
6435             "first-child" : function(c){
6436                 var r = [], ri = -1, n;
6437                 for(var i = 0, ci; ci = n = c[i]; i++){
6438                     while((n = n.previousSibling) && n.nodeType != 1);
6439                     if(!n){
6440                         r[++ri] = ci;
6441                     }
6442                 }
6443                 return r;
6444             },
6445
6446             "last-child" : function(c){
6447                 var r = [], ri = -1, n;
6448                 for(var i = 0, ci; ci = n = c[i]; i++){
6449                     while((n = n.nextSibling) && n.nodeType != 1);
6450                     if(!n){
6451                         r[++ri] = ci;
6452                     }
6453                 }
6454                 return r;
6455             },
6456
6457             "nth-child" : function(c, a) {
6458                 var r = [], ri = -1;
6459                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6460                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6461                 for(var i = 0, n; n = c[i]; i++){
6462                     var pn = n.parentNode;
6463                     if (batch != pn._batch) {
6464                         var j = 0;
6465                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6466                             if(cn.nodeType == 1){
6467                                cn.nodeIndex = ++j;
6468                             }
6469                         }
6470                         pn._batch = batch;
6471                     }
6472                     if (f == 1) {
6473                         if (l == 0 || n.nodeIndex == l){
6474                             r[++ri] = n;
6475                         }
6476                     } else if ((n.nodeIndex + l) % f == 0){
6477                         r[++ri] = n;
6478                     }
6479                 }
6480
6481                 return r;
6482             },
6483
6484             "only-child" : function(c){
6485                 var r = [], ri = -1;;
6486                 for(var i = 0, ci; ci = c[i]; i++){
6487                     if(!prev(ci) && !next(ci)){
6488                         r[++ri] = ci;
6489                     }
6490                 }
6491                 return r;
6492             },
6493
6494             "empty" : function(c){
6495                 var r = [], ri = -1;
6496                 for(var i = 0, ci; ci = c[i]; i++){
6497                     var cns = ci.childNodes, j = 0, cn, empty = true;
6498                     while(cn = cns[j]){
6499                         ++j;
6500                         if(cn.nodeType == 1 || cn.nodeType == 3){
6501                             empty = false;
6502                             break;
6503                         }
6504                     }
6505                     if(empty){
6506                         r[++ri] = ci;
6507                     }
6508                 }
6509                 return r;
6510             },
6511
6512             "contains" : function(c, v){
6513                 var r = [], ri = -1;
6514                 for(var i = 0, ci; ci = c[i]; i++){
6515                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6516                         r[++ri] = ci;
6517                     }
6518                 }
6519                 return r;
6520             },
6521
6522             "nodeValue" : function(c, v){
6523                 var r = [], ri = -1;
6524                 for(var i = 0, ci; ci = c[i]; i++){
6525                     if(ci.firstChild && ci.firstChild.nodeValue == v){
6526                         r[++ri] = ci;
6527                     }
6528                 }
6529                 return r;
6530             },
6531
6532             "checked" : function(c){
6533                 var r = [], ri = -1;
6534                 for(var i = 0, ci; ci = c[i]; i++){
6535                     if(ci.checked == true){
6536                         r[++ri] = ci;
6537                     }
6538                 }
6539                 return r;
6540             },
6541
6542             "not" : function(c, ss){
6543                 return Roo.DomQuery.filter(c, ss, true);
6544             },
6545
6546             "odd" : function(c){
6547                 return this["nth-child"](c, "odd");
6548             },
6549
6550             "even" : function(c){
6551                 return this["nth-child"](c, "even");
6552             },
6553
6554             "nth" : function(c, a){
6555                 return c[a-1] || [];
6556             },
6557
6558             "first" : function(c){
6559                 return c[0] || [];
6560             },
6561
6562             "last" : function(c){
6563                 return c[c.length-1] || [];
6564             },
6565
6566             "has" : function(c, ss){
6567                 var s = Roo.DomQuery.select;
6568                 var r = [], ri = -1;
6569                 for(var i = 0, ci; ci = c[i]; i++){
6570                     if(s(ss, ci).length > 0){
6571                         r[++ri] = ci;
6572                     }
6573                 }
6574                 return r;
6575             },
6576
6577             "next" : function(c, ss){
6578                 var is = Roo.DomQuery.is;
6579                 var r = [], ri = -1;
6580                 for(var i = 0, ci; ci = c[i]; i++){
6581                     var n = next(ci);
6582                     if(n && is(n, ss)){
6583                         r[++ri] = ci;
6584                     }
6585                 }
6586                 return r;
6587             },
6588
6589             "prev" : function(c, ss){
6590                 var is = Roo.DomQuery.is;
6591                 var r = [], ri = -1;
6592                 for(var i = 0, ci; ci = c[i]; i++){
6593                     var n = prev(ci);
6594                     if(n && is(n, ss)){
6595                         r[++ri] = ci;
6596                     }
6597                 }
6598                 return r;
6599             }
6600         }
6601     };
6602 }();
6603
6604 /**
6605  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6606  * @param {String} path The selector/xpath query
6607  * @param {Node} root (optional) The start of the query (defaults to document).
6608  * @return {Array}
6609  * @member Roo
6610  * @method query
6611  */
6612 Roo.query = Roo.DomQuery.select;
6613 /*
6614  * Based on:
6615  * Ext JS Library 1.1.1
6616  * Copyright(c) 2006-2007, Ext JS, LLC.
6617  *
6618  * Originally Released Under LGPL - original licence link has changed is not relivant.
6619  *
6620  * Fork - LGPL
6621  * <script type="text/javascript">
6622  */
6623
6624 /**
6625  * @class Roo.util.Observable
6626  * Base class that provides a common interface for publishing events. Subclasses are expected to
6627  * to have a property "events" with all the events defined.<br>
6628  * For example:
6629  * <pre><code>
6630  Employee = function(name){
6631     this.name = name;
6632     this.addEvents({
6633         "fired" : true,
6634         "quit" : true
6635     });
6636  }
6637  Roo.extend(Employee, Roo.util.Observable);
6638 </code></pre>
6639  * @param {Object} config properties to use (incuding events / listeners)
6640  */
6641
6642 Roo.util.Observable = function(cfg){
6643     
6644     cfg = cfg|| {};
6645     this.addEvents(cfg.events || {});
6646     if (cfg.events) {
6647         delete cfg.events; // make sure
6648     }
6649      
6650     Roo.apply(this, cfg);
6651     
6652     if(this.listeners){
6653         this.on(this.listeners);
6654         delete this.listeners;
6655     }
6656 };
6657 Roo.util.Observable.prototype = {
6658     /** 
6659  * @cfg {Object} listeners  list of events and functions to call for this object, 
6660  * For example :
6661  * <pre><code>
6662     listeners :  { 
6663        'click' : function(e) {
6664            ..... 
6665         } ,
6666         .... 
6667     } 
6668   </code></pre>
6669  */
6670     
6671     
6672     /**
6673      * Fires the specified event with the passed parameters (minus the event name).
6674      * @param {String} eventName
6675      * @param {Object...} args Variable number of parameters are passed to handlers
6676      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6677      */
6678     fireEvent : function(){
6679         var ce = this.events[arguments[0].toLowerCase()];
6680         if(typeof ce == "object"){
6681             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6682         }else{
6683             return true;
6684         }
6685     },
6686
6687     // private
6688     filterOptRe : /^(?:scope|delay|buffer|single)$/,
6689
6690     /**
6691      * Appends an event handler to this component
6692      * @param {String}   eventName The type of event to listen for
6693      * @param {Function} handler The method the event invokes
6694      * @param {Object}   scope (optional) The scope in which to execute the handler
6695      * function. The handler function's "this" context.
6696      * @param {Object}   options (optional) An object containing handler configuration
6697      * properties. This may contain any of the following properties:<ul>
6698      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6699      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6700      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6701      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6702      * by the specified number of milliseconds. If the event fires again within that time, the original
6703      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6704      * </ul><br>
6705      * <p>
6706      * <b>Combining Options</b><br>
6707      * Using the options argument, it is possible to combine different types of listeners:<br>
6708      * <br>
6709      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6710                 <pre><code>
6711                 el.on('click', this.onClick, this, {
6712                         single: true,
6713                 delay: 100,
6714                 forumId: 4
6715                 });
6716                 </code></pre>
6717      * <p>
6718      * <b>Attaching multiple handlers in 1 call</b><br>
6719      * The method also allows for a single argument to be passed which is a config object containing properties
6720      * which specify multiple handlers.
6721      * <pre><code>
6722                 el.on({
6723                         'click': {
6724                         fn: this.onClick,
6725                         scope: this,
6726                         delay: 100
6727                 }, 
6728                 'mouseover': {
6729                         fn: this.onMouseOver,
6730                         scope: this
6731                 },
6732                 'mouseout': {
6733                         fn: this.onMouseOut,
6734                         scope: this
6735                 }
6736                 });
6737                 </code></pre>
6738      * <p>
6739      * Or a shorthand syntax which passes the same scope object to all handlers:
6740         <pre><code>
6741                 el.on({
6742                         'click': this.onClick,
6743                 'mouseover': this.onMouseOver,
6744                 'mouseout': this.onMouseOut,
6745                 scope: this
6746                 });
6747                 </code></pre>
6748      */
6749     addListener : function(eventName, fn, scope, o){
6750         if(typeof eventName == "object"){
6751             o = eventName;
6752             for(var e in o){
6753                 if(this.filterOptRe.test(e)){
6754                     continue;
6755                 }
6756                 if(typeof o[e] == "function"){
6757                     // shared options
6758                     this.addListener(e, o[e], o.scope,  o);
6759                 }else{
6760                     // individual options
6761                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
6762                 }
6763             }
6764             return;
6765         }
6766         o = (!o || typeof o == "boolean") ? {} : o;
6767         eventName = eventName.toLowerCase();
6768         var ce = this.events[eventName] || true;
6769         if(typeof ce == "boolean"){
6770             ce = new Roo.util.Event(this, eventName);
6771             this.events[eventName] = ce;
6772         }
6773         ce.addListener(fn, scope, o);
6774     },
6775
6776     /**
6777      * Removes a listener
6778      * @param {String}   eventName     The type of event to listen for
6779      * @param {Function} handler        The handler to remove
6780      * @param {Object}   scope  (optional) The scope (this object) for the handler
6781      */
6782     removeListener : function(eventName, fn, scope){
6783         var ce = this.events[eventName.toLowerCase()];
6784         if(typeof ce == "object"){
6785             ce.removeListener(fn, scope);
6786         }
6787     },
6788
6789     /**
6790      * Removes all listeners for this object
6791      */
6792     purgeListeners : function(){
6793         for(var evt in this.events){
6794             if(typeof this.events[evt] == "object"){
6795                  this.events[evt].clearListeners();
6796             }
6797         }
6798     },
6799
6800     relayEvents : function(o, events){
6801         var createHandler = function(ename){
6802             return function(){
6803                  
6804                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6805             };
6806         };
6807         for(var i = 0, len = events.length; i < len; i++){
6808             var ename = events[i];
6809             if(!this.events[ename]){
6810                 this.events[ename] = true;
6811             };
6812             o.on(ename, createHandler(ename), this);
6813         }
6814     },
6815
6816     /**
6817      * Used to define events on this Observable
6818      * @param {Object} object The object with the events defined
6819      */
6820     addEvents : function(o){
6821         if(!this.events){
6822             this.events = {};
6823         }
6824         Roo.applyIf(this.events, o);
6825     },
6826
6827     /**
6828      * Checks to see if this object has any listeners for a specified event
6829      * @param {String} eventName The name of the event to check for
6830      * @return {Boolean} True if the event is being listened for, else false
6831      */
6832     hasListener : function(eventName){
6833         var e = this.events[eventName];
6834         return typeof e == "object" && e.listeners.length > 0;
6835     }
6836 };
6837 /**
6838  * Appends an event handler to this element (shorthand for addListener)
6839  * @param {String}   eventName     The type of event to listen for
6840  * @param {Function} handler        The method the event invokes
6841  * @param {Object}   scope (optional) The scope in which to execute the handler
6842  * function. The handler function's "this" context.
6843  * @param {Object}   options  (optional)
6844  * @method
6845  */
6846 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6847 /**
6848  * Removes a listener (shorthand for removeListener)
6849  * @param {String}   eventName     The type of event to listen for
6850  * @param {Function} handler        The handler to remove
6851  * @param {Object}   scope  (optional) The scope (this object) for the handler
6852  * @method
6853  */
6854 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6855
6856 /**
6857  * Starts capture on the specified Observable. All events will be passed
6858  * to the supplied function with the event name + standard signature of the event
6859  * <b>before</b> the event is fired. If the supplied function returns false,
6860  * the event will not fire.
6861  * @param {Observable} o The Observable to capture
6862  * @param {Function} fn The function to call
6863  * @param {Object} scope (optional) The scope (this object) for the fn
6864  * @static
6865  */
6866 Roo.util.Observable.capture = function(o, fn, scope){
6867     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6868 };
6869
6870 /**
6871  * Removes <b>all</b> added captures from the Observable.
6872  * @param {Observable} o The Observable to release
6873  * @static
6874  */
6875 Roo.util.Observable.releaseCapture = function(o){
6876     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6877 };
6878
6879 (function(){
6880
6881     var createBuffered = function(h, o, scope){
6882         var task = new Roo.util.DelayedTask();
6883         return function(){
6884             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6885         };
6886     };
6887
6888     var createSingle = function(h, e, fn, scope){
6889         return function(){
6890             e.removeListener(fn, scope);
6891             return h.apply(scope, arguments);
6892         };
6893     };
6894
6895     var createDelayed = function(h, o, scope){
6896         return function(){
6897             var args = Array.prototype.slice.call(arguments, 0);
6898             setTimeout(function(){
6899                 h.apply(scope, args);
6900             }, o.delay || 10);
6901         };
6902     };
6903
6904     Roo.util.Event = function(obj, name){
6905         this.name = name;
6906         this.obj = obj;
6907         this.listeners = [];
6908     };
6909
6910     Roo.util.Event.prototype = {
6911         addListener : function(fn, scope, options){
6912             var o = options || {};
6913             scope = scope || this.obj;
6914             if(!this.isListening(fn, scope)){
6915                 var l = {fn: fn, scope: scope, options: o};
6916                 var h = fn;
6917                 if(o.delay){
6918                     h = createDelayed(h, o, scope);
6919                 }
6920                 if(o.single){
6921                     h = createSingle(h, this, fn, scope);
6922                 }
6923                 if(o.buffer){
6924                     h = createBuffered(h, o, scope);
6925                 }
6926                 l.fireFn = h;
6927                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6928                     this.listeners.push(l);
6929                 }else{
6930                     this.listeners = this.listeners.slice(0);
6931                     this.listeners.push(l);
6932                 }
6933             }
6934         },
6935
6936         findListener : function(fn, scope){
6937             scope = scope || this.obj;
6938             var ls = this.listeners;
6939             for(var i = 0, len = ls.length; i < len; i++){
6940                 var l = ls[i];
6941                 if(l.fn == fn && l.scope == scope){
6942                     return i;
6943                 }
6944             }
6945             return -1;
6946         },
6947
6948         isListening : function(fn, scope){
6949             return this.findListener(fn, scope) != -1;
6950         },
6951
6952         removeListener : function(fn, scope){
6953             var index;
6954             if((index = this.findListener(fn, scope)) != -1){
6955                 if(!this.firing){
6956                     this.listeners.splice(index, 1);
6957                 }else{
6958                     this.listeners = this.listeners.slice(0);
6959                     this.listeners.splice(index, 1);
6960                 }
6961                 return true;
6962             }
6963             return false;
6964         },
6965
6966         clearListeners : function(){
6967             this.listeners = [];
6968         },
6969
6970         fire : function(){
6971             var ls = this.listeners, scope, len = ls.length;
6972             if(len > 0){
6973                 this.firing = true;
6974                 var args = Array.prototype.slice.call(arguments, 0);                
6975                 for(var i = 0; i < len; i++){
6976                     var l = ls[i];
6977                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6978                         this.firing = false;
6979                         return false;
6980                     }
6981                 }
6982                 this.firing = false;
6983             }
6984             return true;
6985         }
6986     };
6987 })();/*
6988  * RooJS Library 
6989  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6990  *
6991  * Licence LGPL 
6992  *
6993  */
6994  
6995 /**
6996  * @class Roo.Document
6997  * @extends Roo.util.Observable
6998  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6999  * 
7000  * @param {Object} config the methods and properties of the 'base' class for the application.
7001  * 
7002  *  Generic Page handler - implement this to start your app..
7003  * 
7004  * eg.
7005  *  MyProject = new Roo.Document({
7006         events : {
7007             'load' : true // your events..
7008         },
7009         listeners : {
7010             'ready' : function() {
7011                 // fired on Roo.onReady()
7012             }
7013         }
7014  * 
7015  */
7016 Roo.Document = function(cfg) {
7017      
7018     this.addEvents({ 
7019         'ready' : true
7020     });
7021     Roo.util.Observable.call(this,cfg);
7022     
7023     var _this = this;
7024     
7025     Roo.onReady(function() {
7026         _this.fireEvent('ready');
7027     },null,false);
7028     
7029     
7030 }
7031
7032 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7033  * Based on:
7034  * Ext JS Library 1.1.1
7035  * Copyright(c) 2006-2007, Ext JS, LLC.
7036  *
7037  * Originally Released Under LGPL - original licence link has changed is not relivant.
7038  *
7039  * Fork - LGPL
7040  * <script type="text/javascript">
7041  */
7042
7043 /**
7044  * @class Roo.EventManager
7045  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7046  * several useful events directly.
7047  * See {@link Roo.EventObject} for more details on normalized event objects.
7048  * @static
7049  */
7050 Roo.EventManager = function(){
7051     var docReadyEvent, docReadyProcId, docReadyState = false;
7052     var resizeEvent, resizeTask, textEvent, textSize;
7053     var E = Roo.lib.Event;
7054     var D = Roo.lib.Dom;
7055
7056     
7057     
7058
7059     var fireDocReady = function(){
7060         if(!docReadyState){
7061             docReadyState = true;
7062             Roo.isReady = true;
7063             if(docReadyProcId){
7064                 clearInterval(docReadyProcId);
7065             }
7066             if(Roo.isGecko || Roo.isOpera) {
7067                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7068             }
7069             if(Roo.isIE){
7070                 var defer = document.getElementById("ie-deferred-loader");
7071                 if(defer){
7072                     defer.onreadystatechange = null;
7073                     defer.parentNode.removeChild(defer);
7074                 }
7075             }
7076             if(docReadyEvent){
7077                 docReadyEvent.fire();
7078                 docReadyEvent.clearListeners();
7079             }
7080         }
7081     };
7082     
7083     var initDocReady = function(){
7084         docReadyEvent = new Roo.util.Event();
7085         if(Roo.isGecko || Roo.isOpera) {
7086             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7087         }else if(Roo.isIE){
7088             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7089             var defer = document.getElementById("ie-deferred-loader");
7090             defer.onreadystatechange = function(){
7091                 if(this.readyState == "complete"){
7092                     fireDocReady();
7093                 }
7094             };
7095         }else if(Roo.isSafari){ 
7096             docReadyProcId = setInterval(function(){
7097                 var rs = document.readyState;
7098                 if(rs == "complete") {
7099                     fireDocReady();     
7100                  }
7101             }, 10);
7102         }
7103         // no matter what, make sure it fires on load
7104         E.on(window, "load", fireDocReady);
7105     };
7106
7107     var createBuffered = function(h, o){
7108         var task = new Roo.util.DelayedTask(h);
7109         return function(e){
7110             // create new event object impl so new events don't wipe out properties
7111             e = new Roo.EventObjectImpl(e);
7112             task.delay(o.buffer, h, null, [e]);
7113         };
7114     };
7115
7116     var createSingle = function(h, el, ename, fn){
7117         return function(e){
7118             Roo.EventManager.removeListener(el, ename, fn);
7119             h(e);
7120         };
7121     };
7122
7123     var createDelayed = function(h, o){
7124         return function(e){
7125             // create new event object impl so new events don't wipe out properties
7126             e = new Roo.EventObjectImpl(e);
7127             setTimeout(function(){
7128                 h(e);
7129             }, o.delay || 10);
7130         };
7131     };
7132     var transitionEndVal = false;
7133     
7134     var transitionEnd = function()
7135     {
7136         if (transitionEndVal) {
7137             return transitionEndVal;
7138         }
7139         var el = document.createElement('div');
7140
7141         var transEndEventNames = {
7142             WebkitTransition : 'webkitTransitionEnd',
7143             MozTransition    : 'transitionend',
7144             OTransition      : 'oTransitionEnd otransitionend',
7145             transition       : 'transitionend'
7146         };
7147     
7148         for (var name in transEndEventNames) {
7149             if (el.style[name] !== undefined) {
7150                 transitionEndVal = transEndEventNames[name];
7151                 return  transitionEndVal ;
7152             }
7153         }
7154     }
7155     
7156   
7157
7158     var listen = function(element, ename, opt, fn, scope)
7159     {
7160         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7161         fn = fn || o.fn; scope = scope || o.scope;
7162         var el = Roo.getDom(element);
7163         
7164         
7165         if(!el){
7166             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7167         }
7168         
7169         if (ename == 'transitionend') {
7170             ename = transitionEnd();
7171         }
7172         var h = function(e){
7173             e = Roo.EventObject.setEvent(e);
7174             var t;
7175             if(o.delegate){
7176                 t = e.getTarget(o.delegate, el);
7177                 if(!t){
7178                     return;
7179                 }
7180             }else{
7181                 t = e.target;
7182             }
7183             if(o.stopEvent === true){
7184                 e.stopEvent();
7185             }
7186             if(o.preventDefault === true){
7187                e.preventDefault();
7188             }
7189             if(o.stopPropagation === true){
7190                 e.stopPropagation();
7191             }
7192
7193             if(o.normalized === false){
7194                 e = e.browserEvent;
7195             }
7196
7197             fn.call(scope || el, e, t, o);
7198         };
7199         if(o.delay){
7200             h = createDelayed(h, o);
7201         }
7202         if(o.single){
7203             h = createSingle(h, el, ename, fn);
7204         }
7205         if(o.buffer){
7206             h = createBuffered(h, o);
7207         }
7208         
7209         fn._handlers = fn._handlers || [];
7210         
7211         
7212         fn._handlers.push([Roo.id(el), ename, h]);
7213         
7214         
7215          
7216         E.on(el, ename, h); // this adds the actuall listener to the object..
7217         
7218         
7219         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7220             el.addEventListener("DOMMouseScroll", h, false);
7221             E.on(window, 'unload', function(){
7222                 el.removeEventListener("DOMMouseScroll", h, false);
7223             });
7224         }
7225         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7226             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7227         }
7228         return h;
7229     };
7230
7231     var stopListening = function(el, ename, fn){
7232         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7233         if(hds){
7234             for(var i = 0, len = hds.length; i < len; i++){
7235                 var h = hds[i];
7236                 if(h[0] == id && h[1] == ename){
7237                     hd = h[2];
7238                     hds.splice(i, 1);
7239                     break;
7240                 }
7241             }
7242         }
7243         E.un(el, ename, hd);
7244         el = Roo.getDom(el);
7245         if(ename == "mousewheel" && el.addEventListener){
7246             el.removeEventListener("DOMMouseScroll", hd, false);
7247         }
7248         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7249             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7250         }
7251     };
7252
7253     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7254     
7255     var pub = {
7256         
7257         
7258         /** 
7259          * Fix for doc tools
7260          * @scope Roo.EventManager
7261          */
7262         
7263         
7264         /** 
7265          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7266          * object with a Roo.EventObject
7267          * @param {Function} fn        The method the event invokes
7268          * @param {Object}   scope    An object that becomes the scope of the handler
7269          * @param {boolean}  override If true, the obj passed in becomes
7270          *                             the execution scope of the listener
7271          * @return {Function} The wrapped function
7272          * @deprecated
7273          */
7274         wrap : function(fn, scope, override){
7275             return function(e){
7276                 Roo.EventObject.setEvent(e);
7277                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7278             };
7279         },
7280         
7281         /**
7282      * Appends an event handler to an element (shorthand for addListener)
7283      * @param {String/HTMLElement}   element        The html element or id to assign the
7284      * @param {String}   eventName The type of event to listen for
7285      * @param {Function} handler The method the event invokes
7286      * @param {Object}   scope (optional) The scope in which to execute the handler
7287      * function. The handler function's "this" context.
7288      * @param {Object}   options (optional) An object containing handler configuration
7289      * properties. This may contain any of the following properties:<ul>
7290      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7291      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7292      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7293      * <li>preventDefault {Boolean} True to prevent the default action</li>
7294      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7295      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7296      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7297      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7298      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7299      * by the specified number of milliseconds. If the event fires again within that time, the original
7300      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7301      * </ul><br>
7302      * <p>
7303      * <b>Combining Options</b><br>
7304      * Using the options argument, it is possible to combine different types of listeners:<br>
7305      * <br>
7306      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7307      * Code:<pre><code>
7308 el.on('click', this.onClick, this, {
7309     single: true,
7310     delay: 100,
7311     stopEvent : true,
7312     forumId: 4
7313 });</code></pre>
7314      * <p>
7315      * <b>Attaching multiple handlers in 1 call</b><br>
7316       * The method also allows for a single argument to be passed which is a config object containing properties
7317      * which specify multiple handlers.
7318      * <p>
7319      * Code:<pre><code>
7320 el.on({
7321     'click' : {
7322         fn: this.onClick
7323         scope: this,
7324         delay: 100
7325     },
7326     'mouseover' : {
7327         fn: this.onMouseOver
7328         scope: this
7329     },
7330     'mouseout' : {
7331         fn: this.onMouseOut
7332         scope: this
7333     }
7334 });</code></pre>
7335      * <p>
7336      * Or a shorthand syntax:<br>
7337      * Code:<pre><code>
7338 el.on({
7339     'click' : this.onClick,
7340     'mouseover' : this.onMouseOver,
7341     'mouseout' : this.onMouseOut
7342     scope: this
7343 });</code></pre>
7344      */
7345         addListener : function(element, eventName, fn, scope, options){
7346             if(typeof eventName == "object"){
7347                 var o = eventName;
7348                 for(var e in o){
7349                     if(propRe.test(e)){
7350                         continue;
7351                     }
7352                     if(typeof o[e] == "function"){
7353                         // shared options
7354                         listen(element, e, o, o[e], o.scope);
7355                     }else{
7356                         // individual options
7357                         listen(element, e, o[e]);
7358                     }
7359                 }
7360                 return;
7361             }
7362             return listen(element, eventName, options, fn, scope);
7363         },
7364         
7365         /**
7366          * Removes an event handler
7367          *
7368          * @param {String/HTMLElement}   element        The id or html element to remove the 
7369          *                             event from
7370          * @param {String}   eventName     The type of event
7371          * @param {Function} fn
7372          * @return {Boolean} True if a listener was actually removed
7373          */
7374         removeListener : function(element, eventName, fn){
7375             return stopListening(element, eventName, fn);
7376         },
7377         
7378         /**
7379          * Fires when the document is ready (before onload and before images are loaded). Can be 
7380          * accessed shorthanded Roo.onReady().
7381          * @param {Function} fn        The method the event invokes
7382          * @param {Object}   scope    An  object that becomes the scope of the handler
7383          * @param {boolean}  options
7384          */
7385         onDocumentReady : function(fn, scope, options){
7386             if(docReadyState){ // if it already fired
7387                 docReadyEvent.addListener(fn, scope, options);
7388                 docReadyEvent.fire();
7389                 docReadyEvent.clearListeners();
7390                 return;
7391             }
7392             if(!docReadyEvent){
7393                 initDocReady();
7394             }
7395             docReadyEvent.addListener(fn, scope, options);
7396         },
7397         
7398         /**
7399          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7400          * @param {Function} fn        The method the event invokes
7401          * @param {Object}   scope    An object that becomes the scope of the handler
7402          * @param {boolean}  options
7403          */
7404         onWindowResize : function(fn, scope, options)
7405         {
7406             if(!resizeEvent){
7407                 resizeEvent = new Roo.util.Event();
7408                 resizeTask = new Roo.util.DelayedTask(function(){
7409                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7410                 });
7411                 E.on(window, "resize", function()
7412                 {
7413                     if (Roo.isIE) {
7414                         resizeTask.delay(50);
7415                     } else {
7416                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7417                     }
7418                 });
7419             }
7420             resizeEvent.addListener(fn, scope, options);
7421         },
7422
7423         /**
7424          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7425          * @param {Function} fn        The method the event invokes
7426          * @param {Object}   scope    An object that becomes the scope of the handler
7427          * @param {boolean}  options
7428          */
7429         onTextResize : function(fn, scope, options){
7430             if(!textEvent){
7431                 textEvent = new Roo.util.Event();
7432                 var textEl = new Roo.Element(document.createElement('div'));
7433                 textEl.dom.className = 'x-text-resize';
7434                 textEl.dom.innerHTML = 'X';
7435                 textEl.appendTo(document.body);
7436                 textSize = textEl.dom.offsetHeight;
7437                 setInterval(function(){
7438                     if(textEl.dom.offsetHeight != textSize){
7439                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7440                     }
7441                 }, this.textResizeInterval);
7442             }
7443             textEvent.addListener(fn, scope, options);
7444         },
7445
7446         /**
7447          * Removes the passed window resize listener.
7448          * @param {Function} fn        The method the event invokes
7449          * @param {Object}   scope    The scope of handler
7450          */
7451         removeResizeListener : function(fn, scope){
7452             if(resizeEvent){
7453                 resizeEvent.removeListener(fn, scope);
7454             }
7455         },
7456
7457         // private
7458         fireResize : function(){
7459             if(resizeEvent){
7460                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7461             }   
7462         },
7463         /**
7464          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7465          */
7466         ieDeferSrc : false,
7467         /**
7468          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7469          */
7470         textResizeInterval : 50
7471     };
7472     
7473     /**
7474      * Fix for doc tools
7475      * @scopeAlias pub=Roo.EventManager
7476      */
7477     
7478      /**
7479      * Appends an event handler to an element (shorthand for addListener)
7480      * @param {String/HTMLElement}   element        The html element or id to assign the
7481      * @param {String}   eventName The type of event to listen for
7482      * @param {Function} handler The method the event invokes
7483      * @param {Object}   scope (optional) The scope in which to execute the handler
7484      * function. The handler function's "this" context.
7485      * @param {Object}   options (optional) An object containing handler configuration
7486      * properties. This may contain any of the following properties:<ul>
7487      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7488      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7489      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7490      * <li>preventDefault {Boolean} True to prevent the default action</li>
7491      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7492      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7493      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7494      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7495      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7496      * by the specified number of milliseconds. If the event fires again within that time, the original
7497      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7498      * </ul><br>
7499      * <p>
7500      * <b>Combining Options</b><br>
7501      * Using the options argument, it is possible to combine different types of listeners:<br>
7502      * <br>
7503      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7504      * Code:<pre><code>
7505 el.on('click', this.onClick, this, {
7506     single: true,
7507     delay: 100,
7508     stopEvent : true,
7509     forumId: 4
7510 });</code></pre>
7511      * <p>
7512      * <b>Attaching multiple handlers in 1 call</b><br>
7513       * The method also allows for a single argument to be passed which is a config object containing properties
7514      * which specify multiple handlers.
7515      * <p>
7516      * Code:<pre><code>
7517 el.on({
7518     'click' : {
7519         fn: this.onClick
7520         scope: this,
7521         delay: 100
7522     },
7523     'mouseover' : {
7524         fn: this.onMouseOver
7525         scope: this
7526     },
7527     'mouseout' : {
7528         fn: this.onMouseOut
7529         scope: this
7530     }
7531 });</code></pre>
7532      * <p>
7533      * Or a shorthand syntax:<br>
7534      * Code:<pre><code>
7535 el.on({
7536     'click' : this.onClick,
7537     'mouseover' : this.onMouseOver,
7538     'mouseout' : this.onMouseOut
7539     scope: this
7540 });</code></pre>
7541      */
7542     pub.on = pub.addListener;
7543     pub.un = pub.removeListener;
7544
7545     pub.stoppedMouseDownEvent = new Roo.util.Event();
7546     return pub;
7547 }();
7548 /**
7549   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
7550   * @param {Function} fn        The method the event invokes
7551   * @param {Object}   scope    An  object that becomes the scope of the handler
7552   * @param {boolean}  override If true, the obj passed in becomes
7553   *                             the execution scope of the listener
7554   * @member Roo
7555   * @method onReady
7556  */
7557 Roo.onReady = Roo.EventManager.onDocumentReady;
7558
7559 Roo.onReady(function(){
7560     var bd = Roo.get(document.body);
7561     if(!bd){ return; }
7562
7563     var cls = [
7564             Roo.isIE ? "roo-ie"
7565             : Roo.isIE11 ? "roo-ie11"
7566             : Roo.isEdge ? "roo-edge"
7567             : Roo.isGecko ? "roo-gecko"
7568             : Roo.isOpera ? "roo-opera"
7569             : Roo.isSafari ? "roo-safari" : ""];
7570
7571     if(Roo.isMac){
7572         cls.push("roo-mac");
7573     }
7574     if(Roo.isLinux){
7575         cls.push("roo-linux");
7576     }
7577     if(Roo.isIOS){
7578         cls.push("roo-ios");
7579     }
7580     if(Roo.isTouch){
7581         cls.push("roo-touch");
7582     }
7583     if(Roo.isBorderBox){
7584         cls.push('roo-border-box');
7585     }
7586     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7587         var p = bd.dom.parentNode;
7588         if(p){
7589             p.className += ' roo-strict';
7590         }
7591     }
7592     bd.addClass(cls.join(' '));
7593 });
7594
7595 /**
7596  * @class Roo.EventObject
7597  * EventObject exposes the Yahoo! UI Event functionality directly on the object
7598  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
7599  * Example:
7600  * <pre><code>
7601  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7602     e.preventDefault();
7603     var target = e.getTarget();
7604     ...
7605  }
7606  var myDiv = Roo.get("myDiv");
7607  myDiv.on("click", handleClick);
7608  //or
7609  Roo.EventManager.on("myDiv", 'click', handleClick);
7610  Roo.EventManager.addListener("myDiv", 'click', handleClick);
7611  </code></pre>
7612  * @static
7613  */
7614 Roo.EventObject = function(){
7615     
7616     var E = Roo.lib.Event;
7617     
7618     // safari keypress events for special keys return bad keycodes
7619     var safariKeys = {
7620         63234 : 37, // left
7621         63235 : 39, // right
7622         63232 : 38, // up
7623         63233 : 40, // down
7624         63276 : 33, // page up
7625         63277 : 34, // page down
7626         63272 : 46, // delete
7627         63273 : 36, // home
7628         63275 : 35  // end
7629     };
7630
7631     // normalize button clicks
7632     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7633                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7634
7635     Roo.EventObjectImpl = function(e){
7636         if(e){
7637             this.setEvent(e.browserEvent || e);
7638         }
7639     };
7640     Roo.EventObjectImpl.prototype = {
7641         /**
7642          * Used to fix doc tools.
7643          * @scope Roo.EventObject.prototype
7644          */
7645             
7646
7647         
7648         
7649         /** The normal browser event */
7650         browserEvent : null,
7651         /** The button pressed in a mouse event */
7652         button : -1,
7653         /** True if the shift key was down during the event */
7654         shiftKey : false,
7655         /** True if the control key was down during the event */
7656         ctrlKey : false,
7657         /** True if the alt key was down during the event */
7658         altKey : false,
7659
7660         /** Key constant 
7661         * @type Number */
7662         BACKSPACE : 8,
7663         /** Key constant 
7664         * @type Number */
7665         TAB : 9,
7666         /** Key constant 
7667         * @type Number */
7668         RETURN : 13,
7669         /** Key constant 
7670         * @type Number */
7671         ENTER : 13,
7672         /** Key constant 
7673         * @type Number */
7674         SHIFT : 16,
7675         /** Key constant 
7676         * @type Number */
7677         CONTROL : 17,
7678         /** Key constant 
7679         * @type Number */
7680         ESC : 27,
7681         /** Key constant 
7682         * @type Number */
7683         SPACE : 32,
7684         /** Key constant 
7685         * @type Number */
7686         PAGEUP : 33,
7687         /** Key constant 
7688         * @type Number */
7689         PAGEDOWN : 34,
7690         /** Key constant 
7691         * @type Number */
7692         END : 35,
7693         /** Key constant 
7694         * @type Number */
7695         HOME : 36,
7696         /** Key constant 
7697         * @type Number */
7698         LEFT : 37,
7699         /** Key constant 
7700         * @type Number */
7701         UP : 38,
7702         /** Key constant 
7703         * @type Number */
7704         RIGHT : 39,
7705         /** Key constant 
7706         * @type Number */
7707         DOWN : 40,
7708         /** Key constant 
7709         * @type Number */
7710         DELETE : 46,
7711         /** Key constant 
7712         * @type Number */
7713         F5 : 116,
7714
7715            /** @private */
7716         setEvent : function(e){
7717             if(e == this || (e && e.browserEvent)){ // already wrapped
7718                 return e;
7719             }
7720             this.browserEvent = e;
7721             if(e){
7722                 // normalize buttons
7723                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7724                 if(e.type == 'click' && this.button == -1){
7725                     this.button = 0;
7726                 }
7727                 this.type = e.type;
7728                 this.shiftKey = e.shiftKey;
7729                 // mac metaKey behaves like ctrlKey
7730                 this.ctrlKey = e.ctrlKey || e.metaKey;
7731                 this.altKey = e.altKey;
7732                 // in getKey these will be normalized for the mac
7733                 this.keyCode = e.keyCode;
7734                 // keyup warnings on firefox.
7735                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7736                 // cache the target for the delayed and or buffered events
7737                 this.target = E.getTarget(e);
7738                 // same for XY
7739                 this.xy = E.getXY(e);
7740             }else{
7741                 this.button = -1;
7742                 this.shiftKey = false;
7743                 this.ctrlKey = false;
7744                 this.altKey = false;
7745                 this.keyCode = 0;
7746                 this.charCode =0;
7747                 this.target = null;
7748                 this.xy = [0, 0];
7749             }
7750             return this;
7751         },
7752
7753         /**
7754          * Stop the event (preventDefault and stopPropagation)
7755          */
7756         stopEvent : function(){
7757             if(this.browserEvent){
7758                 if(this.browserEvent.type == 'mousedown'){
7759                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7760                 }
7761                 E.stopEvent(this.browserEvent);
7762             }
7763         },
7764
7765         /**
7766          * Prevents the browsers default handling of the event.
7767          */
7768         preventDefault : function(){
7769             if(this.browserEvent){
7770                 E.preventDefault(this.browserEvent);
7771             }
7772         },
7773
7774         /** @private */
7775         isNavKeyPress : function(){
7776             var k = this.keyCode;
7777             k = Roo.isSafari ? (safariKeys[k] || k) : k;
7778             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7779         },
7780
7781         isSpecialKey : function(){
7782             var k = this.keyCode;
7783             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
7784             (k == 16) || (k == 17) ||
7785             (k >= 18 && k <= 20) ||
7786             (k >= 33 && k <= 35) ||
7787             (k >= 36 && k <= 39) ||
7788             (k >= 44 && k <= 45);
7789         },
7790         /**
7791          * Cancels bubbling of the event.
7792          */
7793         stopPropagation : function(){
7794             if(this.browserEvent){
7795                 if(this.type == 'mousedown'){
7796                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
7797                 }
7798                 E.stopPropagation(this.browserEvent);
7799             }
7800         },
7801
7802         /**
7803          * Gets the key code for the event.
7804          * @return {Number}
7805          */
7806         getCharCode : function(){
7807             return this.charCode || this.keyCode;
7808         },
7809
7810         /**
7811          * Returns a normalized keyCode for the event.
7812          * @return {Number} The key code
7813          */
7814         getKey : function(){
7815             var k = this.keyCode || this.charCode;
7816             return Roo.isSafari ? (safariKeys[k] || k) : k;
7817         },
7818
7819         /**
7820          * Gets the x coordinate of the event.
7821          * @return {Number}
7822          */
7823         getPageX : function(){
7824             return this.xy[0];
7825         },
7826
7827         /**
7828          * Gets the y coordinate of the event.
7829          * @return {Number}
7830          */
7831         getPageY : function(){
7832             return this.xy[1];
7833         },
7834
7835         /**
7836          * Gets the time of the event.
7837          * @return {Number}
7838          */
7839         getTime : function(){
7840             if(this.browserEvent){
7841                 return E.getTime(this.browserEvent);
7842             }
7843             return null;
7844         },
7845
7846         /**
7847          * Gets the page coordinates of the event.
7848          * @return {Array} The xy values like [x, y]
7849          */
7850         getXY : function(){
7851             return this.xy;
7852         },
7853
7854         /**
7855          * Gets the target for the event.
7856          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7857          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7858                 search as a number or element (defaults to 10 || document.body)
7859          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7860          * @return {HTMLelement}
7861          */
7862         getTarget : function(selector, maxDepth, returnEl){
7863             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7864         },
7865         /**
7866          * Gets the related target.
7867          * @return {HTMLElement}
7868          */
7869         getRelatedTarget : function(){
7870             if(this.browserEvent){
7871                 return E.getRelatedTarget(this.browserEvent);
7872             }
7873             return null;
7874         },
7875
7876         /**
7877          * Normalizes mouse wheel delta across browsers
7878          * @return {Number} The delta
7879          */
7880         getWheelDelta : function(){
7881             var e = this.browserEvent;
7882             var delta = 0;
7883             if(e.wheelDelta){ /* IE/Opera. */
7884                 delta = e.wheelDelta/120;
7885             }else if(e.detail){ /* Mozilla case. */
7886                 delta = -e.detail/3;
7887             }
7888             return delta;
7889         },
7890
7891         /**
7892          * Returns true if the control, meta, shift or alt key was pressed during this event.
7893          * @return {Boolean}
7894          */
7895         hasModifier : function(){
7896             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7897         },
7898
7899         /**
7900          * Returns true if the target of this event equals el or is a child of el
7901          * @param {String/HTMLElement/Element} el
7902          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7903          * @return {Boolean}
7904          */
7905         within : function(el, related){
7906             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7907             return t && Roo.fly(el).contains(t);
7908         },
7909
7910         getPoint : function(){
7911             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7912         }
7913     };
7914
7915     return new Roo.EventObjectImpl();
7916 }();
7917             
7918     /*
7919  * Based on:
7920  * Ext JS Library 1.1.1
7921  * Copyright(c) 2006-2007, Ext JS, LLC.
7922  *
7923  * Originally Released Under LGPL - original licence link has changed is not relivant.
7924  *
7925  * Fork - LGPL
7926  * <script type="text/javascript">
7927  */
7928
7929  
7930 // was in Composite Element!??!?!
7931  
7932 (function(){
7933     var D = Roo.lib.Dom;
7934     var E = Roo.lib.Event;
7935     var A = Roo.lib.Anim;
7936
7937     // local style camelizing for speed
7938     var propCache = {};
7939     var camelRe = /(-[a-z])/gi;
7940     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7941     var view = document.defaultView;
7942
7943 /**
7944  * @class Roo.Element
7945  * Represents an Element in the DOM.<br><br>
7946  * Usage:<br>
7947 <pre><code>
7948 var el = Roo.get("my-div");
7949
7950 // or with getEl
7951 var el = getEl("my-div");
7952
7953 // or with a DOM element
7954 var el = Roo.get(myDivElement);
7955 </code></pre>
7956  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7957  * each call instead of constructing a new one.<br><br>
7958  * <b>Animations</b><br />
7959  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7960  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7961 <pre>
7962 Option    Default   Description
7963 --------- --------  ---------------------------------------------
7964 duration  .35       The duration of the animation in seconds
7965 easing    easeOut   The YUI easing method
7966 callback  none      A function to execute when the anim completes
7967 scope     this      The scope (this) of the callback function
7968 </pre>
7969 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7970 * manipulate the animation. Here's an example:
7971 <pre><code>
7972 var el = Roo.get("my-div");
7973
7974 // no animation
7975 el.setWidth(100);
7976
7977 // default animation
7978 el.setWidth(100, true);
7979
7980 // animation with some options set
7981 el.setWidth(100, {
7982     duration: 1,
7983     callback: this.foo,
7984     scope: this
7985 });
7986
7987 // using the "anim" property to get the Anim object
7988 var opt = {
7989     duration: 1,
7990     callback: this.foo,
7991     scope: this
7992 };
7993 el.setWidth(100, opt);
7994 ...
7995 if(opt.anim.isAnimated()){
7996     opt.anim.stop();
7997 }
7998 </code></pre>
7999 * <b> Composite (Collections of) Elements</b><br />
8000  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8001  * @constructor Create a new Element directly.
8002  * @param {String/HTMLElement} element
8003  * @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).
8004  */
8005     Roo.Element = function(element, forceNew)
8006     {
8007         var dom = typeof element == "string" ?
8008                 document.getElementById(element) : element;
8009         
8010         this.listeners = {};
8011         
8012         if(!dom){ // invalid id/element
8013             return null;
8014         }
8015         var id = dom.id;
8016         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8017             return Roo.Element.cache[id];
8018         }
8019
8020         /**
8021          * The DOM element
8022          * @type HTMLElement
8023          */
8024         this.dom = dom;
8025
8026         /**
8027          * The DOM element ID
8028          * @type String
8029          */
8030         this.id = id || Roo.id(dom);
8031         
8032         return this; // assumed for cctor?
8033     };
8034
8035     var El = Roo.Element;
8036
8037     El.prototype = {
8038         /**
8039          * The element's default display mode  (defaults to "") 
8040          * @type String
8041          */
8042         originalDisplay : "",
8043
8044         
8045         // note this is overridden in BS version..
8046         visibilityMode : 1, 
8047         /**
8048          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8049          * @type String
8050          */
8051         defaultUnit : "px",
8052         
8053         /**
8054          * Sets the element's visibility mode. When setVisible() is called it
8055          * will use this to determine whether to set the visibility or the display property.
8056          * @param visMode Element.VISIBILITY or Element.DISPLAY
8057          * @return {Roo.Element} this
8058          */
8059         setVisibilityMode : function(visMode){
8060             this.visibilityMode = visMode;
8061             return this;
8062         },
8063         /**
8064          * Convenience method for setVisibilityMode(Element.DISPLAY)
8065          * @param {String} display (optional) What to set display to when visible
8066          * @return {Roo.Element} this
8067          */
8068         enableDisplayMode : function(display){
8069             this.setVisibilityMode(El.DISPLAY);
8070             if(typeof display != "undefined") { this.originalDisplay = display; }
8071             return this;
8072         },
8073
8074         /**
8075          * 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)
8076          * @param {String} selector The simple selector to test
8077          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8078                 search as a number or element (defaults to 10 || document.body)
8079          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8080          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8081          */
8082         findParent : function(simpleSelector, maxDepth, returnEl){
8083             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8084             maxDepth = maxDepth || 50;
8085             if(typeof maxDepth != "number"){
8086                 stopEl = Roo.getDom(maxDepth);
8087                 maxDepth = 10;
8088             }
8089             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8090                 if(dq.is(p, simpleSelector)){
8091                     return returnEl ? Roo.get(p) : p;
8092                 }
8093                 depth++;
8094                 p = p.parentNode;
8095             }
8096             return null;
8097         },
8098
8099
8100         /**
8101          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8102          * @param {String} selector The simple selector to test
8103          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8104                 search as a number or element (defaults to 10 || document.body)
8105          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8106          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8107          */
8108         findParentNode : function(simpleSelector, maxDepth, returnEl){
8109             var p = Roo.fly(this.dom.parentNode, '_internal');
8110             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8111         },
8112         
8113         /**
8114          * Looks at  the scrollable parent element
8115          */
8116         findScrollableParent : function()
8117         {
8118             var overflowRegex = /(auto|scroll)/;
8119             
8120             if(this.getStyle('position') === 'fixed'){
8121                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8122             }
8123             
8124             var excludeStaticParent = this.getStyle('position') === "absolute";
8125             
8126             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8127                 
8128                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8129                     continue;
8130                 }
8131                 
8132                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8133                     return parent;
8134                 }
8135                 
8136                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8137                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8138                 }
8139             }
8140             
8141             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8142         },
8143
8144         /**
8145          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8146          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8147          * @param {String} selector The simple selector to test
8148          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8149                 search as a number or element (defaults to 10 || document.body)
8150          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8151          */
8152         up : function(simpleSelector, maxDepth){
8153             return this.findParentNode(simpleSelector, maxDepth, true);
8154         },
8155
8156
8157
8158         /**
8159          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8160          * @param {String} selector The simple selector to test
8161          * @return {Boolean} True if this element matches the selector, else false
8162          */
8163         is : function(simpleSelector){
8164             return Roo.DomQuery.is(this.dom, simpleSelector);
8165         },
8166
8167         /**
8168          * Perform animation on this element.
8169          * @param {Object} args The YUI animation control args
8170          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8171          * @param {Function} onComplete (optional) Function to call when animation completes
8172          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8173          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8174          * @return {Roo.Element} this
8175          */
8176         animate : function(args, duration, onComplete, easing, animType){
8177             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8178             return this;
8179         },
8180
8181         /*
8182          * @private Internal animation call
8183          */
8184         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8185             animType = animType || 'run';
8186             opt = opt || {};
8187             var anim = Roo.lib.Anim[animType](
8188                 this.dom, args,
8189                 (opt.duration || defaultDur) || .35,
8190                 (opt.easing || defaultEase) || 'easeOut',
8191                 function(){
8192                     Roo.callback(cb, this);
8193                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8194                 },
8195                 this
8196             );
8197             opt.anim = anim;
8198             return anim;
8199         },
8200
8201         // private legacy anim prep
8202         preanim : function(a, i){
8203             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8204         },
8205
8206         /**
8207          * Removes worthless text nodes
8208          * @param {Boolean} forceReclean (optional) By default the element
8209          * keeps track if it has been cleaned already so
8210          * you can call this over and over. However, if you update the element and
8211          * need to force a reclean, you can pass true.
8212          */
8213         clean : function(forceReclean){
8214             if(this.isCleaned && forceReclean !== true){
8215                 return this;
8216             }
8217             var ns = /\S/;
8218             var d = this.dom, n = d.firstChild, ni = -1;
8219             while(n){
8220                 var nx = n.nextSibling;
8221                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8222                     d.removeChild(n);
8223                 }else{
8224                     n.nodeIndex = ++ni;
8225                 }
8226                 n = nx;
8227             }
8228             this.isCleaned = true;
8229             return this;
8230         },
8231
8232         // private
8233         calcOffsetsTo : function(el){
8234             el = Roo.get(el);
8235             var d = el.dom;
8236             var restorePos = false;
8237             if(el.getStyle('position') == 'static'){
8238                 el.position('relative');
8239                 restorePos = true;
8240             }
8241             var x = 0, y =0;
8242             var op = this.dom;
8243             while(op && op != d && op.tagName != 'HTML'){
8244                 x+= op.offsetLeft;
8245                 y+= op.offsetTop;
8246                 op = op.offsetParent;
8247             }
8248             if(restorePos){
8249                 el.position('static');
8250             }
8251             return [x, y];
8252         },
8253
8254         /**
8255          * Scrolls this element into view within the passed container.
8256          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8257          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8258          * @return {Roo.Element} this
8259          */
8260         scrollIntoView : function(container, hscroll){
8261             var c = Roo.getDom(container) || document.body;
8262             var el = this.dom;
8263
8264             var o = this.calcOffsetsTo(c),
8265                 l = o[0],
8266                 t = o[1],
8267                 b = t+el.offsetHeight,
8268                 r = l+el.offsetWidth;
8269
8270             var ch = c.clientHeight;
8271             var ct = parseInt(c.scrollTop, 10);
8272             var cl = parseInt(c.scrollLeft, 10);
8273             var cb = ct + ch;
8274             var cr = cl + c.clientWidth;
8275
8276             if(t < ct){
8277                 c.scrollTop = t;
8278             }else if(b > cb){
8279                 c.scrollTop = b-ch;
8280             }
8281
8282             if(hscroll !== false){
8283                 if(l < cl){
8284                     c.scrollLeft = l;
8285                 }else if(r > cr){
8286                     c.scrollLeft = r-c.clientWidth;
8287                 }
8288             }
8289             return this;
8290         },
8291
8292         // private
8293         scrollChildIntoView : function(child, hscroll){
8294             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8295         },
8296
8297         /**
8298          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8299          * the new height may not be available immediately.
8300          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8301          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8302          * @param {Function} onComplete (optional) Function to call when animation completes
8303          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8304          * @return {Roo.Element} this
8305          */
8306         autoHeight : function(animate, duration, onComplete, easing){
8307             var oldHeight = this.getHeight();
8308             this.clip();
8309             this.setHeight(1); // force clipping
8310             setTimeout(function(){
8311                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8312                 if(!animate){
8313                     this.setHeight(height);
8314                     this.unclip();
8315                     if(typeof onComplete == "function"){
8316                         onComplete();
8317                     }
8318                 }else{
8319                     this.setHeight(oldHeight); // restore original height
8320                     this.setHeight(height, animate, duration, function(){
8321                         this.unclip();
8322                         if(typeof onComplete == "function") { onComplete(); }
8323                     }.createDelegate(this), easing);
8324                 }
8325             }.createDelegate(this), 0);
8326             return this;
8327         },
8328
8329         /**
8330          * Returns true if this element is an ancestor of the passed element
8331          * @param {HTMLElement/String} el The element to check
8332          * @return {Boolean} True if this element is an ancestor of el, else false
8333          */
8334         contains : function(el){
8335             if(!el){return false;}
8336             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8337         },
8338
8339         /**
8340          * Checks whether the element is currently visible using both visibility and display properties.
8341          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8342          * @return {Boolean} True if the element is currently visible, else false
8343          */
8344         isVisible : function(deep) {
8345             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8346             if(deep !== true || !vis){
8347                 return vis;
8348             }
8349             var p = this.dom.parentNode;
8350             while(p && p.tagName.toLowerCase() != "body"){
8351                 if(!Roo.fly(p, '_isVisible').isVisible()){
8352                     return false;
8353                 }
8354                 p = p.parentNode;
8355             }
8356             return true;
8357         },
8358
8359         /**
8360          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8361          * @param {String} selector The CSS selector
8362          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8363          * @return {CompositeElement/CompositeElementLite} The composite element
8364          */
8365         select : function(selector, unique){
8366             return El.select(selector, unique, this.dom);
8367         },
8368
8369         /**
8370          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8371          * @param {String} selector The CSS selector
8372          * @return {Array} An array of the matched nodes
8373          */
8374         query : function(selector, unique){
8375             return Roo.DomQuery.select(selector, this.dom);
8376         },
8377
8378         /**
8379          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8380          * @param {String} selector The CSS selector
8381          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8382          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8383          */
8384         child : function(selector, returnDom){
8385             var n = Roo.DomQuery.selectNode(selector, this.dom);
8386             return returnDom ? n : Roo.get(n);
8387         },
8388
8389         /**
8390          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8391          * @param {String} selector The CSS selector
8392          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8393          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8394          */
8395         down : function(selector, returnDom){
8396             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8397             return returnDom ? n : Roo.get(n);
8398         },
8399
8400         /**
8401          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8402          * @param {String} group The group the DD object is member of
8403          * @param {Object} config The DD config object
8404          * @param {Object} overrides An object containing methods to override/implement on the DD object
8405          * @return {Roo.dd.DD} The DD object
8406          */
8407         initDD : function(group, config, overrides){
8408             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8409             return Roo.apply(dd, overrides);
8410         },
8411
8412         /**
8413          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8414          * @param {String} group The group the DDProxy object is member of
8415          * @param {Object} config The DDProxy config object
8416          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8417          * @return {Roo.dd.DDProxy} The DDProxy object
8418          */
8419         initDDProxy : function(group, config, overrides){
8420             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8421             return Roo.apply(dd, overrides);
8422         },
8423
8424         /**
8425          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8426          * @param {String} group The group the DDTarget object is member of
8427          * @param {Object} config The DDTarget config object
8428          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8429          * @return {Roo.dd.DDTarget} The DDTarget object
8430          */
8431         initDDTarget : function(group, config, overrides){
8432             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8433             return Roo.apply(dd, overrides);
8434         },
8435
8436         /**
8437          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8438          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8439          * @param {Boolean} visible Whether the element is visible
8440          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8441          * @return {Roo.Element} this
8442          */
8443          setVisible : function(visible, animate){
8444             if(!animate || !A){
8445                 if(this.visibilityMode == El.DISPLAY){
8446                     this.setDisplayed(visible);
8447                 }else{
8448                     this.fixDisplay();
8449                     this.dom.style.visibility = visible ? "visible" : "hidden";
8450                 }
8451             }else{
8452                 // closure for composites
8453                 var dom = this.dom;
8454                 var visMode = this.visibilityMode;
8455                 if(visible){
8456                     this.setOpacity(.01);
8457                     this.setVisible(true);
8458                 }
8459                 this.anim({opacity: { to: (visible?1:0) }},
8460                       this.preanim(arguments, 1),
8461                       null, .35, 'easeIn', function(){
8462                          if(!visible){
8463                              if(visMode == El.DISPLAY){
8464                                  dom.style.display = "none";
8465                              }else{
8466                                  dom.style.visibility = "hidden";
8467                              }
8468                              Roo.get(dom).setOpacity(1);
8469                          }
8470                      });
8471             }
8472             return this;
8473         },
8474
8475         /**
8476          * Returns true if display is not "none"
8477          * @return {Boolean}
8478          */
8479         isDisplayed : function() {
8480             return this.getStyle("display") != "none";
8481         },
8482
8483         /**
8484          * Toggles the element's visibility or display, depending on visibility mode.
8485          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8486          * @return {Roo.Element} this
8487          */
8488         toggle : function(animate){
8489             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8490             return this;
8491         },
8492
8493         /**
8494          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8495          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8496          * @return {Roo.Element} this
8497          */
8498         setDisplayed : function(value) {
8499             if(typeof value == "boolean"){
8500                value = value ? this.originalDisplay : "none";
8501             }
8502             this.setStyle("display", value);
8503             return this;
8504         },
8505
8506         /**
8507          * Tries to focus the element. Any exceptions are caught and ignored.
8508          * @return {Roo.Element} this
8509          */
8510         focus : function() {
8511             try{
8512                 this.dom.focus();
8513             }catch(e){}
8514             return this;
8515         },
8516
8517         /**
8518          * Tries to blur the element. Any exceptions are caught and ignored.
8519          * @return {Roo.Element} this
8520          */
8521         blur : function() {
8522             try{
8523                 this.dom.blur();
8524             }catch(e){}
8525             return this;
8526         },
8527
8528         /**
8529          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8530          * @param {String/Array} className The CSS class to add, or an array of classes
8531          * @return {Roo.Element} this
8532          */
8533         addClass : function(className){
8534             if(className instanceof Array){
8535                 for(var i = 0, len = className.length; i < len; i++) {
8536                     this.addClass(className[i]);
8537                 }
8538             }else{
8539                 if(className && !this.hasClass(className)){
8540                     if (this.dom instanceof SVGElement) {
8541                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
8542                     } else {
8543                         this.dom.className = this.dom.className + " " + className;
8544                     }
8545                 }
8546             }
8547             return this;
8548         },
8549
8550         /**
8551          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8552          * @param {String/Array} className The CSS class to add, or an array of classes
8553          * @return {Roo.Element} this
8554          */
8555         radioClass : function(className){
8556             var siblings = this.dom.parentNode.childNodes;
8557             for(var i = 0; i < siblings.length; i++) {
8558                 var s = siblings[i];
8559                 if(s.nodeType == 1){
8560                     Roo.get(s).removeClass(className);
8561                 }
8562             }
8563             this.addClass(className);
8564             return this;
8565         },
8566
8567         /**
8568          * Removes one or more CSS classes from the element.
8569          * @param {String/Array} className The CSS class to remove, or an array of classes
8570          * @return {Roo.Element} this
8571          */
8572         removeClass : function(className){
8573             
8574             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8575             if(!className || !cn){
8576                 return this;
8577             }
8578             if(className instanceof Array){
8579                 for(var i = 0, len = className.length; i < len; i++) {
8580                     this.removeClass(className[i]);
8581                 }
8582             }else{
8583                 if(this.hasClass(className)){
8584                     var re = this.classReCache[className];
8585                     if (!re) {
8586                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8587                        this.classReCache[className] = re;
8588                     }
8589                     if (this.dom instanceof SVGElement) {
8590                         this.dom.className.baseVal = cn.replace(re, " ");
8591                     } else {
8592                         this.dom.className = cn.replace(re, " ");
8593                     }
8594                 }
8595             }
8596             return this;
8597         },
8598
8599         // private
8600         classReCache: {},
8601
8602         /**
8603          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8604          * @param {String} className The CSS class to toggle
8605          * @return {Roo.Element} this
8606          */
8607         toggleClass : function(className){
8608             if(this.hasClass(className)){
8609                 this.removeClass(className);
8610             }else{
8611                 this.addClass(className);
8612             }
8613             return this;
8614         },
8615
8616         /**
8617          * Checks if the specified CSS class exists on this element's DOM node.
8618          * @param {String} className The CSS class to check for
8619          * @return {Boolean} True if the class exists, else false
8620          */
8621         hasClass : function(className){
8622             if (this.dom instanceof SVGElement) {
8623                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
8624             } 
8625             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8626         },
8627
8628         /**
8629          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
8630          * @param {String} oldClassName The CSS class to replace
8631          * @param {String} newClassName The replacement CSS class
8632          * @return {Roo.Element} this
8633          */
8634         replaceClass : function(oldClassName, newClassName){
8635             this.removeClass(oldClassName);
8636             this.addClass(newClassName);
8637             return this;
8638         },
8639
8640         /**
8641          * Returns an object with properties matching the styles requested.
8642          * For example, el.getStyles('color', 'font-size', 'width') might return
8643          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8644          * @param {String} style1 A style name
8645          * @param {String} style2 A style name
8646          * @param {String} etc.
8647          * @return {Object} The style object
8648          */
8649         getStyles : function(){
8650             var a = arguments, len = a.length, r = {};
8651             for(var i = 0; i < len; i++){
8652                 r[a[i]] = this.getStyle(a[i]);
8653             }
8654             return r;
8655         },
8656
8657         /**
8658          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8659          * @param {String} property The style property whose value is returned.
8660          * @return {String} The current value of the style property for this element.
8661          */
8662         getStyle : function(){
8663             return view && view.getComputedStyle ?
8664                 function(prop){
8665                     var el = this.dom, v, cs, camel;
8666                     if(prop == 'float'){
8667                         prop = "cssFloat";
8668                     }
8669                     if(el.style && (v = el.style[prop])){
8670                         return v;
8671                     }
8672                     if(cs = view.getComputedStyle(el, "")){
8673                         if(!(camel = propCache[prop])){
8674                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
8675                         }
8676                         return cs[camel];
8677                     }
8678                     return null;
8679                 } :
8680                 function(prop){
8681                     var el = this.dom, v, cs, camel;
8682                     if(prop == 'opacity'){
8683                         if(typeof el.style.filter == 'string'){
8684                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8685                             if(m){
8686                                 var fv = parseFloat(m[1]);
8687                                 if(!isNaN(fv)){
8688                                     return fv ? fv / 100 : 0;
8689                                 }
8690                             }
8691                         }
8692                         return 1;
8693                     }else if(prop == 'float'){
8694                         prop = "styleFloat";
8695                     }
8696                     if(!(camel = propCache[prop])){
8697                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
8698                     }
8699                     if(v = el.style[camel]){
8700                         return v;
8701                     }
8702                     if(cs = el.currentStyle){
8703                         return cs[camel];
8704                     }
8705                     return null;
8706                 };
8707         }(),
8708
8709         /**
8710          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8711          * @param {String/Object} property The style property to be set, or an object of multiple styles.
8712          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8713          * @return {Roo.Element} this
8714          */
8715         setStyle : function(prop, value){
8716             if(typeof prop == "string"){
8717                 
8718                 if (prop == 'float') {
8719                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
8720                     return this;
8721                 }
8722                 
8723                 var camel;
8724                 if(!(camel = propCache[prop])){
8725                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
8726                 }
8727                 
8728                 if(camel == 'opacity') {
8729                     this.setOpacity(value);
8730                 }else{
8731                     this.dom.style[camel] = value;
8732                 }
8733             }else{
8734                 for(var style in prop){
8735                     if(typeof prop[style] != "function"){
8736                        this.setStyle(style, prop[style]);
8737                     }
8738                 }
8739             }
8740             return this;
8741         },
8742
8743         /**
8744          * More flexible version of {@link #setStyle} for setting style properties.
8745          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8746          * a function which returns such a specification.
8747          * @return {Roo.Element} this
8748          */
8749         applyStyles : function(style){
8750             Roo.DomHelper.applyStyles(this.dom, style);
8751             return this;
8752         },
8753
8754         /**
8755           * 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).
8756           * @return {Number} The X position of the element
8757           */
8758         getX : function(){
8759             return D.getX(this.dom);
8760         },
8761
8762         /**
8763           * 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).
8764           * @return {Number} The Y position of the element
8765           */
8766         getY : function(){
8767             return D.getY(this.dom);
8768         },
8769
8770         /**
8771           * 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).
8772           * @return {Array} The XY position of the element
8773           */
8774         getXY : function(){
8775             return D.getXY(this.dom);
8776         },
8777
8778         /**
8779          * 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).
8780          * @param {Number} The X position of the element
8781          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8782          * @return {Roo.Element} this
8783          */
8784         setX : function(x, animate){
8785             if(!animate || !A){
8786                 D.setX(this.dom, x);
8787             }else{
8788                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8789             }
8790             return this;
8791         },
8792
8793         /**
8794          * 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).
8795          * @param {Number} The Y position of the element
8796          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8797          * @return {Roo.Element} this
8798          */
8799         setY : function(y, animate){
8800             if(!animate || !A){
8801                 D.setY(this.dom, y);
8802             }else{
8803                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8804             }
8805             return this;
8806         },
8807
8808         /**
8809          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8810          * @param {String} left The left CSS property value
8811          * @return {Roo.Element} this
8812          */
8813         setLeft : function(left){
8814             this.setStyle("left", this.addUnits(left));
8815             return this;
8816         },
8817
8818         /**
8819          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8820          * @param {String} top The top CSS property value
8821          * @return {Roo.Element} this
8822          */
8823         setTop : function(top){
8824             this.setStyle("top", this.addUnits(top));
8825             return this;
8826         },
8827
8828         /**
8829          * Sets the element's CSS right style.
8830          * @param {String} right The right CSS property value
8831          * @return {Roo.Element} this
8832          */
8833         setRight : function(right){
8834             this.setStyle("right", this.addUnits(right));
8835             return this;
8836         },
8837
8838         /**
8839          * Sets the element's CSS bottom style.
8840          * @param {String} bottom The bottom CSS property value
8841          * @return {Roo.Element} this
8842          */
8843         setBottom : function(bottom){
8844             this.setStyle("bottom", this.addUnits(bottom));
8845             return this;
8846         },
8847
8848         /**
8849          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8850          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8851          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8852          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8853          * @return {Roo.Element} this
8854          */
8855         setXY : function(pos, animate){
8856             if(!animate || !A){
8857                 D.setXY(this.dom, pos);
8858             }else{
8859                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8860             }
8861             return this;
8862         },
8863
8864         /**
8865          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8866          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8867          * @param {Number} x X value for new position (coordinates are page-based)
8868          * @param {Number} y Y value for new position (coordinates are page-based)
8869          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8870          * @return {Roo.Element} this
8871          */
8872         setLocation : function(x, y, animate){
8873             this.setXY([x, y], this.preanim(arguments, 2));
8874             return this;
8875         },
8876
8877         /**
8878          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8879          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8880          * @param {Number} x X value for new position (coordinates are page-based)
8881          * @param {Number} y Y value for new position (coordinates are page-based)
8882          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8883          * @return {Roo.Element} this
8884          */
8885         moveTo : function(x, y, animate){
8886             this.setXY([x, y], this.preanim(arguments, 2));
8887             return this;
8888         },
8889
8890         /**
8891          * Returns the region of the given element.
8892          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8893          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8894          */
8895         getRegion : function(){
8896             return D.getRegion(this.dom);
8897         },
8898
8899         /**
8900          * Returns the offset height of the element
8901          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8902          * @return {Number} The element's height
8903          */
8904         getHeight : function(contentHeight){
8905             var h = this.dom.offsetHeight || 0;
8906             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8907         },
8908
8909         /**
8910          * Returns the offset width of the element
8911          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8912          * @return {Number} The element's width
8913          */
8914         getWidth : function(contentWidth){
8915             var w = this.dom.offsetWidth || 0;
8916             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8917         },
8918
8919         /**
8920          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8921          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8922          * if a height has not been set using CSS.
8923          * @return {Number}
8924          */
8925         getComputedHeight : function(){
8926             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8927             if(!h){
8928                 h = parseInt(this.getStyle('height'), 10) || 0;
8929                 if(!this.isBorderBox()){
8930                     h += this.getFrameWidth('tb');
8931                 }
8932             }
8933             return h;
8934         },
8935
8936         /**
8937          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8938          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8939          * if a width has not been set using CSS.
8940          * @return {Number}
8941          */
8942         getComputedWidth : function(){
8943             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8944             if(!w){
8945                 w = parseInt(this.getStyle('width'), 10) || 0;
8946                 if(!this.isBorderBox()){
8947                     w += this.getFrameWidth('lr');
8948                 }
8949             }
8950             return w;
8951         },
8952
8953         /**
8954          * Returns the size of the element.
8955          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8956          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8957          */
8958         getSize : function(contentSize){
8959             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8960         },
8961
8962         /**
8963          * Returns the width and height of the viewport.
8964          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8965          */
8966         getViewSize : function(){
8967             var d = this.dom, doc = document, aw = 0, ah = 0;
8968             if(d == doc || d == doc.body){
8969                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8970             }else{
8971                 return {
8972                     width : d.clientWidth,
8973                     height: d.clientHeight
8974                 };
8975             }
8976         },
8977
8978         /**
8979          * Returns the value of the "value" attribute
8980          * @param {Boolean} asNumber true to parse the value as a number
8981          * @return {String/Number}
8982          */
8983         getValue : function(asNumber){
8984             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8985         },
8986
8987         // private
8988         adjustWidth : function(width){
8989             if(typeof width == "number"){
8990                 if(this.autoBoxAdjust && !this.isBorderBox()){
8991                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8992                 }
8993                 if(width < 0){
8994                     width = 0;
8995                 }
8996             }
8997             return width;
8998         },
8999
9000         // private
9001         adjustHeight : function(height){
9002             if(typeof height == "number"){
9003                if(this.autoBoxAdjust && !this.isBorderBox()){
9004                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9005                }
9006                if(height < 0){
9007                    height = 0;
9008                }
9009             }
9010             return height;
9011         },
9012
9013         /**
9014          * Set the width of the element
9015          * @param {Number} width The new width
9016          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9017          * @return {Roo.Element} this
9018          */
9019         setWidth : function(width, animate){
9020             width = this.adjustWidth(width);
9021             if(!animate || !A){
9022                 this.dom.style.width = this.addUnits(width);
9023             }else{
9024                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9025             }
9026             return this;
9027         },
9028
9029         /**
9030          * Set the height of the element
9031          * @param {Number} height The new height
9032          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9033          * @return {Roo.Element} this
9034          */
9035          setHeight : function(height, animate){
9036             height = this.adjustHeight(height);
9037             if(!animate || !A){
9038                 this.dom.style.height = this.addUnits(height);
9039             }else{
9040                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9041             }
9042             return this;
9043         },
9044
9045         /**
9046          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9047          * @param {Number} width The new width
9048          * @param {Number} height The new height
9049          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9050          * @return {Roo.Element} this
9051          */
9052          setSize : function(width, height, animate){
9053             if(typeof width == "object"){ // in case of object from getSize()
9054                 height = width.height; width = width.width;
9055             }
9056             width = this.adjustWidth(width); height = this.adjustHeight(height);
9057             if(!animate || !A){
9058                 this.dom.style.width = this.addUnits(width);
9059                 this.dom.style.height = this.addUnits(height);
9060             }else{
9061                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9062             }
9063             return this;
9064         },
9065
9066         /**
9067          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9068          * @param {Number} x X value for new position (coordinates are page-based)
9069          * @param {Number} y Y value for new position (coordinates are page-based)
9070          * @param {Number} width The new width
9071          * @param {Number} height The new height
9072          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9073          * @return {Roo.Element} this
9074          */
9075         setBounds : function(x, y, width, height, animate){
9076             if(!animate || !A){
9077                 this.setSize(width, height);
9078                 this.setLocation(x, y);
9079             }else{
9080                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9081                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9082                               this.preanim(arguments, 4), 'motion');
9083             }
9084             return this;
9085         },
9086
9087         /**
9088          * 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.
9089          * @param {Roo.lib.Region} region The region to fill
9090          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9091          * @return {Roo.Element} this
9092          */
9093         setRegion : function(region, animate){
9094             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9095             return this;
9096         },
9097
9098         /**
9099          * Appends an event handler
9100          *
9101          * @param {String}   eventName     The type of event to append
9102          * @param {Function} fn        The method the event invokes
9103          * @param {Object} scope       (optional) The scope (this object) of the fn
9104          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9105          */
9106         addListener : function(eventName, fn, scope, options)
9107         {
9108             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9109                 this.addListener('touchstart', this.onTapHandler, this);
9110             }
9111             
9112             // we need to handle a special case where dom element is a svg element.
9113             // in this case we do not actua
9114             if (!this.dom) {
9115                 return;
9116             }
9117             
9118             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9119                 if (typeof(this.listeners[eventName]) == 'undefined') {
9120                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9121                 }
9122                 this.listeners[eventName].addListener(fn, scope, options);
9123                 return;
9124             }
9125             
9126                 
9127             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9128             
9129             
9130         },
9131         tapedTwice : false,
9132         onTapHandler : function(event)
9133         {
9134             if(!this.tapedTwice) {
9135                 this.tapedTwice = true;
9136                 var s = this;
9137                 setTimeout( function() {
9138                     s.tapedTwice = false;
9139                 }, 300 );
9140                 return;
9141             }
9142             event.preventDefault();
9143             var revent = new MouseEvent('dblclick',  {
9144                 view: window,
9145                 bubbles: true,
9146                 cancelable: true
9147             });
9148              
9149             this.dom.dispatchEvent(revent);
9150             //action on double tap goes below
9151              
9152         }, 
9153  
9154         /**
9155          * Removes an event handler from this element
9156          * @param {String} eventName the type of event to remove
9157          * @param {Function} fn the method the event invokes
9158          * @param {Function} scope (needed for svg fake listeners)
9159          * @return {Roo.Element} this
9160          */
9161         removeListener : function(eventName, fn, scope){
9162             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9163             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9164                 return this;
9165             }
9166             this.listeners[eventName].removeListener(fn, scope);
9167             return this;
9168         },
9169
9170         /**
9171          * Removes all previous added listeners from this element
9172          * @return {Roo.Element} this
9173          */
9174         removeAllListeners : function(){
9175             E.purgeElement(this.dom);
9176             this.listeners = {};
9177             return this;
9178         },
9179
9180         relayEvent : function(eventName, observable){
9181             this.on(eventName, function(e){
9182                 observable.fireEvent(eventName, e);
9183             });
9184         },
9185
9186         
9187         /**
9188          * Set the opacity of the element
9189          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9190          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9191          * @return {Roo.Element} this
9192          */
9193          setOpacity : function(opacity, animate){
9194             if(!animate || !A){
9195                 var s = this.dom.style;
9196                 if(Roo.isIE){
9197                     s.zoom = 1;
9198                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9199                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9200                 }else{
9201                     s.opacity = opacity;
9202                 }
9203             }else{
9204                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9205             }
9206             return this;
9207         },
9208
9209         /**
9210          * Gets the left X coordinate
9211          * @param {Boolean} local True to get the local css position instead of page coordinate
9212          * @return {Number}
9213          */
9214         getLeft : function(local){
9215             if(!local){
9216                 return this.getX();
9217             }else{
9218                 return parseInt(this.getStyle("left"), 10) || 0;
9219             }
9220         },
9221
9222         /**
9223          * Gets the right X coordinate of the element (element X position + element width)
9224          * @param {Boolean} local True to get the local css position instead of page coordinate
9225          * @return {Number}
9226          */
9227         getRight : function(local){
9228             if(!local){
9229                 return this.getX() + this.getWidth();
9230             }else{
9231                 return (this.getLeft(true) + this.getWidth()) || 0;
9232             }
9233         },
9234
9235         /**
9236          * Gets the top Y coordinate
9237          * @param {Boolean} local True to get the local css position instead of page coordinate
9238          * @return {Number}
9239          */
9240         getTop : function(local) {
9241             if(!local){
9242                 return this.getY();
9243             }else{
9244                 return parseInt(this.getStyle("top"), 10) || 0;
9245             }
9246         },
9247
9248         /**
9249          * Gets the bottom Y coordinate of the element (element Y position + element height)
9250          * @param {Boolean} local True to get the local css position instead of page coordinate
9251          * @return {Number}
9252          */
9253         getBottom : function(local){
9254             if(!local){
9255                 return this.getY() + this.getHeight();
9256             }else{
9257                 return (this.getTop(true) + this.getHeight()) || 0;
9258             }
9259         },
9260
9261         /**
9262         * Initializes positioning on this element. If a desired position is not passed, it will make the
9263         * the element positioned relative IF it is not already positioned.
9264         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9265         * @param {Number} zIndex (optional) The zIndex to apply
9266         * @param {Number} x (optional) Set the page X position
9267         * @param {Number} y (optional) Set the page Y position
9268         */
9269         position : function(pos, zIndex, x, y){
9270             if(!pos){
9271                if(this.getStyle('position') == 'static'){
9272                    this.setStyle('position', 'relative');
9273                }
9274             }else{
9275                 this.setStyle("position", pos);
9276             }
9277             if(zIndex){
9278                 this.setStyle("z-index", zIndex);
9279             }
9280             if(x !== undefined && y !== undefined){
9281                 this.setXY([x, y]);
9282             }else if(x !== undefined){
9283                 this.setX(x);
9284             }else if(y !== undefined){
9285                 this.setY(y);
9286             }
9287         },
9288
9289         /**
9290         * Clear positioning back to the default when the document was loaded
9291         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9292         * @return {Roo.Element} this
9293          */
9294         clearPositioning : function(value){
9295             value = value ||'';
9296             this.setStyle({
9297                 "left": value,
9298                 "right": value,
9299                 "top": value,
9300                 "bottom": value,
9301                 "z-index": "",
9302                 "position" : "static"
9303             });
9304             return this;
9305         },
9306
9307         /**
9308         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9309         * snapshot before performing an update and then restoring the element.
9310         * @return {Object}
9311         */
9312         getPositioning : function(){
9313             var l = this.getStyle("left");
9314             var t = this.getStyle("top");
9315             return {
9316                 "position" : this.getStyle("position"),
9317                 "left" : l,
9318                 "right" : l ? "" : this.getStyle("right"),
9319                 "top" : t,
9320                 "bottom" : t ? "" : this.getStyle("bottom"),
9321                 "z-index" : this.getStyle("z-index")
9322             };
9323         },
9324
9325         /**
9326          * Gets the width of the border(s) for the specified side(s)
9327          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9328          * passing lr would get the border (l)eft width + the border (r)ight width.
9329          * @return {Number} The width of the sides passed added together
9330          */
9331         getBorderWidth : function(side){
9332             return this.addStyles(side, El.borders);
9333         },
9334
9335         /**
9336          * Gets the width of the padding(s) for the specified side(s)
9337          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9338          * passing lr would get the padding (l)eft + the padding (r)ight.
9339          * @return {Number} The padding of the sides passed added together
9340          */
9341         getPadding : function(side){
9342             return this.addStyles(side, El.paddings);
9343         },
9344
9345         /**
9346         * Set positioning with an object returned by getPositioning().
9347         * @param {Object} posCfg
9348         * @return {Roo.Element} this
9349          */
9350         setPositioning : function(pc){
9351             this.applyStyles(pc);
9352             if(pc.right == "auto"){
9353                 this.dom.style.right = "";
9354             }
9355             if(pc.bottom == "auto"){
9356                 this.dom.style.bottom = "";
9357             }
9358             return this;
9359         },
9360
9361         // private
9362         fixDisplay : function(){
9363             if(this.getStyle("display") == "none"){
9364                 this.setStyle("visibility", "hidden");
9365                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9366                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9367                     this.setStyle("display", "block");
9368                 }
9369             }
9370         },
9371
9372         /**
9373          * Quick set left and top adding default units
9374          * @param {String} left The left CSS property value
9375          * @param {String} top The top CSS property value
9376          * @return {Roo.Element} this
9377          */
9378          setLeftTop : function(left, top){
9379             this.dom.style.left = this.addUnits(left);
9380             this.dom.style.top = this.addUnits(top);
9381             return this;
9382         },
9383
9384         /**
9385          * Move this element relative to its current position.
9386          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9387          * @param {Number} distance How far to move the element in pixels
9388          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9389          * @return {Roo.Element} this
9390          */
9391          move : function(direction, distance, animate){
9392             var xy = this.getXY();
9393             direction = direction.toLowerCase();
9394             switch(direction){
9395                 case "l":
9396                 case "left":
9397                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9398                     break;
9399                case "r":
9400                case "right":
9401                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9402                     break;
9403                case "t":
9404                case "top":
9405                case "up":
9406                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9407                     break;
9408                case "b":
9409                case "bottom":
9410                case "down":
9411                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9412                     break;
9413             }
9414             return this;
9415         },
9416
9417         /**
9418          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9419          * @return {Roo.Element} this
9420          */
9421         clip : function(){
9422             if(!this.isClipped){
9423                this.isClipped = true;
9424                this.originalClip = {
9425                    "o": this.getStyle("overflow"),
9426                    "x": this.getStyle("overflow-x"),
9427                    "y": this.getStyle("overflow-y")
9428                };
9429                this.setStyle("overflow", "hidden");
9430                this.setStyle("overflow-x", "hidden");
9431                this.setStyle("overflow-y", "hidden");
9432             }
9433             return this;
9434         },
9435
9436         /**
9437          *  Return clipping (overflow) to original clipping before clip() was called
9438          * @return {Roo.Element} this
9439          */
9440         unclip : function(){
9441             if(this.isClipped){
9442                 this.isClipped = false;
9443                 var o = this.originalClip;
9444                 if(o.o){this.setStyle("overflow", o.o);}
9445                 if(o.x){this.setStyle("overflow-x", o.x);}
9446                 if(o.y){this.setStyle("overflow-y", o.y);}
9447             }
9448             return this;
9449         },
9450
9451
9452         /**
9453          * Gets the x,y coordinates specified by the anchor position on the element.
9454          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9455          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9456          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9457          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9458          * @return {Array} [x, y] An array containing the element's x and y coordinates
9459          */
9460         getAnchorXY : function(anchor, local, s){
9461             //Passing a different size is useful for pre-calculating anchors,
9462             //especially for anchored animations that change the el size.
9463
9464             var w, h, vp = false;
9465             if(!s){
9466                 var d = this.dom;
9467                 if(d == document.body || d == document){
9468                     vp = true;
9469                     w = D.getViewWidth(); h = D.getViewHeight();
9470                 }else{
9471                     w = this.getWidth(); h = this.getHeight();
9472                 }
9473             }else{
9474                 w = s.width;  h = s.height;
9475             }
9476             var x = 0, y = 0, r = Math.round;
9477             switch((anchor || "tl").toLowerCase()){
9478                 case "c":
9479                     x = r(w*.5);
9480                     y = r(h*.5);
9481                 break;
9482                 case "t":
9483                     x = r(w*.5);
9484                     y = 0;
9485                 break;
9486                 case "l":
9487                     x = 0;
9488                     y = r(h*.5);
9489                 break;
9490                 case "r":
9491                     x = w;
9492                     y = r(h*.5);
9493                 break;
9494                 case "b":
9495                     x = r(w*.5);
9496                     y = h;
9497                 break;
9498                 case "tl":
9499                     x = 0;
9500                     y = 0;
9501                 break;
9502                 case "bl":
9503                     x = 0;
9504                     y = h;
9505                 break;
9506                 case "br":
9507                     x = w;
9508                     y = h;
9509                 break;
9510                 case "tr":
9511                     x = w;
9512                     y = 0;
9513                 break;
9514             }
9515             if(local === true){
9516                 return [x, y];
9517             }
9518             if(vp){
9519                 var sc = this.getScroll();
9520                 return [x + sc.left, y + sc.top];
9521             }
9522             //Add the element's offset xy
9523             var o = this.getXY();
9524             return [x+o[0], y+o[1]];
9525         },
9526
9527         /**
9528          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9529          * supported position values.
9530          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9531          * @param {String} position The position to align to.
9532          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9533          * @return {Array} [x, y]
9534          */
9535         getAlignToXY : function(el, p, o)
9536         {
9537             el = Roo.get(el);
9538             var d = this.dom;
9539             if(!el.dom){
9540                 throw "Element.alignTo with an element that doesn't exist";
9541             }
9542             var c = false; //constrain to viewport
9543             var p1 = "", p2 = "";
9544             o = o || [0,0];
9545
9546             if(!p){
9547                 p = "tl-bl";
9548             }else if(p == "?"){
9549                 p = "tl-bl?";
9550             }else if(p.indexOf("-") == -1){
9551                 p = "tl-" + p;
9552             }
9553             p = p.toLowerCase();
9554             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9555             if(!m){
9556                throw "Element.alignTo with an invalid alignment " + p;
9557             }
9558             p1 = m[1]; p2 = m[2]; c = !!m[3];
9559
9560             //Subtract the aligned el's internal xy from the target's offset xy
9561             //plus custom offset to get the aligned el's new offset xy
9562             var a1 = this.getAnchorXY(p1, true);
9563             var a2 = el.getAnchorXY(p2, false);
9564             var x = a2[0] - a1[0] + o[0];
9565             var y = a2[1] - a1[1] + o[1];
9566             if(c){
9567                 //constrain the aligned el to viewport if necessary
9568                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9569                 // 5px of margin for ie
9570                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9571
9572                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9573                 //perpendicular to the vp border, allow the aligned el to slide on that border,
9574                 //otherwise swap the aligned el to the opposite border of the target.
9575                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9576                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9577                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
9578                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9579
9580                var doc = document;
9581                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9582                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9583
9584                if((x+w) > dw + scrollX){
9585                     x = swapX ? r.left-w : dw+scrollX-w;
9586                 }
9587                if(x < scrollX){
9588                    x = swapX ? r.right : scrollX;
9589                }
9590                if((y+h) > dh + scrollY){
9591                     y = swapY ? r.top-h : dh+scrollY-h;
9592                 }
9593                if (y < scrollY){
9594                    y = swapY ? r.bottom : scrollY;
9595                }
9596             }
9597             return [x,y];
9598         },
9599
9600         // private
9601         getConstrainToXY : function(){
9602             var os = {top:0, left:0, bottom:0, right: 0};
9603
9604             return function(el, local, offsets, proposedXY){
9605                 el = Roo.get(el);
9606                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9607
9608                 var vw, vh, vx = 0, vy = 0;
9609                 if(el.dom == document.body || el.dom == document){
9610                     vw = Roo.lib.Dom.getViewWidth();
9611                     vh = Roo.lib.Dom.getViewHeight();
9612                 }else{
9613                     vw = el.dom.clientWidth;
9614                     vh = el.dom.clientHeight;
9615                     if(!local){
9616                         var vxy = el.getXY();
9617                         vx = vxy[0];
9618                         vy = vxy[1];
9619                     }
9620                 }
9621
9622                 var s = el.getScroll();
9623
9624                 vx += offsets.left + s.left;
9625                 vy += offsets.top + s.top;
9626
9627                 vw -= offsets.right;
9628                 vh -= offsets.bottom;
9629
9630                 var vr = vx+vw;
9631                 var vb = vy+vh;
9632
9633                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9634                 var x = xy[0], y = xy[1];
9635                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9636
9637                 // only move it if it needs it
9638                 var moved = false;
9639
9640                 // first validate right/bottom
9641                 if((x + w) > vr){
9642                     x = vr - w;
9643                     moved = true;
9644                 }
9645                 if((y + h) > vb){
9646                     y = vb - h;
9647                     moved = true;
9648                 }
9649                 // then make sure top/left isn't negative
9650                 if(x < vx){
9651                     x = vx;
9652                     moved = true;
9653                 }
9654                 if(y < vy){
9655                     y = vy;
9656                     moved = true;
9657                 }
9658                 return moved ? [x, y] : false;
9659             };
9660         }(),
9661
9662         // private
9663         adjustForConstraints : function(xy, parent, offsets){
9664             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
9665         },
9666
9667         /**
9668          * Aligns this element with another element relative to the specified anchor points. If the other element is the
9669          * document it aligns it to the viewport.
9670          * The position parameter is optional, and can be specified in any one of the following formats:
9671          * <ul>
9672          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9673          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9674          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
9675          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
9676          *   <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
9677          *       element's anchor point, and the second value is used as the target's anchor point.</li>
9678          * </ul>
9679          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
9680          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9681          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
9682          * that specified in order to enforce the viewport constraints.
9683          * Following are all of the supported anchor positions:
9684     <pre>
9685     Value  Description
9686     -----  -----------------------------
9687     tl     The top left corner (default)
9688     t      The center of the top edge
9689     tr     The top right corner
9690     l      The center of the left edge
9691     c      In the center of the element
9692     r      The center of the right edge
9693     bl     The bottom left corner
9694     b      The center of the bottom edge
9695     br     The bottom right corner
9696     </pre>
9697     Example Usage:
9698     <pre><code>
9699     // align el to other-el using the default positioning ("tl-bl", non-constrained)
9700     el.alignTo("other-el");
9701
9702     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9703     el.alignTo("other-el", "tr?");
9704
9705     // align the bottom right corner of el with the center left edge of other-el
9706     el.alignTo("other-el", "br-l?");
9707
9708     // align the center of el with the bottom left corner of other-el and
9709     // adjust the x position by -6 pixels (and the y position by 0)
9710     el.alignTo("other-el", "c-bl", [-6, 0]);
9711     </code></pre>
9712          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9713          * @param {String} position The position to align to.
9714          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9715          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9716          * @return {Roo.Element} this
9717          */
9718         alignTo : function(element, position, offsets, animate){
9719             var xy = this.getAlignToXY(element, position, offsets);
9720             this.setXY(xy, this.preanim(arguments, 3));
9721             return this;
9722         },
9723
9724         /**
9725          * Anchors an element to another element and realigns it when the window is resized.
9726          * @param {String/HTMLElement/Roo.Element} element The element to align to.
9727          * @param {String} position The position to align to.
9728          * @param {Array} offsets (optional) Offset the positioning by [x, y]
9729          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9730          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9731          * is a number, it is used as the buffer delay (defaults to 50ms).
9732          * @param {Function} callback The function to call after the animation finishes
9733          * @return {Roo.Element} this
9734          */
9735         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9736             var action = function(){
9737                 this.alignTo(el, alignment, offsets, animate);
9738                 Roo.callback(callback, this);
9739             };
9740             Roo.EventManager.onWindowResize(action, this);
9741             var tm = typeof monitorScroll;
9742             if(tm != 'undefined'){
9743                 Roo.EventManager.on(window, 'scroll', action, this,
9744                     {buffer: tm == 'number' ? monitorScroll : 50});
9745             }
9746             action.call(this); // align immediately
9747             return this;
9748         },
9749         /**
9750          * Clears any opacity settings from this element. Required in some cases for IE.
9751          * @return {Roo.Element} this
9752          */
9753         clearOpacity : function(){
9754             if (window.ActiveXObject) {
9755                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9756                     this.dom.style.filter = "";
9757                 }
9758             } else {
9759                 this.dom.style.opacity = "";
9760                 this.dom.style["-moz-opacity"] = "";
9761                 this.dom.style["-khtml-opacity"] = "";
9762             }
9763             return this;
9764         },
9765
9766         /**
9767          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9768          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9769          * @return {Roo.Element} this
9770          */
9771         hide : function(animate){
9772             this.setVisible(false, this.preanim(arguments, 0));
9773             return this;
9774         },
9775
9776         /**
9777         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9778         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9779          * @return {Roo.Element} this
9780          */
9781         show : function(animate){
9782             this.setVisible(true, this.preanim(arguments, 0));
9783             return this;
9784         },
9785
9786         /**
9787          * @private Test if size has a unit, otherwise appends the default
9788          */
9789         addUnits : function(size){
9790             return Roo.Element.addUnits(size, this.defaultUnit);
9791         },
9792
9793         /**
9794          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9795          * @return {Roo.Element} this
9796          */
9797         beginMeasure : function(){
9798             var el = this.dom;
9799             if(el.offsetWidth || el.offsetHeight){
9800                 return this; // offsets work already
9801             }
9802             var changed = [];
9803             var p = this.dom, b = document.body; // start with this element
9804             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9805                 var pe = Roo.get(p);
9806                 if(pe.getStyle('display') == 'none'){
9807                     changed.push({el: p, visibility: pe.getStyle("visibility")});
9808                     p.style.visibility = "hidden";
9809                     p.style.display = "block";
9810                 }
9811                 p = p.parentNode;
9812             }
9813             this._measureChanged = changed;
9814             return this;
9815
9816         },
9817
9818         /**
9819          * Restores displays to before beginMeasure was called
9820          * @return {Roo.Element} this
9821          */
9822         endMeasure : function(){
9823             var changed = this._measureChanged;
9824             if(changed){
9825                 for(var i = 0, len = changed.length; i < len; i++) {
9826                     var r = changed[i];
9827                     r.el.style.visibility = r.visibility;
9828                     r.el.style.display = "none";
9829                 }
9830                 this._measureChanged = null;
9831             }
9832             return this;
9833         },
9834
9835         /**
9836         * Update the innerHTML of this element, optionally searching for and processing scripts
9837         * @param {String} html The new HTML
9838         * @param {Boolean} loadScripts (optional) true to look for and process scripts
9839         * @param {Function} callback For async script loading you can be noticed when the update completes
9840         * @return {Roo.Element} this
9841          */
9842         update : function(html, loadScripts, callback){
9843             if(typeof html == "undefined"){
9844                 html = "";
9845             }
9846             if(loadScripts !== true){
9847                 this.dom.innerHTML = html;
9848                 if(typeof callback == "function"){
9849                     callback();
9850                 }
9851                 return this;
9852             }
9853             var id = Roo.id();
9854             var dom = this.dom;
9855
9856             html += '<span id="' + id + '"></span>';
9857
9858             E.onAvailable(id, function(){
9859                 var hd = document.getElementsByTagName("head")[0];
9860                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9861                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9862                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9863
9864                 var match;
9865                 while(match = re.exec(html)){
9866                     var attrs = match[1];
9867                     var srcMatch = attrs ? attrs.match(srcRe) : false;
9868                     if(srcMatch && srcMatch[2]){
9869                        var s = document.createElement("script");
9870                        s.src = srcMatch[2];
9871                        var typeMatch = attrs.match(typeRe);
9872                        if(typeMatch && typeMatch[2]){
9873                            s.type = typeMatch[2];
9874                        }
9875                        hd.appendChild(s);
9876                     }else if(match[2] && match[2].length > 0){
9877                         if(window.execScript) {
9878                            window.execScript(match[2]);
9879                         } else {
9880                             /**
9881                              * eval:var:id
9882                              * eval:var:dom
9883                              * eval:var:html
9884                              * 
9885                              */
9886                            window.eval(match[2]);
9887                         }
9888                     }
9889                 }
9890                 var el = document.getElementById(id);
9891                 if(el){el.parentNode.removeChild(el);}
9892                 if(typeof callback == "function"){
9893                     callback();
9894                 }
9895             });
9896             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9897             return this;
9898         },
9899
9900         /**
9901          * Direct access to the UpdateManager update() method (takes the same parameters).
9902          * @param {String/Function} url The url for this request or a function to call to get the url
9903          * @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}
9904          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9905          * @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.
9906          * @return {Roo.Element} this
9907          */
9908         load : function(){
9909             var um = this.getUpdateManager();
9910             um.update.apply(um, arguments);
9911             return this;
9912         },
9913
9914         /**
9915         * Gets this element's UpdateManager
9916         * @return {Roo.UpdateManager} The UpdateManager
9917         */
9918         getUpdateManager : function(){
9919             if(!this.updateManager){
9920                 this.updateManager = new Roo.UpdateManager(this);
9921             }
9922             return this.updateManager;
9923         },
9924
9925         /**
9926          * Disables text selection for this element (normalized across browsers)
9927          * @return {Roo.Element} this
9928          */
9929         unselectable : function(){
9930             this.dom.unselectable = "on";
9931             this.swallowEvent("selectstart", true);
9932             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9933             this.addClass("x-unselectable");
9934             return this;
9935         },
9936
9937         /**
9938         * Calculates the x, y to center this element on the screen
9939         * @return {Array} The x, y values [x, y]
9940         */
9941         getCenterXY : function(){
9942             return this.getAlignToXY(document, 'c-c');
9943         },
9944
9945         /**
9946         * Centers the Element in either the viewport, or another Element.
9947         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9948         */
9949         center : function(centerIn){
9950             this.alignTo(centerIn || document, 'c-c');
9951             return this;
9952         },
9953
9954         /**
9955          * Tests various css rules/browsers to determine if this element uses a border box
9956          * @return {Boolean}
9957          */
9958         isBorderBox : function(){
9959             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9960         },
9961
9962         /**
9963          * Return a box {x, y, width, height} that can be used to set another elements
9964          * size/location to match this element.
9965          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9966          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9967          * @return {Object} box An object in the format {x, y, width, height}
9968          */
9969         getBox : function(contentBox, local){
9970             var xy;
9971             if(!local){
9972                 xy = this.getXY();
9973             }else{
9974                 var left = parseInt(this.getStyle("left"), 10) || 0;
9975                 var top = parseInt(this.getStyle("top"), 10) || 0;
9976                 xy = [left, top];
9977             }
9978             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9979             if(!contentBox){
9980                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9981             }else{
9982                 var l = this.getBorderWidth("l")+this.getPadding("l");
9983                 var r = this.getBorderWidth("r")+this.getPadding("r");
9984                 var t = this.getBorderWidth("t")+this.getPadding("t");
9985                 var b = this.getBorderWidth("b")+this.getPadding("b");
9986                 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)};
9987             }
9988             bx.right = bx.x + bx.width;
9989             bx.bottom = bx.y + bx.height;
9990             return bx;
9991         },
9992
9993         /**
9994          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9995          for more information about the sides.
9996          * @param {String} sides
9997          * @return {Number}
9998          */
9999         getFrameWidth : function(sides, onlyContentBox){
10000             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10001         },
10002
10003         /**
10004          * 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.
10005          * @param {Object} box The box to fill {x, y, width, height}
10006          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10007          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10008          * @return {Roo.Element} this
10009          */
10010         setBox : function(box, adjust, animate){
10011             var w = box.width, h = box.height;
10012             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10013                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10014                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10015             }
10016             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10017             return this;
10018         },
10019
10020         /**
10021          * Forces the browser to repaint this element
10022          * @return {Roo.Element} this
10023          */
10024          repaint : function(){
10025             var dom = this.dom;
10026             this.addClass("x-repaint");
10027             setTimeout(function(){
10028                 Roo.get(dom).removeClass("x-repaint");
10029             }, 1);
10030             return this;
10031         },
10032
10033         /**
10034          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10035          * then it returns the calculated width of the sides (see getPadding)
10036          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10037          * @return {Object/Number}
10038          */
10039         getMargins : function(side){
10040             if(!side){
10041                 return {
10042                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10043                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10044                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10045                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10046                 };
10047             }else{
10048                 return this.addStyles(side, El.margins);
10049              }
10050         },
10051
10052         // private
10053         addStyles : function(sides, styles){
10054             var val = 0, v, w;
10055             for(var i = 0, len = sides.length; i < len; i++){
10056                 v = this.getStyle(styles[sides.charAt(i)]);
10057                 if(v){
10058                      w = parseInt(v, 10);
10059                      if(w){ val += w; }
10060                 }
10061             }
10062             return val;
10063         },
10064
10065         /**
10066          * Creates a proxy element of this element
10067          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10068          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10069          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10070          * @return {Roo.Element} The new proxy element
10071          */
10072         createProxy : function(config, renderTo, matchBox){
10073             if(renderTo){
10074                 renderTo = Roo.getDom(renderTo);
10075             }else{
10076                 renderTo = document.body;
10077             }
10078             config = typeof config == "object" ?
10079                 config : {tag : "div", cls: config};
10080             var proxy = Roo.DomHelper.append(renderTo, config, true);
10081             if(matchBox){
10082                proxy.setBox(this.getBox());
10083             }
10084             return proxy;
10085         },
10086
10087         /**
10088          * Puts a mask over this element to disable user interaction. Requires core.css.
10089          * This method can only be applied to elements which accept child nodes.
10090          * @param {String} msg (optional) A message to display in the mask
10091          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10092          * @return {Element} The mask  element
10093          */
10094         mask : function(msg, msgCls)
10095         {
10096             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10097                 this.setStyle("position", "relative");
10098             }
10099             if(!this._mask){
10100                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10101             }
10102             
10103             this.addClass("x-masked");
10104             this._mask.setDisplayed(true);
10105             
10106             // we wander
10107             var z = 0;
10108             var dom = this.dom;
10109             while (dom && dom.style) {
10110                 if (!isNaN(parseInt(dom.style.zIndex))) {
10111                     z = Math.max(z, parseInt(dom.style.zIndex));
10112                 }
10113                 dom = dom.parentNode;
10114             }
10115             // if we are masking the body - then it hides everything..
10116             if (this.dom == document.body) {
10117                 z = 1000000;
10118                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10119                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10120             }
10121            
10122             if(typeof msg == 'string'){
10123                 if(!this._maskMsg){
10124                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10125                         cls: "roo-el-mask-msg", 
10126                         cn: [
10127                             {
10128                                 tag: 'i',
10129                                 cls: 'fa fa-spinner fa-spin'
10130                             },
10131                             {
10132                                 tag: 'div'
10133                             }   
10134                         ]
10135                     }, true);
10136                 }
10137                 var mm = this._maskMsg;
10138                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10139                 if (mm.dom.lastChild) { // weird IE issue?
10140                     mm.dom.lastChild.innerHTML = msg;
10141                 }
10142                 mm.setDisplayed(true);
10143                 mm.center(this);
10144                 mm.setStyle('z-index', z + 102);
10145             }
10146             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10147                 this._mask.setHeight(this.getHeight());
10148             }
10149             this._mask.setStyle('z-index', z + 100);
10150             
10151             return this._mask;
10152         },
10153
10154         /**
10155          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10156          * it is cached for reuse.
10157          */
10158         unmask : function(removeEl){
10159             if(this._mask){
10160                 if(removeEl === true){
10161                     this._mask.remove();
10162                     delete this._mask;
10163                     if(this._maskMsg){
10164                         this._maskMsg.remove();
10165                         delete this._maskMsg;
10166                     }
10167                 }else{
10168                     this._mask.setDisplayed(false);
10169                     if(this._maskMsg){
10170                         this._maskMsg.setDisplayed(false);
10171                     }
10172                 }
10173             }
10174             this.removeClass("x-masked");
10175         },
10176
10177         /**
10178          * Returns true if this element is masked
10179          * @return {Boolean}
10180          */
10181         isMasked : function(){
10182             return this._mask && this._mask.isVisible();
10183         },
10184
10185         /**
10186          * Creates an iframe shim for this element to keep selects and other windowed objects from
10187          * showing through.
10188          * @return {Roo.Element} The new shim element
10189          */
10190         createShim : function(){
10191             var el = document.createElement('iframe');
10192             el.frameBorder = 'no';
10193             el.className = 'roo-shim';
10194             if(Roo.isIE && Roo.isSecure){
10195                 el.src = Roo.SSL_SECURE_URL;
10196             }
10197             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10198             shim.autoBoxAdjust = false;
10199             return shim;
10200         },
10201
10202         /**
10203          * Removes this element from the DOM and deletes it from the cache
10204          */
10205         remove : function(){
10206             if(this.dom.parentNode){
10207                 this.dom.parentNode.removeChild(this.dom);
10208             }
10209             delete El.cache[this.dom.id];
10210         },
10211
10212         /**
10213          * Sets up event handlers to add and remove a css class when the mouse is over this element
10214          * @param {String} className
10215          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10216          * mouseout events for children elements
10217          * @return {Roo.Element} this
10218          */
10219         addClassOnOver : function(className, preventFlicker){
10220             this.on("mouseover", function(){
10221                 Roo.fly(this, '_internal').addClass(className);
10222             }, this.dom);
10223             var removeFn = function(e){
10224                 if(preventFlicker !== true || !e.within(this, true)){
10225                     Roo.fly(this, '_internal').removeClass(className);
10226                 }
10227             };
10228             this.on("mouseout", removeFn, this.dom);
10229             return this;
10230         },
10231
10232         /**
10233          * Sets up event handlers to add and remove a css class when this element has the focus
10234          * @param {String} className
10235          * @return {Roo.Element} this
10236          */
10237         addClassOnFocus : function(className){
10238             this.on("focus", function(){
10239                 Roo.fly(this, '_internal').addClass(className);
10240             }, this.dom);
10241             this.on("blur", function(){
10242                 Roo.fly(this, '_internal').removeClass(className);
10243             }, this.dom);
10244             return this;
10245         },
10246         /**
10247          * 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)
10248          * @param {String} className
10249          * @return {Roo.Element} this
10250          */
10251         addClassOnClick : function(className){
10252             var dom = this.dom;
10253             this.on("mousedown", function(){
10254                 Roo.fly(dom, '_internal').addClass(className);
10255                 var d = Roo.get(document);
10256                 var fn = function(){
10257                     Roo.fly(dom, '_internal').removeClass(className);
10258                     d.removeListener("mouseup", fn);
10259                 };
10260                 d.on("mouseup", fn);
10261             });
10262             return this;
10263         },
10264
10265         /**
10266          * Stops the specified event from bubbling and optionally prevents the default action
10267          * @param {String} eventName
10268          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10269          * @return {Roo.Element} this
10270          */
10271         swallowEvent : function(eventName, preventDefault){
10272             var fn = function(e){
10273                 e.stopPropagation();
10274                 if(preventDefault){
10275                     e.preventDefault();
10276                 }
10277             };
10278             if(eventName instanceof Array){
10279                 for(var i = 0, len = eventName.length; i < len; i++){
10280                      this.on(eventName[i], fn);
10281                 }
10282                 return this;
10283             }
10284             this.on(eventName, fn);
10285             return this;
10286         },
10287
10288         /**
10289          * @private
10290          */
10291         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10292
10293         /**
10294          * Sizes this element to its parent element's dimensions performing
10295          * neccessary box adjustments.
10296          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10297          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10298          * @return {Roo.Element} this
10299          */
10300         fitToParent : function(monitorResize, targetParent) {
10301           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10302           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10303           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10304             return this;
10305           }
10306           var p = Roo.get(targetParent || this.dom.parentNode);
10307           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10308           if (monitorResize === true) {
10309             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10310             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10311           }
10312           return this;
10313         },
10314
10315         /**
10316          * Gets the next sibling, skipping text nodes
10317          * @return {HTMLElement} The next sibling or null
10318          */
10319         getNextSibling : function(){
10320             var n = this.dom.nextSibling;
10321             while(n && n.nodeType != 1){
10322                 n = n.nextSibling;
10323             }
10324             return n;
10325         },
10326
10327         /**
10328          * Gets the previous sibling, skipping text nodes
10329          * @return {HTMLElement} The previous sibling or null
10330          */
10331         getPrevSibling : function(){
10332             var n = this.dom.previousSibling;
10333             while(n && n.nodeType != 1){
10334                 n = n.previousSibling;
10335             }
10336             return n;
10337         },
10338
10339
10340         /**
10341          * Appends the passed element(s) to this element
10342          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10343          * @return {Roo.Element} this
10344          */
10345         appendChild: function(el){
10346             el = Roo.get(el);
10347             el.appendTo(this);
10348             return this;
10349         },
10350
10351         /**
10352          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10353          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10354          * automatically generated with the specified attributes.
10355          * @param {HTMLElement} insertBefore (optional) a child element of this element
10356          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10357          * @return {Roo.Element} The new child element
10358          */
10359         createChild: function(config, insertBefore, returnDom){
10360             config = config || {tag:'div'};
10361             if(insertBefore){
10362                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10363             }
10364             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10365         },
10366
10367         /**
10368          * Appends this element to the passed element
10369          * @param {String/HTMLElement/Element} el The new parent element
10370          * @return {Roo.Element} this
10371          */
10372         appendTo: function(el){
10373             el = Roo.getDom(el);
10374             el.appendChild(this.dom);
10375             return this;
10376         },
10377
10378         /**
10379          * Inserts this element before the passed element in the DOM
10380          * @param {String/HTMLElement/Element} el The element to insert before
10381          * @return {Roo.Element} this
10382          */
10383         insertBefore: function(el){
10384             el = Roo.getDom(el);
10385             el.parentNode.insertBefore(this.dom, el);
10386             return this;
10387         },
10388
10389         /**
10390          * Inserts this element after the passed element in the DOM
10391          * @param {String/HTMLElement/Element} el The element to insert after
10392          * @return {Roo.Element} this
10393          */
10394         insertAfter: function(el){
10395             el = Roo.getDom(el);
10396             el.parentNode.insertBefore(this.dom, el.nextSibling);
10397             return this;
10398         },
10399
10400         /**
10401          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10402          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10403          * @return {Roo.Element} The new child
10404          */
10405         insertFirst: function(el, returnDom){
10406             el = el || {};
10407             if(typeof el == 'object' && !el.nodeType){ // dh config
10408                 return this.createChild(el, this.dom.firstChild, returnDom);
10409             }else{
10410                 el = Roo.getDom(el);
10411                 this.dom.insertBefore(el, this.dom.firstChild);
10412                 return !returnDom ? Roo.get(el) : el;
10413             }
10414         },
10415
10416         /**
10417          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10418          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10419          * @param {String} where (optional) 'before' or 'after' defaults to before
10420          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10421          * @return {Roo.Element} the inserted Element
10422          */
10423         insertSibling: function(el, where, returnDom){
10424             where = where ? where.toLowerCase() : 'before';
10425             el = el || {};
10426             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10427
10428             if(typeof el == 'object' && !el.nodeType){ // dh config
10429                 if(where == 'after' && !this.dom.nextSibling){
10430                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10431                 }else{
10432                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10433                 }
10434
10435             }else{
10436                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10437                             where == 'before' ? this.dom : this.dom.nextSibling);
10438                 if(!returnDom){
10439                     rt = Roo.get(rt);
10440                 }
10441             }
10442             return rt;
10443         },
10444
10445         /**
10446          * Creates and wraps this element with another element
10447          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10448          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10449          * @return {HTMLElement/Element} The newly created wrapper element
10450          */
10451         wrap: function(config, returnDom){
10452             if(!config){
10453                 config = {tag: "div"};
10454             }
10455             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10456             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10457             return newEl;
10458         },
10459
10460         /**
10461          * Replaces the passed element with this element
10462          * @param {String/HTMLElement/Element} el The element to replace
10463          * @return {Roo.Element} this
10464          */
10465         replace: function(el){
10466             el = Roo.get(el);
10467             this.insertBefore(el);
10468             el.remove();
10469             return this;
10470         },
10471
10472         /**
10473          * Inserts an html fragment into this element
10474          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10475          * @param {String} html The HTML fragment
10476          * @param {Boolean} returnEl True to return an Roo.Element
10477          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10478          */
10479         insertHtml : function(where, html, returnEl){
10480             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10481             return returnEl ? Roo.get(el) : el;
10482         },
10483
10484         /**
10485          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10486          * @param {Object} o The object with the attributes
10487          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10488          * @return {Roo.Element} this
10489          */
10490         set : function(o, useSet){
10491             var el = this.dom;
10492             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10493             for(var attr in o){
10494                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10495                 if(attr=="cls"){
10496                     el.className = o["cls"];
10497                 }else{
10498                     if(useSet) {
10499                         el.setAttribute(attr, o[attr]);
10500                     } else {
10501                         el[attr] = o[attr];
10502                     }
10503                 }
10504             }
10505             if(o.style){
10506                 Roo.DomHelper.applyStyles(el, o.style);
10507             }
10508             return this;
10509         },
10510
10511         /**
10512          * Convenience method for constructing a KeyMap
10513          * @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:
10514          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10515          * @param {Function} fn The function to call
10516          * @param {Object} scope (optional) The scope of the function
10517          * @return {Roo.KeyMap} The KeyMap created
10518          */
10519         addKeyListener : function(key, fn, scope){
10520             var config;
10521             if(typeof key != "object" || key instanceof Array){
10522                 config = {
10523                     key: key,
10524                     fn: fn,
10525                     scope: scope
10526                 };
10527             }else{
10528                 config = {
10529                     key : key.key,
10530                     shift : key.shift,
10531                     ctrl : key.ctrl,
10532                     alt : key.alt,
10533                     fn: fn,
10534                     scope: scope
10535                 };
10536             }
10537             return new Roo.KeyMap(this, config);
10538         },
10539
10540         /**
10541          * Creates a KeyMap for this element
10542          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10543          * @return {Roo.KeyMap} The KeyMap created
10544          */
10545         addKeyMap : function(config){
10546             return new Roo.KeyMap(this, config);
10547         },
10548
10549         /**
10550          * Returns true if this element is scrollable.
10551          * @return {Boolean}
10552          */
10553          isScrollable : function(){
10554             var dom = this.dom;
10555             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10556         },
10557
10558         /**
10559          * 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().
10560          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10561          * @param {Number} value The new scroll value
10562          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10563          * @return {Element} this
10564          */
10565
10566         scrollTo : function(side, value, animate){
10567             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10568             if(!animate || !A){
10569                 this.dom[prop] = value;
10570             }else{
10571                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10572                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10573             }
10574             return this;
10575         },
10576
10577         /**
10578          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10579          * within this element's scrollable range.
10580          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10581          * @param {Number} distance How far to scroll the element in pixels
10582          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10583          * @return {Boolean} Returns true if a scroll was triggered or false if the element
10584          * was scrolled as far as it could go.
10585          */
10586          scroll : function(direction, distance, animate){
10587              if(!this.isScrollable()){
10588                  return;
10589              }
10590              var el = this.dom;
10591              var l = el.scrollLeft, t = el.scrollTop;
10592              var w = el.scrollWidth, h = el.scrollHeight;
10593              var cw = el.clientWidth, ch = el.clientHeight;
10594              direction = direction.toLowerCase();
10595              var scrolled = false;
10596              var a = this.preanim(arguments, 2);
10597              switch(direction){
10598                  case "l":
10599                  case "left":
10600                      if(w - l > cw){
10601                          var v = Math.min(l + distance, w-cw);
10602                          this.scrollTo("left", v, a);
10603                          scrolled = true;
10604                      }
10605                      break;
10606                 case "r":
10607                 case "right":
10608                      if(l > 0){
10609                          var v = Math.max(l - distance, 0);
10610                          this.scrollTo("left", v, a);
10611                          scrolled = true;
10612                      }
10613                      break;
10614                 case "t":
10615                 case "top":
10616                 case "up":
10617                      if(t > 0){
10618                          var v = Math.max(t - distance, 0);
10619                          this.scrollTo("top", v, a);
10620                          scrolled = true;
10621                      }
10622                      break;
10623                 case "b":
10624                 case "bottom":
10625                 case "down":
10626                      if(h - t > ch){
10627                          var v = Math.min(t + distance, h-ch);
10628                          this.scrollTo("top", v, a);
10629                          scrolled = true;
10630                      }
10631                      break;
10632              }
10633              return scrolled;
10634         },
10635
10636         /**
10637          * Translates the passed page coordinates into left/top css values for this element
10638          * @param {Number/Array} x The page x or an array containing [x, y]
10639          * @param {Number} y The page y
10640          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10641          */
10642         translatePoints : function(x, y){
10643             if(typeof x == 'object' || x instanceof Array){
10644                 y = x[1]; x = x[0];
10645             }
10646             var p = this.getStyle('position');
10647             var o = this.getXY();
10648
10649             var l = parseInt(this.getStyle('left'), 10);
10650             var t = parseInt(this.getStyle('top'), 10);
10651
10652             if(isNaN(l)){
10653                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10654             }
10655             if(isNaN(t)){
10656                 t = (p == "relative") ? 0 : this.dom.offsetTop;
10657             }
10658
10659             return {left: (x - o[0] + l), top: (y - o[1] + t)};
10660         },
10661
10662         /**
10663          * Returns the current scroll position of the element.
10664          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10665          */
10666         getScroll : function(){
10667             var d = this.dom, doc = document;
10668             if(d == doc || d == doc.body){
10669                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10670                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10671                 return {left: l, top: t};
10672             }else{
10673                 return {left: d.scrollLeft, top: d.scrollTop};
10674             }
10675         },
10676
10677         /**
10678          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10679          * are convert to standard 6 digit hex color.
10680          * @param {String} attr The css attribute
10681          * @param {String} defaultValue The default value to use when a valid color isn't found
10682          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10683          * YUI color anims.
10684          */
10685         getColor : function(attr, defaultValue, prefix){
10686             var v = this.getStyle(attr);
10687             if(!v || v == "transparent" || v == "inherit") {
10688                 return defaultValue;
10689             }
10690             var color = typeof prefix == "undefined" ? "#" : prefix;
10691             if(v.substr(0, 4) == "rgb("){
10692                 var rvs = v.slice(4, v.length -1).split(",");
10693                 for(var i = 0; i < 3; i++){
10694                     var h = parseInt(rvs[i]).toString(16);
10695                     if(h < 16){
10696                         h = "0" + h;
10697                     }
10698                     color += h;
10699                 }
10700             } else {
10701                 if(v.substr(0, 1) == "#"){
10702                     if(v.length == 4) {
10703                         for(var i = 1; i < 4; i++){
10704                             var c = v.charAt(i);
10705                             color +=  c + c;
10706                         }
10707                     }else if(v.length == 7){
10708                         color += v.substr(1);
10709                     }
10710                 }
10711             }
10712             return(color.length > 5 ? color.toLowerCase() : defaultValue);
10713         },
10714
10715         /**
10716          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10717          * gradient background, rounded corners and a 4-way shadow.
10718          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10719          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10720          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10721          * @return {Roo.Element} this
10722          */
10723         boxWrap : function(cls){
10724             cls = cls || 'x-box';
10725             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10726             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10727             return el;
10728         },
10729
10730         /**
10731          * Returns the value of a namespaced attribute from the element's underlying DOM node.
10732          * @param {String} namespace The namespace in which to look for the attribute
10733          * @param {String} name The attribute name
10734          * @return {String} The attribute value
10735          */
10736         getAttributeNS : Roo.isIE ? function(ns, name){
10737             var d = this.dom;
10738             var type = typeof d[ns+":"+name];
10739             if(type != 'undefined' && type != 'unknown'){
10740                 return d[ns+":"+name];
10741             }
10742             return d[name];
10743         } : function(ns, name){
10744             var d = this.dom;
10745             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10746         },
10747         
10748         
10749         /**
10750          * Sets or Returns the value the dom attribute value
10751          * @param {String|Object} name The attribute name (or object to set multiple attributes)
10752          * @param {String} value (optional) The value to set the attribute to
10753          * @return {String} The attribute value
10754          */
10755         attr : function(name){
10756             if (arguments.length > 1) {
10757                 this.dom.setAttribute(name, arguments[1]);
10758                 return arguments[1];
10759             }
10760             if (typeof(name) == 'object') {
10761                 for(var i in name) {
10762                     this.attr(i, name[i]);
10763                 }
10764                 return name;
10765             }
10766             
10767             
10768             if (!this.dom.hasAttribute(name)) {
10769                 return undefined;
10770             }
10771             return this.dom.getAttribute(name);
10772         }
10773         
10774         
10775         
10776     };
10777
10778     var ep = El.prototype;
10779
10780     /**
10781      * Appends an event handler (Shorthand for addListener)
10782      * @param {String}   eventName     The type of event to append
10783      * @param {Function} fn        The method the event invokes
10784      * @param {Object} scope       (optional) The scope (this object) of the fn
10785      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
10786      * @method
10787      */
10788     ep.on = ep.addListener;
10789         // backwards compat
10790     ep.mon = ep.addListener;
10791
10792     /**
10793      * Removes an event handler from this element (shorthand for removeListener)
10794      * @param {String} eventName the type of event to remove
10795      * @param {Function} fn the method the event invokes
10796      * @return {Roo.Element} this
10797      * @method
10798      */
10799     ep.un = ep.removeListener;
10800
10801     /**
10802      * true to automatically adjust width and height settings for box-model issues (default to true)
10803      */
10804     ep.autoBoxAdjust = true;
10805
10806     // private
10807     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10808
10809     // private
10810     El.addUnits = function(v, defaultUnit){
10811         if(v === "" || v == "auto"){
10812             return v;
10813         }
10814         if(v === undefined){
10815             return '';
10816         }
10817         if(typeof v == "number" || !El.unitPattern.test(v)){
10818             return v + (defaultUnit || 'px');
10819         }
10820         return v;
10821     };
10822
10823     // special markup used throughout Roo when box wrapping elements
10824     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>';
10825     /**
10826      * Visibility mode constant - Use visibility to hide element
10827      * @static
10828      * @type Number
10829      */
10830     El.VISIBILITY = 1;
10831     /**
10832      * Visibility mode constant - Use display to hide element
10833      * @static
10834      * @type Number
10835      */
10836     El.DISPLAY = 2;
10837
10838     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10839     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10840     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10841
10842
10843
10844     /**
10845      * @private
10846      */
10847     El.cache = {};
10848
10849     var docEl;
10850
10851     /**
10852      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10853      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10854      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10855      * @return {Element} The Element object
10856      * @static
10857      */
10858     El.get = function(el){
10859         var ex, elm, id;
10860         if(!el){ return null; }
10861         if(typeof el == "string"){ // element id
10862             if(!(elm = document.getElementById(el))){
10863                 return null;
10864             }
10865             if(ex = El.cache[el]){
10866                 ex.dom = elm;
10867             }else{
10868                 ex = El.cache[el] = new El(elm);
10869             }
10870             return ex;
10871         }else if(el.tagName){ // dom element
10872             if(!(id = el.id)){
10873                 id = Roo.id(el);
10874             }
10875             if(ex = El.cache[id]){
10876                 ex.dom = el;
10877             }else{
10878                 ex = El.cache[id] = new El(el);
10879             }
10880             return ex;
10881         }else if(el instanceof El){
10882             if(el != docEl){
10883                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10884                                                               // catch case where it hasn't been appended
10885                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10886             }
10887             return el;
10888         }else if(el.isComposite){
10889             return el;
10890         }else if(el instanceof Array){
10891             return El.select(el);
10892         }else if(el == document){
10893             // create a bogus element object representing the document object
10894             if(!docEl){
10895                 var f = function(){};
10896                 f.prototype = El.prototype;
10897                 docEl = new f();
10898                 docEl.dom = document;
10899             }
10900             return docEl;
10901         }
10902         return null;
10903     };
10904
10905     // private
10906     El.uncache = function(el){
10907         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10908             if(a[i]){
10909                 delete El.cache[a[i].id || a[i]];
10910             }
10911         }
10912     };
10913
10914     // private
10915     // Garbage collection - uncache elements/purge listeners on orphaned elements
10916     // so we don't hold a reference and cause the browser to retain them
10917     El.garbageCollect = function(){
10918         if(!Roo.enableGarbageCollector){
10919             clearInterval(El.collectorThread);
10920             return;
10921         }
10922         for(var eid in El.cache){
10923             var el = El.cache[eid], d = el.dom;
10924             // -------------------------------------------------------
10925             // Determining what is garbage:
10926             // -------------------------------------------------------
10927             // !d
10928             // dom node is null, definitely garbage
10929             // -------------------------------------------------------
10930             // !d.parentNode
10931             // no parentNode == direct orphan, definitely garbage
10932             // -------------------------------------------------------
10933             // !d.offsetParent && !document.getElementById(eid)
10934             // display none elements have no offsetParent so we will
10935             // also try to look it up by it's id. However, check
10936             // offsetParent first so we don't do unneeded lookups.
10937             // This enables collection of elements that are not orphans
10938             // directly, but somewhere up the line they have an orphan
10939             // parent.
10940             // -------------------------------------------------------
10941             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10942                 delete El.cache[eid];
10943                 if(d && Roo.enableListenerCollection){
10944                     E.purgeElement(d);
10945                 }
10946             }
10947         }
10948     }
10949     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10950
10951
10952     // dom is optional
10953     El.Flyweight = function(dom){
10954         this.dom = dom;
10955     };
10956     El.Flyweight.prototype = El.prototype;
10957
10958     El._flyweights = {};
10959     /**
10960      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10961      * the dom node can be overwritten by other code.
10962      * @param {String/HTMLElement} el The dom node or id
10963      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10964      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10965      * @static
10966      * @return {Element} The shared Element object
10967      */
10968     El.fly = function(el, named){
10969         named = named || '_global';
10970         el = Roo.getDom(el);
10971         if(!el){
10972             return null;
10973         }
10974         if(!El._flyweights[named]){
10975             El._flyweights[named] = new El.Flyweight();
10976         }
10977         El._flyweights[named].dom = el;
10978         return El._flyweights[named];
10979     };
10980
10981     /**
10982      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10983      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10984      * Shorthand of {@link Roo.Element#get}
10985      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10986      * @return {Element} The Element object
10987      * @member Roo
10988      * @method get
10989      */
10990     Roo.get = El.get;
10991     /**
10992      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10993      * the dom node can be overwritten by other code.
10994      * Shorthand of {@link Roo.Element#fly}
10995      * @param {String/HTMLElement} el The dom node or id
10996      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10997      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10998      * @static
10999      * @return {Element} The shared Element object
11000      * @member Roo
11001      * @method fly
11002      */
11003     Roo.fly = El.fly;
11004
11005     // speedy lookup for elements never to box adjust
11006     var noBoxAdjust = Roo.isStrict ? {
11007         select:1
11008     } : {
11009         input:1, select:1, textarea:1
11010     };
11011     if(Roo.isIE || Roo.isGecko){
11012         noBoxAdjust['button'] = 1;
11013     }
11014
11015
11016     Roo.EventManager.on(window, 'unload', function(){
11017         delete El.cache;
11018         delete El._flyweights;
11019     });
11020 })();
11021
11022
11023
11024
11025 if(Roo.DomQuery){
11026     Roo.Element.selectorFunction = Roo.DomQuery.select;
11027 }
11028
11029 Roo.Element.select = function(selector, unique, root){
11030     var els;
11031     if(typeof selector == "string"){
11032         els = Roo.Element.selectorFunction(selector, root);
11033     }else if(selector.length !== undefined){
11034         els = selector;
11035     }else{
11036         throw "Invalid selector";
11037     }
11038     if(unique === true){
11039         return new Roo.CompositeElement(els);
11040     }else{
11041         return new Roo.CompositeElementLite(els);
11042     }
11043 };
11044 /**
11045  * Selects elements based on the passed CSS selector to enable working on them as 1.
11046  * @param {String/Array} selector The CSS selector or an array of elements
11047  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11048  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11049  * @return {CompositeElementLite/CompositeElement}
11050  * @member Roo
11051  * @method select
11052  */
11053 Roo.select = Roo.Element.select;
11054
11055
11056
11057
11058
11059
11060
11061
11062
11063
11064
11065
11066
11067
11068 /*
11069  * Based on:
11070  * Ext JS Library 1.1.1
11071  * Copyright(c) 2006-2007, Ext JS, LLC.
11072  *
11073  * Originally Released Under LGPL - original licence link has changed is not relivant.
11074  *
11075  * Fork - LGPL
11076  * <script type="text/javascript">
11077  */
11078
11079
11080
11081 //Notifies Element that fx methods are available
11082 Roo.enableFx = true;
11083
11084 /**
11085  * @class Roo.Fx
11086  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11087  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11088  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11089  * Element effects to work.</p><br/>
11090  *
11091  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11092  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11093  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11094  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11095  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11096  * expected results and should be done with care.</p><br/>
11097  *
11098  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11099  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11100 <pre>
11101 Value  Description
11102 -----  -----------------------------
11103 tl     The top left corner
11104 t      The center of the top edge
11105 tr     The top right corner
11106 l      The center of the left edge
11107 r      The center of the right edge
11108 bl     The bottom left corner
11109 b      The center of the bottom edge
11110 br     The bottom right corner
11111 </pre>
11112  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11113  * below are common options that can be passed to any Fx method.</b>
11114  * @cfg {Function} callback A function called when the effect is finished
11115  * @cfg {Object} scope The scope of the effect function
11116  * @cfg {String} easing A valid Easing value for the effect
11117  * @cfg {String} afterCls A css class to apply after the effect
11118  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11119  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11120  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11121  * effects that end with the element being visually hidden, ignored otherwise)
11122  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11123  * a function which returns such a specification that will be applied to the Element after the effect finishes
11124  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11125  * @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
11126  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11127  */
11128 Roo.Fx = {
11129         /**
11130          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11131          * origin for the slide effect.  This function automatically handles wrapping the element with
11132          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11133          * Usage:
11134          *<pre><code>
11135 // default: slide the element in from the top
11136 el.slideIn();
11137
11138 // custom: slide the element in from the right with a 2-second duration
11139 el.slideIn('r', { duration: 2 });
11140
11141 // common config options shown with default values
11142 el.slideIn('t', {
11143     easing: 'easeOut',
11144     duration: .5
11145 });
11146 </code></pre>
11147          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11148          * @param {Object} options (optional) Object literal with any of the Fx config options
11149          * @return {Roo.Element} The Element
11150          */
11151     slideIn : function(anchor, o){
11152         var el = this.getFxEl();
11153         o = o || {};
11154
11155         el.queueFx(o, function(){
11156
11157             anchor = anchor || "t";
11158
11159             // fix display to visibility
11160             this.fixDisplay();
11161
11162             // restore values after effect
11163             var r = this.getFxRestore();
11164             var b = this.getBox();
11165             // fixed size for slide
11166             this.setSize(b);
11167
11168             // wrap if needed
11169             var wrap = this.fxWrap(r.pos, o, "hidden");
11170
11171             var st = this.dom.style;
11172             st.visibility = "visible";
11173             st.position = "absolute";
11174
11175             // clear out temp styles after slide and unwrap
11176             var after = function(){
11177                 el.fxUnwrap(wrap, r.pos, o);
11178                 st.width = r.width;
11179                 st.height = r.height;
11180                 el.afterFx(o);
11181             };
11182             // time to calc the positions
11183             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11184
11185             switch(anchor.toLowerCase()){
11186                 case "t":
11187                     wrap.setSize(b.width, 0);
11188                     st.left = st.bottom = "0";
11189                     a = {height: bh};
11190                 break;
11191                 case "l":
11192                     wrap.setSize(0, b.height);
11193                     st.right = st.top = "0";
11194                     a = {width: bw};
11195                 break;
11196                 case "r":
11197                     wrap.setSize(0, b.height);
11198                     wrap.setX(b.right);
11199                     st.left = st.top = "0";
11200                     a = {width: bw, points: pt};
11201                 break;
11202                 case "b":
11203                     wrap.setSize(b.width, 0);
11204                     wrap.setY(b.bottom);
11205                     st.left = st.top = "0";
11206                     a = {height: bh, points: pt};
11207                 break;
11208                 case "tl":
11209                     wrap.setSize(0, 0);
11210                     st.right = st.bottom = "0";
11211                     a = {width: bw, height: bh};
11212                 break;
11213                 case "bl":
11214                     wrap.setSize(0, 0);
11215                     wrap.setY(b.y+b.height);
11216                     st.right = st.top = "0";
11217                     a = {width: bw, height: bh, points: pt};
11218                 break;
11219                 case "br":
11220                     wrap.setSize(0, 0);
11221                     wrap.setXY([b.right, b.bottom]);
11222                     st.left = st.top = "0";
11223                     a = {width: bw, height: bh, points: pt};
11224                 break;
11225                 case "tr":
11226                     wrap.setSize(0, 0);
11227                     wrap.setX(b.x+b.width);
11228                     st.left = st.bottom = "0";
11229                     a = {width: bw, height: bh, points: pt};
11230                 break;
11231             }
11232             this.dom.style.visibility = "visible";
11233             wrap.show();
11234
11235             arguments.callee.anim = wrap.fxanim(a,
11236                 o,
11237                 'motion',
11238                 .5,
11239                 'easeOut', after);
11240         });
11241         return this;
11242     },
11243     
11244         /**
11245          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11246          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11247          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11248          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11249          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11250          * Usage:
11251          *<pre><code>
11252 // default: slide the element out to the top
11253 el.slideOut();
11254
11255 // custom: slide the element out to the right with a 2-second duration
11256 el.slideOut('r', { duration: 2 });
11257
11258 // common config options shown with default values
11259 el.slideOut('t', {
11260     easing: 'easeOut',
11261     duration: .5,
11262     remove: false,
11263     useDisplay: false
11264 });
11265 </code></pre>
11266          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11267          * @param {Object} options (optional) Object literal with any of the Fx config options
11268          * @return {Roo.Element} The Element
11269          */
11270     slideOut : function(anchor, o){
11271         var el = this.getFxEl();
11272         o = o || {};
11273
11274         el.queueFx(o, function(){
11275
11276             anchor = anchor || "t";
11277
11278             // restore values after effect
11279             var r = this.getFxRestore();
11280             
11281             var b = this.getBox();
11282             // fixed size for slide
11283             this.setSize(b);
11284
11285             // wrap if needed
11286             var wrap = this.fxWrap(r.pos, o, "visible");
11287
11288             var st = this.dom.style;
11289             st.visibility = "visible";
11290             st.position = "absolute";
11291
11292             wrap.setSize(b);
11293
11294             var after = function(){
11295                 if(o.useDisplay){
11296                     el.setDisplayed(false);
11297                 }else{
11298                     el.hide();
11299                 }
11300
11301                 el.fxUnwrap(wrap, r.pos, o);
11302
11303                 st.width = r.width;
11304                 st.height = r.height;
11305
11306                 el.afterFx(o);
11307             };
11308
11309             var a, zero = {to: 0};
11310             switch(anchor.toLowerCase()){
11311                 case "t":
11312                     st.left = st.bottom = "0";
11313                     a = {height: zero};
11314                 break;
11315                 case "l":
11316                     st.right = st.top = "0";
11317                     a = {width: zero};
11318                 break;
11319                 case "r":
11320                     st.left = st.top = "0";
11321                     a = {width: zero, points: {to:[b.right, b.y]}};
11322                 break;
11323                 case "b":
11324                     st.left = st.top = "0";
11325                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11326                 break;
11327                 case "tl":
11328                     st.right = st.bottom = "0";
11329                     a = {width: zero, height: zero};
11330                 break;
11331                 case "bl":
11332                     st.right = st.top = "0";
11333                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11334                 break;
11335                 case "br":
11336                     st.left = st.top = "0";
11337                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11338                 break;
11339                 case "tr":
11340                     st.left = st.bottom = "0";
11341                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11342                 break;
11343             }
11344
11345             arguments.callee.anim = wrap.fxanim(a,
11346                 o,
11347                 'motion',
11348                 .5,
11349                 "easeOut", after);
11350         });
11351         return this;
11352     },
11353
11354         /**
11355          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11356          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11357          * The element must be removed from the DOM using the 'remove' config option if desired.
11358          * Usage:
11359          *<pre><code>
11360 // default
11361 el.puff();
11362
11363 // common config options shown with default values
11364 el.puff({
11365     easing: 'easeOut',
11366     duration: .5,
11367     remove: false,
11368     useDisplay: false
11369 });
11370 </code></pre>
11371          * @param {Object} options (optional) Object literal with any of the Fx config options
11372          * @return {Roo.Element} The Element
11373          */
11374     puff : function(o){
11375         var el = this.getFxEl();
11376         o = o || {};
11377
11378         el.queueFx(o, function(){
11379             this.clearOpacity();
11380             this.show();
11381
11382             // restore values after effect
11383             var r = this.getFxRestore();
11384             var st = this.dom.style;
11385
11386             var after = function(){
11387                 if(o.useDisplay){
11388                     el.setDisplayed(false);
11389                 }else{
11390                     el.hide();
11391                 }
11392
11393                 el.clearOpacity();
11394
11395                 el.setPositioning(r.pos);
11396                 st.width = r.width;
11397                 st.height = r.height;
11398                 st.fontSize = '';
11399                 el.afterFx(o);
11400             };
11401
11402             var width = this.getWidth();
11403             var height = this.getHeight();
11404
11405             arguments.callee.anim = this.fxanim({
11406                     width : {to: this.adjustWidth(width * 2)},
11407                     height : {to: this.adjustHeight(height * 2)},
11408                     points : {by: [-(width * .5), -(height * .5)]},
11409                     opacity : {to: 0},
11410                     fontSize: {to:200, unit: "%"}
11411                 },
11412                 o,
11413                 'motion',
11414                 .5,
11415                 "easeOut", after);
11416         });
11417         return this;
11418     },
11419
11420         /**
11421          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11422          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11423          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11424          * Usage:
11425          *<pre><code>
11426 // default
11427 el.switchOff();
11428
11429 // all config options shown with default values
11430 el.switchOff({
11431     easing: 'easeIn',
11432     duration: .3,
11433     remove: false,
11434     useDisplay: false
11435 });
11436 </code></pre>
11437          * @param {Object} options (optional) Object literal with any of the Fx config options
11438          * @return {Roo.Element} The Element
11439          */
11440     switchOff : function(o){
11441         var el = this.getFxEl();
11442         o = o || {};
11443
11444         el.queueFx(o, function(){
11445             this.clearOpacity();
11446             this.clip();
11447
11448             // restore values after effect
11449             var r = this.getFxRestore();
11450             var st = this.dom.style;
11451
11452             var after = function(){
11453                 if(o.useDisplay){
11454                     el.setDisplayed(false);
11455                 }else{
11456                     el.hide();
11457                 }
11458
11459                 el.clearOpacity();
11460                 el.setPositioning(r.pos);
11461                 st.width = r.width;
11462                 st.height = r.height;
11463
11464                 el.afterFx(o);
11465             };
11466
11467             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11468                 this.clearOpacity();
11469                 (function(){
11470                     this.fxanim({
11471                         height:{to:1},
11472                         points:{by:[0, this.getHeight() * .5]}
11473                     }, o, 'motion', 0.3, 'easeIn', after);
11474                 }).defer(100, this);
11475             });
11476         });
11477         return this;
11478     },
11479
11480     /**
11481      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11482      * changed using the "attr" config option) and then fading back to the original color. If no original
11483      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11484      * Usage:
11485 <pre><code>
11486 // default: highlight background to yellow
11487 el.highlight();
11488
11489 // custom: highlight foreground text to blue for 2 seconds
11490 el.highlight("0000ff", { attr: 'color', duration: 2 });
11491
11492 // common config options shown with default values
11493 el.highlight("ffff9c", {
11494     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11495     endColor: (current color) or "ffffff",
11496     easing: 'easeIn',
11497     duration: 1
11498 });
11499 </code></pre>
11500      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11501      * @param {Object} options (optional) Object literal with any of the Fx config options
11502      * @return {Roo.Element} The Element
11503      */ 
11504     highlight : function(color, o){
11505         var el = this.getFxEl();
11506         o = o || {};
11507
11508         el.queueFx(o, function(){
11509             color = color || "ffff9c";
11510             attr = o.attr || "backgroundColor";
11511
11512             this.clearOpacity();
11513             this.show();
11514
11515             var origColor = this.getColor(attr);
11516             var restoreColor = this.dom.style[attr];
11517             endColor = (o.endColor || origColor) || "ffffff";
11518
11519             var after = function(){
11520                 el.dom.style[attr] = restoreColor;
11521                 el.afterFx(o);
11522             };
11523
11524             var a = {};
11525             a[attr] = {from: color, to: endColor};
11526             arguments.callee.anim = this.fxanim(a,
11527                 o,
11528                 'color',
11529                 1,
11530                 'easeIn', after);
11531         });
11532         return this;
11533     },
11534
11535    /**
11536     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11537     * Usage:
11538 <pre><code>
11539 // default: a single light blue ripple
11540 el.frame();
11541
11542 // custom: 3 red ripples lasting 3 seconds total
11543 el.frame("ff0000", 3, { duration: 3 });
11544
11545 // common config options shown with default values
11546 el.frame("C3DAF9", 1, {
11547     duration: 1 //duration of entire animation (not each individual ripple)
11548     // Note: Easing is not configurable and will be ignored if included
11549 });
11550 </code></pre>
11551     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11552     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11553     * @param {Object} options (optional) Object literal with any of the Fx config options
11554     * @return {Roo.Element} The Element
11555     */
11556     frame : function(color, count, o){
11557         var el = this.getFxEl();
11558         o = o || {};
11559
11560         el.queueFx(o, function(){
11561             color = color || "#C3DAF9";
11562             if(color.length == 6){
11563                 color = "#" + color;
11564             }
11565             count = count || 1;
11566             duration = o.duration || 1;
11567             this.show();
11568
11569             var b = this.getBox();
11570             var animFn = function(){
11571                 var proxy = this.createProxy({
11572
11573                      style:{
11574                         visbility:"hidden",
11575                         position:"absolute",
11576                         "z-index":"35000", // yee haw
11577                         border:"0px solid " + color
11578                      }
11579                   });
11580                 var scale = Roo.isBorderBox ? 2 : 1;
11581                 proxy.animate({
11582                     top:{from:b.y, to:b.y - 20},
11583                     left:{from:b.x, to:b.x - 20},
11584                     borderWidth:{from:0, to:10},
11585                     opacity:{from:1, to:0},
11586                     height:{from:b.height, to:(b.height + (20*scale))},
11587                     width:{from:b.width, to:(b.width + (20*scale))}
11588                 }, duration, function(){
11589                     proxy.remove();
11590                 });
11591                 if(--count > 0){
11592                      animFn.defer((duration/2)*1000, this);
11593                 }else{
11594                     el.afterFx(o);
11595                 }
11596             };
11597             animFn.call(this);
11598         });
11599         return this;
11600     },
11601
11602    /**
11603     * Creates a pause before any subsequent queued effects begin.  If there are
11604     * no effects queued after the pause it will have no effect.
11605     * Usage:
11606 <pre><code>
11607 el.pause(1);
11608 </code></pre>
11609     * @param {Number} seconds The length of time to pause (in seconds)
11610     * @return {Roo.Element} The Element
11611     */
11612     pause : function(seconds){
11613         var el = this.getFxEl();
11614         var o = {};
11615
11616         el.queueFx(o, function(){
11617             setTimeout(function(){
11618                 el.afterFx(o);
11619             }, seconds * 1000);
11620         });
11621         return this;
11622     },
11623
11624    /**
11625     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
11626     * using the "endOpacity" config option.
11627     * Usage:
11628 <pre><code>
11629 // default: fade in from opacity 0 to 100%
11630 el.fadeIn();
11631
11632 // custom: fade in from opacity 0 to 75% over 2 seconds
11633 el.fadeIn({ endOpacity: .75, duration: 2});
11634
11635 // common config options shown with default values
11636 el.fadeIn({
11637     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11638     easing: 'easeOut',
11639     duration: .5
11640 });
11641 </code></pre>
11642     * @param {Object} options (optional) Object literal with any of the Fx config options
11643     * @return {Roo.Element} The Element
11644     */
11645     fadeIn : function(o){
11646         var el = this.getFxEl();
11647         o = o || {};
11648         el.queueFx(o, function(){
11649             this.setOpacity(0);
11650             this.fixDisplay();
11651             this.dom.style.visibility = 'visible';
11652             var to = o.endOpacity || 1;
11653             arguments.callee.anim = this.fxanim({opacity:{to:to}},
11654                 o, null, .5, "easeOut", function(){
11655                 if(to == 1){
11656                     this.clearOpacity();
11657                 }
11658                 el.afterFx(o);
11659             });
11660         });
11661         return this;
11662     },
11663
11664    /**
11665     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
11666     * using the "endOpacity" config option.
11667     * Usage:
11668 <pre><code>
11669 // default: fade out from the element's current opacity to 0
11670 el.fadeOut();
11671
11672 // custom: fade out from the element's current opacity to 25% over 2 seconds
11673 el.fadeOut({ endOpacity: .25, duration: 2});
11674
11675 // common config options shown with default values
11676 el.fadeOut({
11677     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11678     easing: 'easeOut',
11679     duration: .5
11680     remove: false,
11681     useDisplay: false
11682 });
11683 </code></pre>
11684     * @param {Object} options (optional) Object literal with any of the Fx config options
11685     * @return {Roo.Element} The Element
11686     */
11687     fadeOut : function(o){
11688         var el = this.getFxEl();
11689         o = o || {};
11690         el.queueFx(o, function(){
11691             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11692                 o, null, .5, "easeOut", function(){
11693                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11694                      this.dom.style.display = "none";
11695                 }else{
11696                      this.dom.style.visibility = "hidden";
11697                 }
11698                 this.clearOpacity();
11699                 el.afterFx(o);
11700             });
11701         });
11702         return this;
11703     },
11704
11705    /**
11706     * Animates the transition of an element's dimensions from a starting height/width
11707     * to an ending height/width.
11708     * Usage:
11709 <pre><code>
11710 // change height and width to 100x100 pixels
11711 el.scale(100, 100);
11712
11713 // common config options shown with default values.  The height and width will default to
11714 // the element's existing values if passed as null.
11715 el.scale(
11716     [element's width],
11717     [element's height], {
11718     easing: 'easeOut',
11719     duration: .35
11720 });
11721 </code></pre>
11722     * @param {Number} width  The new width (pass undefined to keep the original width)
11723     * @param {Number} height  The new height (pass undefined to keep the original height)
11724     * @param {Object} options (optional) Object literal with any of the Fx config options
11725     * @return {Roo.Element} The Element
11726     */
11727     scale : function(w, h, o){
11728         this.shift(Roo.apply({}, o, {
11729             width: w,
11730             height: h
11731         }));
11732         return this;
11733     },
11734
11735    /**
11736     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11737     * Any of these properties not specified in the config object will not be changed.  This effect 
11738     * requires that at least one new dimension, position or opacity setting must be passed in on
11739     * the config object in order for the function to have any effect.
11740     * Usage:
11741 <pre><code>
11742 // slide the element horizontally to x position 200 while changing the height and opacity
11743 el.shift({ x: 200, height: 50, opacity: .8 });
11744
11745 // common config options shown with default values.
11746 el.shift({
11747     width: [element's width],
11748     height: [element's height],
11749     x: [element's x position],
11750     y: [element's y position],
11751     opacity: [element's opacity],
11752     easing: 'easeOut',
11753     duration: .35
11754 });
11755 </code></pre>
11756     * @param {Object} options  Object literal with any of the Fx config options
11757     * @return {Roo.Element} The Element
11758     */
11759     shift : function(o){
11760         var el = this.getFxEl();
11761         o = o || {};
11762         el.queueFx(o, function(){
11763             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
11764             if(w !== undefined){
11765                 a.width = {to: this.adjustWidth(w)};
11766             }
11767             if(h !== undefined){
11768                 a.height = {to: this.adjustHeight(h)};
11769             }
11770             if(x !== undefined || y !== undefined){
11771                 a.points = {to: [
11772                     x !== undefined ? x : this.getX(),
11773                     y !== undefined ? y : this.getY()
11774                 ]};
11775             }
11776             if(op !== undefined){
11777                 a.opacity = {to: op};
11778             }
11779             if(o.xy !== undefined){
11780                 a.points = {to: o.xy};
11781             }
11782             arguments.callee.anim = this.fxanim(a,
11783                 o, 'motion', .35, "easeOut", function(){
11784                 el.afterFx(o);
11785             });
11786         });
11787         return this;
11788     },
11789
11790         /**
11791          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
11792          * ending point of the effect.
11793          * Usage:
11794          *<pre><code>
11795 // default: slide the element downward while fading out
11796 el.ghost();
11797
11798 // custom: slide the element out to the right with a 2-second duration
11799 el.ghost('r', { duration: 2 });
11800
11801 // common config options shown with default values
11802 el.ghost('b', {
11803     easing: 'easeOut',
11804     duration: .5
11805     remove: false,
11806     useDisplay: false
11807 });
11808 </code></pre>
11809          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11810          * @param {Object} options (optional) Object literal with any of the Fx config options
11811          * @return {Roo.Element} The Element
11812          */
11813     ghost : function(anchor, o){
11814         var el = this.getFxEl();
11815         o = o || {};
11816
11817         el.queueFx(o, function(){
11818             anchor = anchor || "b";
11819
11820             // restore values after effect
11821             var r = this.getFxRestore();
11822             var w = this.getWidth(),
11823                 h = this.getHeight();
11824
11825             var st = this.dom.style;
11826
11827             var after = function(){
11828                 if(o.useDisplay){
11829                     el.setDisplayed(false);
11830                 }else{
11831                     el.hide();
11832                 }
11833
11834                 el.clearOpacity();
11835                 el.setPositioning(r.pos);
11836                 st.width = r.width;
11837                 st.height = r.height;
11838
11839                 el.afterFx(o);
11840             };
11841
11842             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11843             switch(anchor.toLowerCase()){
11844                 case "t":
11845                     pt.by = [0, -h];
11846                 break;
11847                 case "l":
11848                     pt.by = [-w, 0];
11849                 break;
11850                 case "r":
11851                     pt.by = [w, 0];
11852                 break;
11853                 case "b":
11854                     pt.by = [0, h];
11855                 break;
11856                 case "tl":
11857                     pt.by = [-w, -h];
11858                 break;
11859                 case "bl":
11860                     pt.by = [-w, h];
11861                 break;
11862                 case "br":
11863                     pt.by = [w, h];
11864                 break;
11865                 case "tr":
11866                     pt.by = [w, -h];
11867                 break;
11868             }
11869
11870             arguments.callee.anim = this.fxanim(a,
11871                 o,
11872                 'motion',
11873                 .5,
11874                 "easeOut", after);
11875         });
11876         return this;
11877     },
11878
11879         /**
11880          * Ensures that all effects queued after syncFx is called on the element are
11881          * run concurrently.  This is the opposite of {@link #sequenceFx}.
11882          * @return {Roo.Element} The Element
11883          */
11884     syncFx : function(){
11885         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11886             block : false,
11887             concurrent : true,
11888             stopFx : false
11889         });
11890         return this;
11891     },
11892
11893         /**
11894          * Ensures that all effects queued after sequenceFx is called on the element are
11895          * run in sequence.  This is the opposite of {@link #syncFx}.
11896          * @return {Roo.Element} The Element
11897          */
11898     sequenceFx : function(){
11899         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11900             block : false,
11901             concurrent : false,
11902             stopFx : false
11903         });
11904         return this;
11905     },
11906
11907         /* @private */
11908     nextFx : function(){
11909         var ef = this.fxQueue[0];
11910         if(ef){
11911             ef.call(this);
11912         }
11913     },
11914
11915         /**
11916          * Returns true if the element has any effects actively running or queued, else returns false.
11917          * @return {Boolean} True if element has active effects, else false
11918          */
11919     hasActiveFx : function(){
11920         return this.fxQueue && this.fxQueue[0];
11921     },
11922
11923         /**
11924          * Stops any running effects and clears the element's internal effects queue if it contains
11925          * any additional effects that haven't started yet.
11926          * @return {Roo.Element} The Element
11927          */
11928     stopFx : function(){
11929         if(this.hasActiveFx()){
11930             var cur = this.fxQueue[0];
11931             if(cur && cur.anim && cur.anim.isAnimated()){
11932                 this.fxQueue = [cur]; // clear out others
11933                 cur.anim.stop(true);
11934             }
11935         }
11936         return this;
11937     },
11938
11939         /* @private */
11940     beforeFx : function(o){
11941         if(this.hasActiveFx() && !o.concurrent){
11942            if(o.stopFx){
11943                this.stopFx();
11944                return true;
11945            }
11946            return false;
11947         }
11948         return true;
11949     },
11950
11951         /**
11952          * Returns true if the element is currently blocking so that no other effect can be queued
11953          * until this effect is finished, else returns false if blocking is not set.  This is commonly
11954          * used to ensure that an effect initiated by a user action runs to completion prior to the
11955          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11956          * @return {Boolean} True if blocking, else false
11957          */
11958     hasFxBlock : function(){
11959         var q = this.fxQueue;
11960         return q && q[0] && q[0].block;
11961     },
11962
11963         /* @private */
11964     queueFx : function(o, fn){
11965         if(!this.fxQueue){
11966             this.fxQueue = [];
11967         }
11968         if(!this.hasFxBlock()){
11969             Roo.applyIf(o, this.fxDefaults);
11970             if(!o.concurrent){
11971                 var run = this.beforeFx(o);
11972                 fn.block = o.block;
11973                 this.fxQueue.push(fn);
11974                 if(run){
11975                     this.nextFx();
11976                 }
11977             }else{
11978                 fn.call(this);
11979             }
11980         }
11981         return this;
11982     },
11983
11984         /* @private */
11985     fxWrap : function(pos, o, vis){
11986         var wrap;
11987         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11988             var wrapXY;
11989             if(o.fixPosition){
11990                 wrapXY = this.getXY();
11991             }
11992             var div = document.createElement("div");
11993             div.style.visibility = vis;
11994             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11995             wrap.setPositioning(pos);
11996             if(wrap.getStyle("position") == "static"){
11997                 wrap.position("relative");
11998             }
11999             this.clearPositioning('auto');
12000             wrap.clip();
12001             wrap.dom.appendChild(this.dom);
12002             if(wrapXY){
12003                 wrap.setXY(wrapXY);
12004             }
12005         }
12006         return wrap;
12007     },
12008
12009         /* @private */
12010     fxUnwrap : function(wrap, pos, o){
12011         this.clearPositioning();
12012         this.setPositioning(pos);
12013         if(!o.wrap){
12014             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12015             wrap.remove();
12016         }
12017     },
12018
12019         /* @private */
12020     getFxRestore : function(){
12021         var st = this.dom.style;
12022         return {pos: this.getPositioning(), width: st.width, height : st.height};
12023     },
12024
12025         /* @private */
12026     afterFx : function(o){
12027         if(o.afterStyle){
12028             this.applyStyles(o.afterStyle);
12029         }
12030         if(o.afterCls){
12031             this.addClass(o.afterCls);
12032         }
12033         if(o.remove === true){
12034             this.remove();
12035         }
12036         Roo.callback(o.callback, o.scope, [this]);
12037         if(!o.concurrent){
12038             this.fxQueue.shift();
12039             this.nextFx();
12040         }
12041     },
12042
12043         /* @private */
12044     getFxEl : function(){ // support for composite element fx
12045         return Roo.get(this.dom);
12046     },
12047
12048         /* @private */
12049     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12050         animType = animType || 'run';
12051         opt = opt || {};
12052         var anim = Roo.lib.Anim[animType](
12053             this.dom, args,
12054             (opt.duration || defaultDur) || .35,
12055             (opt.easing || defaultEase) || 'easeOut',
12056             function(){
12057                 Roo.callback(cb, this);
12058             },
12059             this
12060         );
12061         opt.anim = anim;
12062         return anim;
12063     }
12064 };
12065
12066 // backwords compat
12067 Roo.Fx.resize = Roo.Fx.scale;
12068
12069 //When included, Roo.Fx is automatically applied to Element so that all basic
12070 //effects are available directly via the Element API
12071 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12072  * Based on:
12073  * Ext JS Library 1.1.1
12074  * Copyright(c) 2006-2007, Ext JS, LLC.
12075  *
12076  * Originally Released Under LGPL - original licence link has changed is not relivant.
12077  *
12078  * Fork - LGPL
12079  * <script type="text/javascript">
12080  */
12081
12082
12083 /**
12084  * @class Roo.CompositeElement
12085  * Standard composite class. Creates a Roo.Element for every element in the collection.
12086  * <br><br>
12087  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12088  * actions will be performed on all the elements in this collection.</b>
12089  * <br><br>
12090  * All methods return <i>this</i> and can be chained.
12091  <pre><code>
12092  var els = Roo.select("#some-el div.some-class", true);
12093  // or select directly from an existing element
12094  var el = Roo.get('some-el');
12095  el.select('div.some-class', true);
12096
12097  els.setWidth(100); // all elements become 100 width
12098  els.hide(true); // all elements fade out and hide
12099  // or
12100  els.setWidth(100).hide(true);
12101  </code></pre>
12102  */
12103 Roo.CompositeElement = function(els){
12104     this.elements = [];
12105     this.addElements(els);
12106 };
12107 Roo.CompositeElement.prototype = {
12108     isComposite: true,
12109     addElements : function(els){
12110         if(!els) {
12111             return this;
12112         }
12113         if(typeof els == "string"){
12114             els = Roo.Element.selectorFunction(els);
12115         }
12116         var yels = this.elements;
12117         var index = yels.length-1;
12118         for(var i = 0, len = els.length; i < len; i++) {
12119                 yels[++index] = Roo.get(els[i]);
12120         }
12121         return this;
12122     },
12123
12124     /**
12125     * Clears this composite and adds the elements returned by the passed selector.
12126     * @param {String/Array} els A string CSS selector, an array of elements or an element
12127     * @return {CompositeElement} this
12128     */
12129     fill : function(els){
12130         this.elements = [];
12131         this.add(els);
12132         return this;
12133     },
12134
12135     /**
12136     * Filters this composite to only elements that match the passed selector.
12137     * @param {String} selector A string CSS selector
12138     * @param {Boolean} inverse return inverse filter (not matches)
12139     * @return {CompositeElement} this
12140     */
12141     filter : function(selector, inverse){
12142         var els = [];
12143         inverse = inverse || false;
12144         this.each(function(el){
12145             var match = inverse ? !el.is(selector) : el.is(selector);
12146             if(match){
12147                 els[els.length] = el.dom;
12148             }
12149         });
12150         this.fill(els);
12151         return this;
12152     },
12153
12154     invoke : function(fn, args){
12155         var els = this.elements;
12156         for(var i = 0, len = els.length; i < len; i++) {
12157                 Roo.Element.prototype[fn].apply(els[i], args);
12158         }
12159         return this;
12160     },
12161     /**
12162     * Adds elements to this composite.
12163     * @param {String/Array} els A string CSS selector, an array of elements or an element
12164     * @return {CompositeElement} this
12165     */
12166     add : function(els){
12167         if(typeof els == "string"){
12168             this.addElements(Roo.Element.selectorFunction(els));
12169         }else if(els.length !== undefined){
12170             this.addElements(els);
12171         }else{
12172             this.addElements([els]);
12173         }
12174         return this;
12175     },
12176     /**
12177     * Calls the passed function passing (el, this, index) for each element in this composite.
12178     * @param {Function} fn The function to call
12179     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12180     * @return {CompositeElement} this
12181     */
12182     each : function(fn, scope){
12183         var els = this.elements;
12184         for(var i = 0, len = els.length; i < len; i++){
12185             if(fn.call(scope || els[i], els[i], this, i) === false) {
12186                 break;
12187             }
12188         }
12189         return this;
12190     },
12191
12192     /**
12193      * Returns the Element object at the specified index
12194      * @param {Number} index
12195      * @return {Roo.Element}
12196      */
12197     item : function(index){
12198         return this.elements[index] || null;
12199     },
12200
12201     /**
12202      * Returns the first Element
12203      * @return {Roo.Element}
12204      */
12205     first : function(){
12206         return this.item(0);
12207     },
12208
12209     /**
12210      * Returns the last Element
12211      * @return {Roo.Element}
12212      */
12213     last : function(){
12214         return this.item(this.elements.length-1);
12215     },
12216
12217     /**
12218      * Returns the number of elements in this composite
12219      * @return Number
12220      */
12221     getCount : function(){
12222         return this.elements.length;
12223     },
12224
12225     /**
12226      * Returns true if this composite contains the passed element
12227      * @return Boolean
12228      */
12229     contains : function(el){
12230         return this.indexOf(el) !== -1;
12231     },
12232
12233     /**
12234      * Returns true if this composite contains the passed element
12235      * @return Boolean
12236      */
12237     indexOf : function(el){
12238         return this.elements.indexOf(Roo.get(el));
12239     },
12240
12241
12242     /**
12243     * Removes the specified element(s).
12244     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12245     * or an array of any of those.
12246     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12247     * @return {CompositeElement} this
12248     */
12249     removeElement : function(el, removeDom){
12250         if(el instanceof Array){
12251             for(var i = 0, len = el.length; i < len; i++){
12252                 this.removeElement(el[i]);
12253             }
12254             return this;
12255         }
12256         var index = typeof el == 'number' ? el : this.indexOf(el);
12257         if(index !== -1){
12258             if(removeDom){
12259                 var d = this.elements[index];
12260                 if(d.dom){
12261                     d.remove();
12262                 }else{
12263                     d.parentNode.removeChild(d);
12264                 }
12265             }
12266             this.elements.splice(index, 1);
12267         }
12268         return this;
12269     },
12270
12271     /**
12272     * Replaces the specified element with the passed element.
12273     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12274     * to replace.
12275     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12276     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12277     * @return {CompositeElement} this
12278     */
12279     replaceElement : function(el, replacement, domReplace){
12280         var index = typeof el == 'number' ? el : this.indexOf(el);
12281         if(index !== -1){
12282             if(domReplace){
12283                 this.elements[index].replaceWith(replacement);
12284             }else{
12285                 this.elements.splice(index, 1, Roo.get(replacement))
12286             }
12287         }
12288         return this;
12289     },
12290
12291     /**
12292      * Removes all elements.
12293      */
12294     clear : function(){
12295         this.elements = [];
12296     }
12297 };
12298 (function(){
12299     Roo.CompositeElement.createCall = function(proto, fnName){
12300         if(!proto[fnName]){
12301             proto[fnName] = function(){
12302                 return this.invoke(fnName, arguments);
12303             };
12304         }
12305     };
12306     for(var fnName in Roo.Element.prototype){
12307         if(typeof Roo.Element.prototype[fnName] == "function"){
12308             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12309         }
12310     };
12311 })();
12312 /*
12313  * Based on:
12314  * Ext JS Library 1.1.1
12315  * Copyright(c) 2006-2007, Ext JS, LLC.
12316  *
12317  * Originally Released Under LGPL - original licence link has changed is not relivant.
12318  *
12319  * Fork - LGPL
12320  * <script type="text/javascript">
12321  */
12322
12323 /**
12324  * @class Roo.CompositeElementLite
12325  * @extends Roo.CompositeElement
12326  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12327  <pre><code>
12328  var els = Roo.select("#some-el div.some-class");
12329  // or select directly from an existing element
12330  var el = Roo.get('some-el');
12331  el.select('div.some-class');
12332
12333  els.setWidth(100); // all elements become 100 width
12334  els.hide(true); // all elements fade out and hide
12335  // or
12336  els.setWidth(100).hide(true);
12337  </code></pre><br><br>
12338  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12339  * actions will be performed on all the elements in this collection.</b>
12340  */
12341 Roo.CompositeElementLite = function(els){
12342     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12343     this.el = new Roo.Element.Flyweight();
12344 };
12345 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12346     addElements : function(els){
12347         if(els){
12348             if(els instanceof Array){
12349                 this.elements = this.elements.concat(els);
12350             }else{
12351                 var yels = this.elements;
12352                 var index = yels.length-1;
12353                 for(var i = 0, len = els.length; i < len; i++) {
12354                     yels[++index] = els[i];
12355                 }
12356             }
12357         }
12358         return this;
12359     },
12360     invoke : function(fn, args){
12361         var els = this.elements;
12362         var el = this.el;
12363         for(var i = 0, len = els.length; i < len; i++) {
12364             el.dom = els[i];
12365                 Roo.Element.prototype[fn].apply(el, args);
12366         }
12367         return this;
12368     },
12369     /**
12370      * Returns a flyweight Element of the dom element object at the specified index
12371      * @param {Number} index
12372      * @return {Roo.Element}
12373      */
12374     item : function(index){
12375         if(!this.elements[index]){
12376             return null;
12377         }
12378         this.el.dom = this.elements[index];
12379         return this.el;
12380     },
12381
12382     // fixes scope with flyweight
12383     addListener : function(eventName, handler, scope, opt){
12384         var els = this.elements;
12385         for(var i = 0, len = els.length; i < len; i++) {
12386             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12387         }
12388         return this;
12389     },
12390
12391     /**
12392     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12393     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12394     * a reference to the dom node, use el.dom.</b>
12395     * @param {Function} fn The function to call
12396     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12397     * @return {CompositeElement} this
12398     */
12399     each : function(fn, scope){
12400         var els = this.elements;
12401         var el = this.el;
12402         for(var i = 0, len = els.length; i < len; i++){
12403             el.dom = els[i];
12404                 if(fn.call(scope || el, el, this, i) === false){
12405                 break;
12406             }
12407         }
12408         return this;
12409     },
12410
12411     indexOf : function(el){
12412         return this.elements.indexOf(Roo.getDom(el));
12413     },
12414
12415     replaceElement : function(el, replacement, domReplace){
12416         var index = typeof el == 'number' ? el : this.indexOf(el);
12417         if(index !== -1){
12418             replacement = Roo.getDom(replacement);
12419             if(domReplace){
12420                 var d = this.elements[index];
12421                 d.parentNode.insertBefore(replacement, d);
12422                 d.parentNode.removeChild(d);
12423             }
12424             this.elements.splice(index, 1, replacement);
12425         }
12426         return this;
12427     }
12428 });
12429 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12430
12431 /*
12432  * Based on:
12433  * Ext JS Library 1.1.1
12434  * Copyright(c) 2006-2007, Ext JS, LLC.
12435  *
12436  * Originally Released Under LGPL - original licence link has changed is not relivant.
12437  *
12438  * Fork - LGPL
12439  * <script type="text/javascript">
12440  */
12441
12442  
12443
12444 /**
12445  * @class Roo.data.Connection
12446  * @extends Roo.util.Observable
12447  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12448  * either to a configured URL, or to a URL specified at request time. 
12449  * 
12450  * Requests made by this class are asynchronous, and will return immediately. No data from
12451  * the server will be available to the statement immediately following the {@link #request} call.
12452  * To process returned data, use a callback in the request options object, or an event listener.
12453  * 
12454  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12455  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12456  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12457  * property and, if present, the IFRAME's XML document as the responseXML property.
12458  * 
12459  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12460  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12461  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12462  * standard DOM methods.
12463  * @constructor
12464  * @param {Object} config a configuration object.
12465  */
12466 Roo.data.Connection = function(config){
12467     Roo.apply(this, config);
12468     this.addEvents({
12469         /**
12470          * @event beforerequest
12471          * Fires before a network request is made to retrieve a data object.
12472          * @param {Connection} conn This Connection object.
12473          * @param {Object} options The options config object passed to the {@link #request} method.
12474          */
12475         "beforerequest" : true,
12476         /**
12477          * @event requestcomplete
12478          * Fires if the request was successfully completed.
12479          * @param {Connection} conn This Connection object.
12480          * @param {Object} response The XHR object containing the response data.
12481          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12482          * @param {Object} options The options config object passed to the {@link #request} method.
12483          */
12484         "requestcomplete" : true,
12485         /**
12486          * @event requestexception
12487          * Fires if an error HTTP status was returned from the server.
12488          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12489          * @param {Connection} conn This Connection object.
12490          * @param {Object} response The XHR object containing the response data.
12491          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12492          * @param {Object} options The options config object passed to the {@link #request} method.
12493          */
12494         "requestexception" : true
12495     });
12496     Roo.data.Connection.superclass.constructor.call(this);
12497 };
12498
12499 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12500     /**
12501      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12502      */
12503     /**
12504      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12505      * extra parameters to each request made by this object. (defaults to undefined)
12506      */
12507     /**
12508      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12509      *  to each request made by this object. (defaults to undefined)
12510      */
12511     /**
12512      * @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)
12513      */
12514     /**
12515      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12516      */
12517     timeout : 30000,
12518     /**
12519      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12520      * @type Boolean
12521      */
12522     autoAbort:false,
12523
12524     /**
12525      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12526      * @type Boolean
12527      */
12528     disableCaching: true,
12529
12530     /**
12531      * Sends an HTTP request to a remote server.
12532      * @param {Object} options An object which may contain the following properties:<ul>
12533      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12534      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12535      * request, a url encoded string or a function to call to get either.</li>
12536      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12537      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12538      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12539      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12540      * <li>options {Object} The parameter to the request call.</li>
12541      * <li>success {Boolean} True if the request succeeded.</li>
12542      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12543      * </ul></li>
12544      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12545      * The callback is passed the following parameters:<ul>
12546      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12547      * <li>options {Object} The parameter to the request call.</li>
12548      * </ul></li>
12549      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12550      * The callback is passed the following parameters:<ul>
12551      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12552      * <li>options {Object} The parameter to the request call.</li>
12553      * </ul></li>
12554      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12555      * for the callback function. Defaults to the browser window.</li>
12556      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12557      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12558      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12559      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12560      * params for the post data. Any params will be appended to the URL.</li>
12561      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12562      * </ul>
12563      * @return {Number} transactionId
12564      */
12565     request : function(o){
12566         if(this.fireEvent("beforerequest", this, o) !== false){
12567             var p = o.params;
12568
12569             if(typeof p == "function"){
12570                 p = p.call(o.scope||window, o);
12571             }
12572             if(typeof p == "object"){
12573                 p = Roo.urlEncode(o.params);
12574             }
12575             if(this.extraParams){
12576                 var extras = Roo.urlEncode(this.extraParams);
12577                 p = p ? (p + '&' + extras) : extras;
12578             }
12579
12580             var url = o.url || this.url;
12581             if(typeof url == 'function'){
12582                 url = url.call(o.scope||window, o);
12583             }
12584
12585             if(o.form){
12586                 var form = Roo.getDom(o.form);
12587                 url = url || form.action;
12588
12589                 var enctype = form.getAttribute("enctype");
12590                 
12591                 if (o.formData) {
12592                     return this.doFormDataUpload(o, url);
12593                 }
12594                 
12595                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12596                     return this.doFormUpload(o, p, url);
12597                 }
12598                 var f = Roo.lib.Ajax.serializeForm(form);
12599                 p = p ? (p + '&' + f) : f;
12600             }
12601             
12602             if (!o.form && o.formData) {
12603                 o.formData = o.formData === true ? new FormData() : o.formData;
12604                 for (var k in o.params) {
12605                     o.formData.append(k,o.params[k]);
12606                 }
12607                     
12608                 return this.doFormDataUpload(o, url);
12609             }
12610             
12611
12612             var hs = o.headers;
12613             if(this.defaultHeaders){
12614                 hs = Roo.apply(hs || {}, this.defaultHeaders);
12615                 if(!o.headers){
12616                     o.headers = hs;
12617                 }
12618             }
12619
12620             var cb = {
12621                 success: this.handleResponse,
12622                 failure: this.handleFailure,
12623                 scope: this,
12624                 argument: {options: o},
12625                 timeout : o.timeout || this.timeout
12626             };
12627
12628             var method = o.method||this.method||(p ? "POST" : "GET");
12629
12630             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12631                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12632             }
12633
12634             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12635                 if(o.autoAbort){
12636                     this.abort();
12637                 }
12638             }else if(this.autoAbort !== false){
12639                 this.abort();
12640             }
12641
12642             if((method == 'GET' && p) || o.xmlData){
12643                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12644                 p = '';
12645             }
12646             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12647             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12648             Roo.lib.Ajax.useDefaultHeader == true;
12649             return this.transId;
12650         }else{
12651             Roo.callback(o.callback, o.scope, [o, null, null]);
12652             return null;
12653         }
12654     },
12655
12656     /**
12657      * Determine whether this object has a request outstanding.
12658      * @param {Number} transactionId (Optional) defaults to the last transaction
12659      * @return {Boolean} True if there is an outstanding request.
12660      */
12661     isLoading : function(transId){
12662         if(transId){
12663             return Roo.lib.Ajax.isCallInProgress(transId);
12664         }else{
12665             return this.transId ? true : false;
12666         }
12667     },
12668
12669     /**
12670      * Aborts any outstanding request.
12671      * @param {Number} transactionId (Optional) defaults to the last transaction
12672      */
12673     abort : function(transId){
12674         if(transId || this.isLoading()){
12675             Roo.lib.Ajax.abort(transId || this.transId);
12676         }
12677     },
12678
12679     // private
12680     handleResponse : function(response){
12681         this.transId = false;
12682         var options = response.argument.options;
12683         response.argument = options ? options.argument : null;
12684         this.fireEvent("requestcomplete", this, response, options);
12685         Roo.callback(options.success, options.scope, [response, options]);
12686         Roo.callback(options.callback, options.scope, [options, true, response]);
12687     },
12688
12689     // private
12690     handleFailure : function(response, e){
12691         this.transId = false;
12692         var options = response.argument.options;
12693         response.argument = options ? options.argument : null;
12694         this.fireEvent("requestexception", this, response, options, e);
12695         Roo.callback(options.failure, options.scope, [response, options]);
12696         Roo.callback(options.callback, options.scope, [options, false, response]);
12697     },
12698
12699     // private
12700     doFormUpload : function(o, ps, url){
12701         var id = Roo.id();
12702         var frame = document.createElement('iframe');
12703         frame.id = id;
12704         frame.name = id;
12705         frame.className = 'x-hidden';
12706         if(Roo.isIE){
12707             frame.src = Roo.SSL_SECURE_URL;
12708         }
12709         document.body.appendChild(frame);
12710
12711         if(Roo.isIE){
12712            document.frames[id].name = id;
12713         }
12714
12715         var form = Roo.getDom(o.form);
12716         form.target = id;
12717         form.method = 'POST';
12718         form.enctype = form.encoding = 'multipart/form-data';
12719         if(url){
12720             form.action = url;
12721         }
12722
12723         var hiddens, hd;
12724         if(ps){ // add dynamic params
12725             hiddens = [];
12726             ps = Roo.urlDecode(ps, false);
12727             for(var k in ps){
12728                 if(ps.hasOwnProperty(k)){
12729                     hd = document.createElement('input');
12730                     hd.type = 'hidden';
12731                     hd.name = k;
12732                     hd.value = ps[k];
12733                     form.appendChild(hd);
12734                     hiddens.push(hd);
12735                 }
12736             }
12737         }
12738
12739         function cb(){
12740             var r = {  // bogus response object
12741                 responseText : '',
12742                 responseXML : null
12743             };
12744
12745             r.argument = o ? o.argument : null;
12746
12747             try { //
12748                 var doc;
12749                 if(Roo.isIE){
12750                     doc = frame.contentWindow.document;
12751                 }else {
12752                     doc = (frame.contentDocument || window.frames[id].document);
12753                 }
12754                 if(doc && doc.body){
12755                     r.responseText = doc.body.innerHTML;
12756                 }
12757                 if(doc && doc.XMLDocument){
12758                     r.responseXML = doc.XMLDocument;
12759                 }else {
12760                     r.responseXML = doc;
12761                 }
12762             }
12763             catch(e) {
12764                 // ignore
12765             }
12766
12767             Roo.EventManager.removeListener(frame, 'load', cb, this);
12768
12769             this.fireEvent("requestcomplete", this, r, o);
12770             Roo.callback(o.success, o.scope, [r, o]);
12771             Roo.callback(o.callback, o.scope, [o, true, r]);
12772
12773             setTimeout(function(){document.body.removeChild(frame);}, 100);
12774         }
12775
12776         Roo.EventManager.on(frame, 'load', cb, this);
12777         form.submit();
12778
12779         if(hiddens){ // remove dynamic params
12780             for(var i = 0, len = hiddens.length; i < len; i++){
12781                 form.removeChild(hiddens[i]);
12782             }
12783         }
12784     },
12785     // this is a 'formdata version???'
12786     
12787     
12788     doFormDataUpload : function(o,  url)
12789     {
12790         var formData;
12791         if (o.form) {
12792             var form =  Roo.getDom(o.form);
12793             form.enctype = form.encoding = 'multipart/form-data';
12794             formData = o.formData === true ? new FormData(form) : o.formData;
12795         } else {
12796             formData = o.formData === true ? new FormData() : o.formData;
12797         }
12798         
12799       
12800         var cb = {
12801             success: this.handleResponse,
12802             failure: this.handleFailure,
12803             scope: this,
12804             argument: {options: o},
12805             timeout : o.timeout || this.timeout
12806         };
12807  
12808         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12809             if(o.autoAbort){
12810                 this.abort();
12811             }
12812         }else if(this.autoAbort !== false){
12813             this.abort();
12814         }
12815
12816         //Roo.lib.Ajax.defaultPostHeader = null;
12817         Roo.lib.Ajax.useDefaultHeader = false;
12818         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
12819         Roo.lib.Ajax.useDefaultHeader = true;
12820  
12821          
12822     }
12823     
12824 });
12825 /*
12826  * Based on:
12827  * Ext JS Library 1.1.1
12828  * Copyright(c) 2006-2007, Ext JS, LLC.
12829  *
12830  * Originally Released Under LGPL - original licence link has changed is not relivant.
12831  *
12832  * Fork - LGPL
12833  * <script type="text/javascript">
12834  */
12835  
12836 /**
12837  * Global Ajax request class.
12838  * 
12839  * @class Roo.Ajax
12840  * @extends Roo.data.Connection
12841  * @static
12842  * 
12843  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
12844  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12845  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
12846  * @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)
12847  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12848  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12849  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
12850  */
12851 Roo.Ajax = new Roo.data.Connection({
12852     // fix up the docs
12853     /**
12854      * @scope Roo.Ajax
12855      * @type {Boolear} 
12856      */
12857     autoAbort : false,
12858
12859     /**
12860      * Serialize the passed form into a url encoded string
12861      * @scope Roo.Ajax
12862      * @param {String/HTMLElement} form
12863      * @return {String}
12864      */
12865     serializeForm : function(form){
12866         return Roo.lib.Ajax.serializeForm(form);
12867     }
12868 });/*
12869  * Based on:
12870  * Ext JS Library 1.1.1
12871  * Copyright(c) 2006-2007, Ext JS, LLC.
12872  *
12873  * Originally Released Under LGPL - original licence link has changed is not relivant.
12874  *
12875  * Fork - LGPL
12876  * <script type="text/javascript">
12877  */
12878
12879  
12880 /**
12881  * @class Roo.UpdateManager
12882  * @extends Roo.util.Observable
12883  * Provides AJAX-style update for Element object.<br><br>
12884  * Usage:<br>
12885  * <pre><code>
12886  * // Get it from a Roo.Element object
12887  * var el = Roo.get("foo");
12888  * var mgr = el.getUpdateManager();
12889  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
12890  * ...
12891  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12892  * <br>
12893  * // or directly (returns the same UpdateManager instance)
12894  * var mgr = new Roo.UpdateManager("myElementId");
12895  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12896  * mgr.on("update", myFcnNeedsToKnow);
12897  * <br>
12898    // short handed call directly from the element object
12899    Roo.get("foo").load({
12900         url: "bar.php",
12901         scripts:true,
12902         params: "for=bar",
12903         text: "Loading Foo..."
12904    });
12905  * </code></pre>
12906  * @constructor
12907  * Create new UpdateManager directly.
12908  * @param {String/HTMLElement/Roo.Element} el The element to update
12909  * @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).
12910  */
12911 Roo.UpdateManager = function(el, forceNew){
12912     el = Roo.get(el);
12913     if(!forceNew && el.updateManager){
12914         return el.updateManager;
12915     }
12916     /**
12917      * The Element object
12918      * @type Roo.Element
12919      */
12920     this.el = el;
12921     /**
12922      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12923      * @type String
12924      */
12925     this.defaultUrl = null;
12926
12927     this.addEvents({
12928         /**
12929          * @event beforeupdate
12930          * Fired before an update is made, return false from your handler and the update is cancelled.
12931          * @param {Roo.Element} el
12932          * @param {String/Object/Function} url
12933          * @param {String/Object} params
12934          */
12935         "beforeupdate": true,
12936         /**
12937          * @event update
12938          * Fired after successful update is made.
12939          * @param {Roo.Element} el
12940          * @param {Object} oResponseObject The response Object
12941          */
12942         "update": true,
12943         /**
12944          * @event failure
12945          * Fired on update failure.
12946          * @param {Roo.Element} el
12947          * @param {Object} oResponseObject The response Object
12948          */
12949         "failure": true
12950     });
12951     var d = Roo.UpdateManager.defaults;
12952     /**
12953      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12954      * @type String
12955      */
12956     this.sslBlankUrl = d.sslBlankUrl;
12957     /**
12958      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12959      * @type Boolean
12960      */
12961     this.disableCaching = d.disableCaching;
12962     /**
12963      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12964      * @type String
12965      */
12966     this.indicatorText = d.indicatorText;
12967     /**
12968      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12969      * @type String
12970      */
12971     this.showLoadIndicator = d.showLoadIndicator;
12972     /**
12973      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12974      * @type Number
12975      */
12976     this.timeout = d.timeout;
12977
12978     /**
12979      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12980      * @type Boolean
12981      */
12982     this.loadScripts = d.loadScripts;
12983
12984     /**
12985      * Transaction object of current executing transaction
12986      */
12987     this.transaction = null;
12988
12989     /**
12990      * @private
12991      */
12992     this.autoRefreshProcId = null;
12993     /**
12994      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12995      * @type Function
12996      */
12997     this.refreshDelegate = this.refresh.createDelegate(this);
12998     /**
12999      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13000      * @type Function
13001      */
13002     this.updateDelegate = this.update.createDelegate(this);
13003     /**
13004      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13005      * @type Function
13006      */
13007     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13008     /**
13009      * @private
13010      */
13011     this.successDelegate = this.processSuccess.createDelegate(this);
13012     /**
13013      * @private
13014      */
13015     this.failureDelegate = this.processFailure.createDelegate(this);
13016
13017     if(!this.renderer){
13018      /**
13019       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13020       */
13021     this.renderer = new Roo.UpdateManager.BasicRenderer();
13022     }
13023     
13024     Roo.UpdateManager.superclass.constructor.call(this);
13025 };
13026
13027 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13028     /**
13029      * Get the Element this UpdateManager is bound to
13030      * @return {Roo.Element} The element
13031      */
13032     getEl : function(){
13033         return this.el;
13034     },
13035     /**
13036      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13037      * @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:
13038 <pre><code>
13039 um.update({<br/>
13040     url: "your-url.php",<br/>
13041     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13042     callback: yourFunction,<br/>
13043     scope: yourObject, //(optional scope)  <br/>
13044     discardUrl: false, <br/>
13045     nocache: false,<br/>
13046     text: "Loading...",<br/>
13047     timeout: 30,<br/>
13048     scripts: false<br/>
13049 });
13050 </code></pre>
13051      * The only required property is url. The optional properties nocache, text and scripts
13052      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13053      * @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}
13054      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13055      * @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.
13056      */
13057     update : function(url, params, callback, discardUrl){
13058         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13059             var method = this.method,
13060                 cfg;
13061             if(typeof url == "object"){ // must be config object
13062                 cfg = url;
13063                 url = cfg.url;
13064                 params = params || cfg.params;
13065                 callback = callback || cfg.callback;
13066                 discardUrl = discardUrl || cfg.discardUrl;
13067                 if(callback && cfg.scope){
13068                     callback = callback.createDelegate(cfg.scope);
13069                 }
13070                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13071                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13072                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13073                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13074                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13075             }
13076             this.showLoading();
13077             if(!discardUrl){
13078                 this.defaultUrl = url;
13079             }
13080             if(typeof url == "function"){
13081                 url = url.call(this);
13082             }
13083
13084             method = method || (params ? "POST" : "GET");
13085             if(method == "GET"){
13086                 url = this.prepareUrl(url);
13087             }
13088
13089             var o = Roo.apply(cfg ||{}, {
13090                 url : url,
13091                 params: params,
13092                 success: this.successDelegate,
13093                 failure: this.failureDelegate,
13094                 callback: undefined,
13095                 timeout: (this.timeout*1000),
13096                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13097             });
13098             Roo.log("updated manager called with timeout of " + o.timeout);
13099             this.transaction = Roo.Ajax.request(o);
13100         }
13101     },
13102
13103     /**
13104      * 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.
13105      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13106      * @param {String/HTMLElement} form The form Id or form element
13107      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13108      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13109      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13110      */
13111     formUpdate : function(form, url, reset, callback){
13112         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13113             if(typeof url == "function"){
13114                 url = url.call(this);
13115             }
13116             form = Roo.getDom(form);
13117             this.transaction = Roo.Ajax.request({
13118                 form: form,
13119                 url:url,
13120                 success: this.successDelegate,
13121                 failure: this.failureDelegate,
13122                 timeout: (this.timeout*1000),
13123                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13124             });
13125             this.showLoading.defer(1, this);
13126         }
13127     },
13128
13129     /**
13130      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13131      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13132      */
13133     refresh : function(callback){
13134         if(this.defaultUrl == null){
13135             return;
13136         }
13137         this.update(this.defaultUrl, null, callback, true);
13138     },
13139
13140     /**
13141      * Set this element to auto refresh.
13142      * @param {Number} interval How often to update (in seconds).
13143      * @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)
13144      * @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}
13145      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13146      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13147      */
13148     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13149         if(refreshNow){
13150             this.update(url || this.defaultUrl, params, callback, true);
13151         }
13152         if(this.autoRefreshProcId){
13153             clearInterval(this.autoRefreshProcId);
13154         }
13155         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13156     },
13157
13158     /**
13159      * Stop auto refresh on this element.
13160      */
13161      stopAutoRefresh : function(){
13162         if(this.autoRefreshProcId){
13163             clearInterval(this.autoRefreshProcId);
13164             delete this.autoRefreshProcId;
13165         }
13166     },
13167
13168     isAutoRefreshing : function(){
13169        return this.autoRefreshProcId ? true : false;
13170     },
13171     /**
13172      * Called to update the element to "Loading" state. Override to perform custom action.
13173      */
13174     showLoading : function(){
13175         if(this.showLoadIndicator){
13176             this.el.update(this.indicatorText);
13177         }
13178     },
13179
13180     /**
13181      * Adds unique parameter to query string if disableCaching = true
13182      * @private
13183      */
13184     prepareUrl : function(url){
13185         if(this.disableCaching){
13186             var append = "_dc=" + (new Date().getTime());
13187             if(url.indexOf("?") !== -1){
13188                 url += "&" + append;
13189             }else{
13190                 url += "?" + append;
13191             }
13192         }
13193         return url;
13194     },
13195
13196     /**
13197      * @private
13198      */
13199     processSuccess : function(response){
13200         this.transaction = null;
13201         if(response.argument.form && response.argument.reset){
13202             try{ // put in try/catch since some older FF releases had problems with this
13203                 response.argument.form.reset();
13204             }catch(e){}
13205         }
13206         if(this.loadScripts){
13207             this.renderer.render(this.el, response, this,
13208                 this.updateComplete.createDelegate(this, [response]));
13209         }else{
13210             this.renderer.render(this.el, response, this);
13211             this.updateComplete(response);
13212         }
13213     },
13214
13215     updateComplete : function(response){
13216         this.fireEvent("update", this.el, response);
13217         if(typeof response.argument.callback == "function"){
13218             response.argument.callback(this.el, true, response);
13219         }
13220     },
13221
13222     /**
13223      * @private
13224      */
13225     processFailure : function(response){
13226         this.transaction = null;
13227         this.fireEvent("failure", this.el, response);
13228         if(typeof response.argument.callback == "function"){
13229             response.argument.callback(this.el, false, response);
13230         }
13231     },
13232
13233     /**
13234      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13235      * @param {Object} renderer The object implementing the render() method
13236      */
13237     setRenderer : function(renderer){
13238         this.renderer = renderer;
13239     },
13240
13241     getRenderer : function(){
13242        return this.renderer;
13243     },
13244
13245     /**
13246      * Set the defaultUrl used for updates
13247      * @param {String/Function} defaultUrl The url or a function to call to get the url
13248      */
13249     setDefaultUrl : function(defaultUrl){
13250         this.defaultUrl = defaultUrl;
13251     },
13252
13253     /**
13254      * Aborts the executing transaction
13255      */
13256     abort : function(){
13257         if(this.transaction){
13258             Roo.Ajax.abort(this.transaction);
13259         }
13260     },
13261
13262     /**
13263      * Returns true if an update is in progress
13264      * @return {Boolean}
13265      */
13266     isUpdating : function(){
13267         if(this.transaction){
13268             return Roo.Ajax.isLoading(this.transaction);
13269         }
13270         return false;
13271     }
13272 });
13273
13274 /**
13275  * @class Roo.UpdateManager.defaults
13276  * @static (not really - but it helps the doc tool)
13277  * The defaults collection enables customizing the default properties of UpdateManager
13278  */
13279    Roo.UpdateManager.defaults = {
13280        /**
13281          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13282          * @type Number
13283          */
13284          timeout : 30,
13285
13286          /**
13287          * True to process scripts by default (Defaults to false).
13288          * @type Boolean
13289          */
13290         loadScripts : false,
13291
13292         /**
13293         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13294         * @type String
13295         */
13296         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13297         /**
13298          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13299          * @type Boolean
13300          */
13301         disableCaching : false,
13302         /**
13303          * Whether to show indicatorText when loading (Defaults to true).
13304          * @type Boolean
13305          */
13306         showLoadIndicator : true,
13307         /**
13308          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13309          * @type String
13310          */
13311         indicatorText : '<div class="loading-indicator">Loading...</div>'
13312    };
13313
13314 /**
13315  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13316  *Usage:
13317  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13318  * @param {String/HTMLElement/Roo.Element} el The element to update
13319  * @param {String} url The url
13320  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13321  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13322  * @static
13323  * @deprecated
13324  * @member Roo.UpdateManager
13325  */
13326 Roo.UpdateManager.updateElement = function(el, url, params, options){
13327     var um = Roo.get(el, true).getUpdateManager();
13328     Roo.apply(um, options);
13329     um.update(url, params, options ? options.callback : null);
13330 };
13331 // alias for backwards compat
13332 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13333 /**
13334  * @class Roo.UpdateManager.BasicRenderer
13335  * Default Content renderer. Updates the elements innerHTML with the responseText.
13336  */
13337 Roo.UpdateManager.BasicRenderer = function(){};
13338
13339 Roo.UpdateManager.BasicRenderer.prototype = {
13340     /**
13341      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13342      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13343      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13344      * @param {Roo.Element} el The element being rendered
13345      * @param {Object} response The YUI Connect response object
13346      * @param {UpdateManager} updateManager The calling update manager
13347      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13348      */
13349      render : function(el, response, updateManager, callback){
13350         el.update(response.responseText, updateManager.loadScripts, callback);
13351     }
13352 };
13353 /*
13354  * Based on:
13355  * Roo JS
13356  * (c)) Alan Knowles
13357  * Licence : LGPL
13358  */
13359
13360
13361 /**
13362  * @class Roo.DomTemplate
13363  * @extends Roo.Template
13364  * An effort at a dom based template engine..
13365  *
13366  * Similar to XTemplate, except it uses dom parsing to create the template..
13367  *
13368  * Supported features:
13369  *
13370  *  Tags:
13371
13372 <pre><code>
13373       {a_variable} - output encoded.
13374       {a_variable.format:("Y-m-d")} - call a method on the variable
13375       {a_variable:raw} - unencoded output
13376       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13377       {a_variable:this.method_on_template(...)} - call a method on the template object.
13378  
13379 </code></pre>
13380  *  The tpl tag:
13381 <pre><code>
13382         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13383         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13384         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13385         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13386   
13387 </code></pre>
13388  *      
13389  */
13390 Roo.DomTemplate = function()
13391 {
13392      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13393      if (this.html) {
13394         this.compile();
13395      }
13396 };
13397
13398
13399 Roo.extend(Roo.DomTemplate, Roo.Template, {
13400     /**
13401      * id counter for sub templates.
13402      */
13403     id : 0,
13404     /**
13405      * flag to indicate if dom parser is inside a pre,
13406      * it will strip whitespace if not.
13407      */
13408     inPre : false,
13409     
13410     /**
13411      * The various sub templates
13412      */
13413     tpls : false,
13414     
13415     
13416     
13417     /**
13418      *
13419      * basic tag replacing syntax
13420      * WORD:WORD()
13421      *
13422      * // you can fake an object call by doing this
13423      *  x.t:(test,tesT) 
13424      * 
13425      */
13426     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13427     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13428     
13429     iterChild : function (node, method) {
13430         
13431         var oldPre = this.inPre;
13432         if (node.tagName == 'PRE') {
13433             this.inPre = true;
13434         }
13435         for( var i = 0; i < node.childNodes.length; i++) {
13436             method.call(this, node.childNodes[i]);
13437         }
13438         this.inPre = oldPre;
13439     },
13440     
13441     
13442     
13443     /**
13444      * compile the template
13445      *
13446      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13447      *
13448      */
13449     compile: function()
13450     {
13451         var s = this.html;
13452         
13453         // covert the html into DOM...
13454         var doc = false;
13455         var div =false;
13456         try {
13457             doc = document.implementation.createHTMLDocument("");
13458             doc.documentElement.innerHTML =   this.html  ;
13459             div = doc.documentElement;
13460         } catch (e) {
13461             // old IE... - nasty -- it causes all sorts of issues.. with
13462             // images getting pulled from server..
13463             div = document.createElement('div');
13464             div.innerHTML = this.html;
13465         }
13466         //doc.documentElement.innerHTML = htmlBody
13467          
13468         
13469         
13470         this.tpls = [];
13471         var _t = this;
13472         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13473         
13474         var tpls = this.tpls;
13475         
13476         // create a top level template from the snippet..
13477         
13478         //Roo.log(div.innerHTML);
13479         
13480         var tpl = {
13481             uid : 'master',
13482             id : this.id++,
13483             attr : false,
13484             value : false,
13485             body : div.innerHTML,
13486             
13487             forCall : false,
13488             execCall : false,
13489             dom : div,
13490             isTop : true
13491             
13492         };
13493         tpls.unshift(tpl);
13494         
13495         
13496         // compile them...
13497         this.tpls = [];
13498         Roo.each(tpls, function(tp){
13499             this.compileTpl(tp);
13500             this.tpls[tp.id] = tp;
13501         }, this);
13502         
13503         this.master = tpls[0];
13504         return this;
13505         
13506         
13507     },
13508     
13509     compileNode : function(node, istop) {
13510         // test for
13511         //Roo.log(node);
13512         
13513         
13514         // skip anything not a tag..
13515         if (node.nodeType != 1) {
13516             if (node.nodeType == 3 && !this.inPre) {
13517                 // reduce white space..
13518                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
13519                 
13520             }
13521             return;
13522         }
13523         
13524         var tpl = {
13525             uid : false,
13526             id : false,
13527             attr : false,
13528             value : false,
13529             body : '',
13530             
13531             forCall : false,
13532             execCall : false,
13533             dom : false,
13534             isTop : istop
13535             
13536             
13537         };
13538         
13539         
13540         switch(true) {
13541             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13542             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13543             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13544             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13545             // no default..
13546         }
13547         
13548         
13549         if (!tpl.attr) {
13550             // just itterate children..
13551             this.iterChild(node,this.compileNode);
13552             return;
13553         }
13554         tpl.uid = this.id++;
13555         tpl.value = node.getAttribute('roo-' +  tpl.attr);
13556         node.removeAttribute('roo-'+ tpl.attr);
13557         if (tpl.attr != 'name') {
13558             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13559             node.parentNode.replaceChild(placeholder,  node);
13560         } else {
13561             
13562             var placeholder =  document.createElement('span');
13563             placeholder.className = 'roo-tpl-' + tpl.value;
13564             node.parentNode.replaceChild(placeholder,  node);
13565         }
13566         
13567         // parent now sees '{domtplXXXX}
13568         this.iterChild(node,this.compileNode);
13569         
13570         // we should now have node body...
13571         var div = document.createElement('div');
13572         div.appendChild(node);
13573         tpl.dom = node;
13574         // this has the unfortunate side effect of converting tagged attributes
13575         // eg. href="{...}" into %7C...%7D
13576         // this has been fixed by searching for those combo's although it's a bit hacky..
13577         
13578         
13579         tpl.body = div.innerHTML;
13580         
13581         
13582          
13583         tpl.id = tpl.uid;
13584         switch(tpl.attr) {
13585             case 'for' :
13586                 switch (tpl.value) {
13587                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13588                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13589                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13590                 }
13591                 break;
13592             
13593             case 'exec':
13594                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13595                 break;
13596             
13597             case 'if':     
13598                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13599                 break;
13600             
13601             case 'name':
13602                 tpl.id  = tpl.value; // replace non characters???
13603                 break;
13604             
13605         }
13606         
13607         
13608         this.tpls.push(tpl);
13609         
13610         
13611         
13612     },
13613     
13614     
13615     
13616     
13617     /**
13618      * Compile a segment of the template into a 'sub-template'
13619      *
13620      * 
13621      * 
13622      *
13623      */
13624     compileTpl : function(tpl)
13625     {
13626         var fm = Roo.util.Format;
13627         var useF = this.disableFormats !== true;
13628         
13629         var sep = Roo.isGecko ? "+\n" : ",\n";
13630         
13631         var undef = function(str) {
13632             Roo.debug && Roo.log("Property not found :"  + str);
13633             return '';
13634         };
13635           
13636         //Roo.log(tpl.body);
13637         
13638         
13639         
13640         var fn = function(m, lbrace, name, format, args)
13641         {
13642             //Roo.log("ARGS");
13643             //Roo.log(arguments);
13644             args = args ? args.replace(/\\'/g,"'") : args;
13645             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13646             if (typeof(format) == 'undefined') {
13647                 format =  'htmlEncode'; 
13648             }
13649             if (format == 'raw' ) {
13650                 format = false;
13651             }
13652             
13653             if(name.substr(0, 6) == 'domtpl'){
13654                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13655             }
13656             
13657             // build an array of options to determine if value is undefined..
13658             
13659             // basically get 'xxxx.yyyy' then do
13660             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13661             //    (function () { Roo.log("Property not found"); return ''; })() :
13662             //    ......
13663             
13664             var udef_ar = [];
13665             var lookfor = '';
13666             Roo.each(name.split('.'), function(st) {
13667                 lookfor += (lookfor.length ? '.': '') + st;
13668                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
13669             });
13670             
13671             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13672             
13673             
13674             if(format && useF){
13675                 
13676                 args = args ? ',' + args : "";
13677                  
13678                 if(format.substr(0, 5) != "this."){
13679                     format = "fm." + format + '(';
13680                 }else{
13681                     format = 'this.call("'+ format.substr(5) + '", ';
13682                     args = ", values";
13683                 }
13684                 
13685                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
13686             }
13687              
13688             if (args && args.length) {
13689                 // called with xxyx.yuu:(test,test)
13690                 // change to ()
13691                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
13692             }
13693             // raw.. - :raw modifier..
13694             return "'"+ sep + udef_st  + name + ")"+sep+"'";
13695             
13696         };
13697         var body;
13698         // branched to use + in gecko and [].join() in others
13699         if(Roo.isGecko){
13700             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
13701                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13702                     "';};};";
13703         }else{
13704             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
13705             body.push(tpl.body.replace(/(\r\n|\n)/g,
13706                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13707             body.push("'].join('');};};");
13708             body = body.join('');
13709         }
13710         
13711         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13712        
13713         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
13714         eval(body);
13715         
13716         return this;
13717     },
13718      
13719     /**
13720      * same as applyTemplate, except it's done to one of the subTemplates
13721      * when using named templates, you can do:
13722      *
13723      * var str = pl.applySubTemplate('your-name', values);
13724      *
13725      * 
13726      * @param {Number} id of the template
13727      * @param {Object} values to apply to template
13728      * @param {Object} parent (normaly the instance of this object)
13729      */
13730     applySubTemplate : function(id, values, parent)
13731     {
13732         
13733         
13734         var t = this.tpls[id];
13735         
13736         
13737         try { 
13738             if(t.ifCall && !t.ifCall.call(this, values, parent)){
13739                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13740                 return '';
13741             }
13742         } catch(e) {
13743             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13744             Roo.log(values);
13745           
13746             return '';
13747         }
13748         try { 
13749             
13750             if(t.execCall && t.execCall.call(this, values, parent)){
13751                 return '';
13752             }
13753         } catch(e) {
13754             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13755             Roo.log(values);
13756             return '';
13757         }
13758         
13759         try {
13760             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13761             parent = t.target ? values : parent;
13762             if(t.forCall && vs instanceof Array){
13763                 var buf = [];
13764                 for(var i = 0, len = vs.length; i < len; i++){
13765                     try {
13766                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
13767                     } catch (e) {
13768                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13769                         Roo.log(e.body);
13770                         //Roo.log(t.compiled);
13771                         Roo.log(vs[i]);
13772                     }   
13773                 }
13774                 return buf.join('');
13775             }
13776         } catch (e) {
13777             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13778             Roo.log(values);
13779             return '';
13780         }
13781         try {
13782             return t.compiled.call(this, vs, parent);
13783         } catch (e) {
13784             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13785             Roo.log(e.body);
13786             //Roo.log(t.compiled);
13787             Roo.log(values);
13788             return '';
13789         }
13790     },
13791
13792    
13793
13794     applyTemplate : function(values){
13795         return this.master.compiled.call(this, values, {});
13796         //var s = this.subs;
13797     },
13798
13799     apply : function(){
13800         return this.applyTemplate.apply(this, arguments);
13801     }
13802
13803  });
13804
13805 Roo.DomTemplate.from = function(el){
13806     el = Roo.getDom(el);
13807     return new Roo.Domtemplate(el.value || el.innerHTML);
13808 };/*
13809  * Based on:
13810  * Ext JS Library 1.1.1
13811  * Copyright(c) 2006-2007, Ext JS, LLC.
13812  *
13813  * Originally Released Under LGPL - original licence link has changed is not relivant.
13814  *
13815  * Fork - LGPL
13816  * <script type="text/javascript">
13817  */
13818
13819 /**
13820  * @class Roo.util.DelayedTask
13821  * Provides a convenient method of performing setTimeout where a new
13822  * timeout cancels the old timeout. An example would be performing validation on a keypress.
13823  * You can use this class to buffer
13824  * the keypress events for a certain number of milliseconds, and perform only if they stop
13825  * for that amount of time.
13826  * @constructor The parameters to this constructor serve as defaults and are not required.
13827  * @param {Function} fn (optional) The default function to timeout
13828  * @param {Object} scope (optional) The default scope of that timeout
13829  * @param {Array} args (optional) The default Array of arguments
13830  */
13831 Roo.util.DelayedTask = function(fn, scope, args){
13832     var id = null, d, t;
13833
13834     var call = function(){
13835         var now = new Date().getTime();
13836         if(now - t >= d){
13837             clearInterval(id);
13838             id = null;
13839             fn.apply(scope, args || []);
13840         }
13841     };
13842     /**
13843      * Cancels any pending timeout and queues a new one
13844      * @param {Number} delay The milliseconds to delay
13845      * @param {Function} newFn (optional) Overrides function passed to constructor
13846      * @param {Object} newScope (optional) Overrides scope passed to constructor
13847      * @param {Array} newArgs (optional) Overrides args passed to constructor
13848      */
13849     this.delay = function(delay, newFn, newScope, newArgs){
13850         if(id && delay != d){
13851             this.cancel();
13852         }
13853         d = delay;
13854         t = new Date().getTime();
13855         fn = newFn || fn;
13856         scope = newScope || scope;
13857         args = newArgs || args;
13858         if(!id){
13859             id = setInterval(call, d);
13860         }
13861     };
13862
13863     /**
13864      * Cancel the last queued timeout
13865      */
13866     this.cancel = function(){
13867         if(id){
13868             clearInterval(id);
13869             id = null;
13870         }
13871     };
13872 };/*
13873  * Based on:
13874  * Ext JS Library 1.1.1
13875  * Copyright(c) 2006-2007, Ext JS, LLC.
13876  *
13877  * Originally Released Under LGPL - original licence link has changed is not relivant.
13878  *
13879  * Fork - LGPL
13880  * <script type="text/javascript">
13881  */
13882 /**
13883  * @class Roo.util.TaskRunner
13884  * Manage background tasks - not sure why this is better that setInterval?
13885  * @static
13886  *
13887  */
13888  
13889 Roo.util.TaskRunner = function(interval){
13890     interval = interval || 10;
13891     var tasks = [], removeQueue = [];
13892     var id = 0;
13893     var running = false;
13894
13895     var stopThread = function(){
13896         running = false;
13897         clearInterval(id);
13898         id = 0;
13899     };
13900
13901     var startThread = function(){
13902         if(!running){
13903             running = true;
13904             id = setInterval(runTasks, interval);
13905         }
13906     };
13907
13908     var removeTask = function(task){
13909         removeQueue.push(task);
13910         if(task.onStop){
13911             task.onStop();
13912         }
13913     };
13914
13915     var runTasks = function(){
13916         if(removeQueue.length > 0){
13917             for(var i = 0, len = removeQueue.length; i < len; i++){
13918                 tasks.remove(removeQueue[i]);
13919             }
13920             removeQueue = [];
13921             if(tasks.length < 1){
13922                 stopThread();
13923                 return;
13924             }
13925         }
13926         var now = new Date().getTime();
13927         for(var i = 0, len = tasks.length; i < len; ++i){
13928             var t = tasks[i];
13929             var itime = now - t.taskRunTime;
13930             if(t.interval <= itime){
13931                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13932                 t.taskRunTime = now;
13933                 if(rt === false || t.taskRunCount === t.repeat){
13934                     removeTask(t);
13935                     return;
13936                 }
13937             }
13938             if(t.duration && t.duration <= (now - t.taskStartTime)){
13939                 removeTask(t);
13940             }
13941         }
13942     };
13943
13944     /**
13945      * Queues a new task.
13946      * @param {Object} task
13947      *
13948      * Task property : interval = how frequent to run.
13949      * Task object should implement
13950      * function run()
13951      * Task object may implement
13952      * function onStop()
13953      */
13954     this.start = function(task){
13955         tasks.push(task);
13956         task.taskStartTime = new Date().getTime();
13957         task.taskRunTime = 0;
13958         task.taskRunCount = 0;
13959         startThread();
13960         return task;
13961     };
13962     /**
13963      * Stop  new task.
13964      * @param {Object} task
13965      */
13966     this.stop = function(task){
13967         removeTask(task);
13968         return task;
13969     };
13970     /**
13971      * Stop all Tasks
13972      */
13973     this.stopAll = function(){
13974         stopThread();
13975         for(var i = 0, len = tasks.length; i < len; i++){
13976             if(tasks[i].onStop){
13977                 tasks[i].onStop();
13978             }
13979         }
13980         tasks = [];
13981         removeQueue = [];
13982     };
13983 };
13984
13985 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13986  * Based on:
13987  * Ext JS Library 1.1.1
13988  * Copyright(c) 2006-2007, Ext JS, LLC.
13989  *
13990  * Originally Released Under LGPL - original licence link has changed is not relivant.
13991  *
13992  * Fork - LGPL
13993  * <script type="text/javascript">
13994  */
13995
13996  
13997 /**
13998  * @class Roo.util.MixedCollection
13999  * @extends Roo.util.Observable
14000  * A Collection class that maintains both numeric indexes and keys and exposes events.
14001  * @constructor
14002  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14003  * collection (defaults to false)
14004  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14005  * and return the key value for that item.  This is used when available to look up the key on items that
14006  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
14007  * equivalent to providing an implementation for the {@link #getKey} method.
14008  */
14009 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14010     this.items = [];
14011     this.map = {};
14012     this.keys = [];
14013     this.length = 0;
14014     this.addEvents({
14015         /**
14016          * @event clear
14017          * Fires when the collection is cleared.
14018          */
14019         "clear" : true,
14020         /**
14021          * @event add
14022          * Fires when an item is added to the collection.
14023          * @param {Number} index The index at which the item was added.
14024          * @param {Object} o The item added.
14025          * @param {String} key The key associated with the added item.
14026          */
14027         "add" : true,
14028         /**
14029          * @event replace
14030          * Fires when an item is replaced in the collection.
14031          * @param {String} key he key associated with the new added.
14032          * @param {Object} old The item being replaced.
14033          * @param {Object} new The new item.
14034          */
14035         "replace" : true,
14036         /**
14037          * @event remove
14038          * Fires when an item is removed from the collection.
14039          * @param {Object} o The item being removed.
14040          * @param {String} key (optional) The key associated with the removed item.
14041          */
14042         "remove" : true,
14043         "sort" : true
14044     });
14045     this.allowFunctions = allowFunctions === true;
14046     if(keyFn){
14047         this.getKey = keyFn;
14048     }
14049     Roo.util.MixedCollection.superclass.constructor.call(this);
14050 };
14051
14052 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14053     allowFunctions : false,
14054     
14055 /**
14056  * Adds an item to the collection.
14057  * @param {String} key The key to associate with the item
14058  * @param {Object} o The item to add.
14059  * @return {Object} The item added.
14060  */
14061     add : function(key, o){
14062         if(arguments.length == 1){
14063             o = arguments[0];
14064             key = this.getKey(o);
14065         }
14066         if(typeof key == "undefined" || key === null){
14067             this.length++;
14068             this.items.push(o);
14069             this.keys.push(null);
14070         }else{
14071             var old = this.map[key];
14072             if(old){
14073                 return this.replace(key, o);
14074             }
14075             this.length++;
14076             this.items.push(o);
14077             this.map[key] = o;
14078             this.keys.push(key);
14079         }
14080         this.fireEvent("add", this.length-1, o, key);
14081         return o;
14082     },
14083        
14084 /**
14085   * MixedCollection has a generic way to fetch keys if you implement getKey.
14086 <pre><code>
14087 // normal way
14088 var mc = new Roo.util.MixedCollection();
14089 mc.add(someEl.dom.id, someEl);
14090 mc.add(otherEl.dom.id, otherEl);
14091 //and so on
14092
14093 // using getKey
14094 var mc = new Roo.util.MixedCollection();
14095 mc.getKey = function(el){
14096    return el.dom.id;
14097 };
14098 mc.add(someEl);
14099 mc.add(otherEl);
14100
14101 // or via the constructor
14102 var mc = new Roo.util.MixedCollection(false, function(el){
14103    return el.dom.id;
14104 });
14105 mc.add(someEl);
14106 mc.add(otherEl);
14107 </code></pre>
14108  * @param o {Object} The item for which to find the key.
14109  * @return {Object} The key for the passed item.
14110  */
14111     getKey : function(o){
14112          return o.id; 
14113     },
14114    
14115 /**
14116  * Replaces an item in the collection.
14117  * @param {String} key The key associated with the item to replace, or the item to replace.
14118  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14119  * @return {Object}  The new item.
14120  */
14121     replace : function(key, o){
14122         if(arguments.length == 1){
14123             o = arguments[0];
14124             key = this.getKey(o);
14125         }
14126         var old = this.item(key);
14127         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14128              return this.add(key, o);
14129         }
14130         var index = this.indexOfKey(key);
14131         this.items[index] = o;
14132         this.map[key] = o;
14133         this.fireEvent("replace", key, old, o);
14134         return o;
14135     },
14136    
14137 /**
14138  * Adds all elements of an Array or an Object to the collection.
14139  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14140  * an Array of values, each of which are added to the collection.
14141  */
14142     addAll : function(objs){
14143         if(arguments.length > 1 || objs instanceof Array){
14144             var args = arguments.length > 1 ? arguments : objs;
14145             for(var i = 0, len = args.length; i < len; i++){
14146                 this.add(args[i]);
14147             }
14148         }else{
14149             for(var key in objs){
14150                 if(this.allowFunctions || typeof objs[key] != "function"){
14151                     this.add(key, objs[key]);
14152                 }
14153             }
14154         }
14155     },
14156    
14157 /**
14158  * Executes the specified function once for every item in the collection, passing each
14159  * item as the first and only parameter. returning false from the function will stop the iteration.
14160  * @param {Function} fn The function to execute for each item.
14161  * @param {Object} scope (optional) The scope in which to execute the function.
14162  */
14163     each : function(fn, scope){
14164         var items = [].concat(this.items); // each safe for removal
14165         for(var i = 0, len = items.length; i < len; i++){
14166             if(fn.call(scope || items[i], items[i], i, len) === false){
14167                 break;
14168             }
14169         }
14170     },
14171    
14172 /**
14173  * Executes the specified function once for every key in the collection, passing each
14174  * key, and its associated item as the first two parameters.
14175  * @param {Function} fn The function to execute for each item.
14176  * @param {Object} scope (optional) The scope in which to execute the function.
14177  */
14178     eachKey : function(fn, scope){
14179         for(var i = 0, len = this.keys.length; i < len; i++){
14180             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14181         }
14182     },
14183    
14184 /**
14185  * Returns the first item in the collection which elicits a true return value from the
14186  * passed selection function.
14187  * @param {Function} fn The selection function to execute for each item.
14188  * @param {Object} scope (optional) The scope in which to execute the function.
14189  * @return {Object} The first item in the collection which returned true from the selection function.
14190  */
14191     find : function(fn, scope){
14192         for(var i = 0, len = this.items.length; i < len; i++){
14193             if(fn.call(scope || window, this.items[i], this.keys[i])){
14194                 return this.items[i];
14195             }
14196         }
14197         return null;
14198     },
14199    
14200 /**
14201  * Inserts an item at the specified index in the collection.
14202  * @param {Number} index The index to insert the item at.
14203  * @param {String} key The key to associate with the new item, or the item itself.
14204  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14205  * @return {Object} The item inserted.
14206  */
14207     insert : function(index, key, o){
14208         if(arguments.length == 2){
14209             o = arguments[1];
14210             key = this.getKey(o);
14211         }
14212         if(index >= this.length){
14213             return this.add(key, o);
14214         }
14215         this.length++;
14216         this.items.splice(index, 0, o);
14217         if(typeof key != "undefined" && key != null){
14218             this.map[key] = o;
14219         }
14220         this.keys.splice(index, 0, key);
14221         this.fireEvent("add", index, o, key);
14222         return o;
14223     },
14224    
14225 /**
14226  * Removed an item from the collection.
14227  * @param {Object} o The item to remove.
14228  * @return {Object} The item removed.
14229  */
14230     remove : function(o){
14231         return this.removeAt(this.indexOf(o));
14232     },
14233    
14234 /**
14235  * Remove an item from a specified index in the collection.
14236  * @param {Number} index The index within the collection of the item to remove.
14237  */
14238     removeAt : function(index){
14239         if(index < this.length && index >= 0){
14240             this.length--;
14241             var o = this.items[index];
14242             this.items.splice(index, 1);
14243             var key = this.keys[index];
14244             if(typeof key != "undefined"){
14245                 delete this.map[key];
14246             }
14247             this.keys.splice(index, 1);
14248             this.fireEvent("remove", o, key);
14249         }
14250     },
14251    
14252 /**
14253  * Removed an item associated with the passed key fom the collection.
14254  * @param {String} key The key of the item to remove.
14255  */
14256     removeKey : function(key){
14257         return this.removeAt(this.indexOfKey(key));
14258     },
14259    
14260 /**
14261  * Returns the number of items in the collection.
14262  * @return {Number} the number of items in the collection.
14263  */
14264     getCount : function(){
14265         return this.length; 
14266     },
14267    
14268 /**
14269  * Returns index within the collection of the passed Object.
14270  * @param {Object} o The item to find the index of.
14271  * @return {Number} index of the item.
14272  */
14273     indexOf : function(o){
14274         if(!this.items.indexOf){
14275             for(var i = 0, len = this.items.length; i < len; i++){
14276                 if(this.items[i] == o) {
14277                     return i;
14278                 }
14279             }
14280             return -1;
14281         }else{
14282             return this.items.indexOf(o);
14283         }
14284     },
14285    
14286 /**
14287  * Returns index within the collection of the passed key.
14288  * @param {String} key The key to find the index of.
14289  * @return {Number} index of the key.
14290  */
14291     indexOfKey : function(key){
14292         if(!this.keys.indexOf){
14293             for(var i = 0, len = this.keys.length; i < len; i++){
14294                 if(this.keys[i] == key) {
14295                     return i;
14296                 }
14297             }
14298             return -1;
14299         }else{
14300             return this.keys.indexOf(key);
14301         }
14302     },
14303    
14304 /**
14305  * Returns the item associated with the passed key OR index. Key has priority over index.
14306  * @param {String/Number} key The key or index of the item.
14307  * @return {Object} The item associated with the passed key.
14308  */
14309     item : function(key){
14310         if (key === 'length') {
14311             return null;
14312         }
14313         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14314         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14315     },
14316     
14317 /**
14318  * Returns the item at the specified index.
14319  * @param {Number} index The index of the item.
14320  * @return {Object}
14321  */
14322     itemAt : function(index){
14323         return this.items[index];
14324     },
14325     
14326 /**
14327  * Returns the item associated with the passed key.
14328  * @param {String/Number} key The key of the item.
14329  * @return {Object} The item associated with the passed key.
14330  */
14331     key : function(key){
14332         return this.map[key];
14333     },
14334    
14335 /**
14336  * Returns true if the collection contains the passed Object as an item.
14337  * @param {Object} o  The Object to look for in the collection.
14338  * @return {Boolean} True if the collection contains the Object as an item.
14339  */
14340     contains : function(o){
14341         return this.indexOf(o) != -1;
14342     },
14343    
14344 /**
14345  * Returns true if the collection contains the passed Object as a key.
14346  * @param {String} key The key to look for in the collection.
14347  * @return {Boolean} True if the collection contains the Object as a key.
14348  */
14349     containsKey : function(key){
14350         return typeof this.map[key] != "undefined";
14351     },
14352    
14353 /**
14354  * Removes all items from the collection.
14355  */
14356     clear : function(){
14357         this.length = 0;
14358         this.items = [];
14359         this.keys = [];
14360         this.map = {};
14361         this.fireEvent("clear");
14362     },
14363    
14364 /**
14365  * Returns the first item in the collection.
14366  * @return {Object} the first item in the collection..
14367  */
14368     first : function(){
14369         return this.items[0]; 
14370     },
14371    
14372 /**
14373  * Returns the last item in the collection.
14374  * @return {Object} the last item in the collection..
14375  */
14376     last : function(){
14377         return this.items[this.length-1];   
14378     },
14379     
14380     _sort : function(property, dir, fn){
14381         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14382         fn = fn || function(a, b){
14383             return a-b;
14384         };
14385         var c = [], k = this.keys, items = this.items;
14386         for(var i = 0, len = items.length; i < len; i++){
14387             c[c.length] = {key: k[i], value: items[i], index: i};
14388         }
14389         c.sort(function(a, b){
14390             var v = fn(a[property], b[property]) * dsc;
14391             if(v == 0){
14392                 v = (a.index < b.index ? -1 : 1);
14393             }
14394             return v;
14395         });
14396         for(var i = 0, len = c.length; i < len; i++){
14397             items[i] = c[i].value;
14398             k[i] = c[i].key;
14399         }
14400         this.fireEvent("sort", this);
14401     },
14402     
14403     /**
14404      * Sorts this collection with the passed comparison function
14405      * @param {String} direction (optional) "ASC" or "DESC"
14406      * @param {Function} fn (optional) comparison function
14407      */
14408     sort : function(dir, fn){
14409         this._sort("value", dir, fn);
14410     },
14411     
14412     /**
14413      * Sorts this collection by keys
14414      * @param {String} direction (optional) "ASC" or "DESC"
14415      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14416      */
14417     keySort : function(dir, fn){
14418         this._sort("key", dir, fn || function(a, b){
14419             return String(a).toUpperCase()-String(b).toUpperCase();
14420         });
14421     },
14422     
14423     /**
14424      * Returns a range of items in this collection
14425      * @param {Number} startIndex (optional) defaults to 0
14426      * @param {Number} endIndex (optional) default to the last item
14427      * @return {Array} An array of items
14428      */
14429     getRange : function(start, end){
14430         var items = this.items;
14431         if(items.length < 1){
14432             return [];
14433         }
14434         start = start || 0;
14435         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14436         var r = [];
14437         if(start <= end){
14438             for(var i = start; i <= end; i++) {
14439                     r[r.length] = items[i];
14440             }
14441         }else{
14442             for(var i = start; i >= end; i--) {
14443                     r[r.length] = items[i];
14444             }
14445         }
14446         return r;
14447     },
14448         
14449     /**
14450      * Filter the <i>objects</i> in this collection by a specific property. 
14451      * Returns a new collection that has been filtered.
14452      * @param {String} property A property on your objects
14453      * @param {String/RegExp} value Either string that the property values 
14454      * should start with or a RegExp to test against the property
14455      * @return {MixedCollection} The new filtered collection
14456      */
14457     filter : function(property, value){
14458         if(!value.exec){ // not a regex
14459             value = String(value);
14460             if(value.length == 0){
14461                 return this.clone();
14462             }
14463             value = new RegExp("^" + Roo.escapeRe(value), "i");
14464         }
14465         return this.filterBy(function(o){
14466             return o && value.test(o[property]);
14467         });
14468         },
14469     
14470     /**
14471      * Filter by a function. * Returns a new collection that has been filtered.
14472      * The passed function will be called with each 
14473      * object in the collection. If the function returns true, the value is included 
14474      * otherwise it is filtered.
14475      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14476      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14477      * @return {MixedCollection} The new filtered collection
14478      */
14479     filterBy : function(fn, scope){
14480         var r = new Roo.util.MixedCollection();
14481         r.getKey = this.getKey;
14482         var k = this.keys, it = this.items;
14483         for(var i = 0, len = it.length; i < len; i++){
14484             if(fn.call(scope||this, it[i], k[i])){
14485                                 r.add(k[i], it[i]);
14486                         }
14487         }
14488         return r;
14489     },
14490     
14491     /**
14492      * Creates a duplicate of this collection
14493      * @return {MixedCollection}
14494      */
14495     clone : function(){
14496         var r = new Roo.util.MixedCollection();
14497         var k = this.keys, it = this.items;
14498         for(var i = 0, len = it.length; i < len; i++){
14499             r.add(k[i], it[i]);
14500         }
14501         r.getKey = this.getKey;
14502         return r;
14503     }
14504 });
14505 /**
14506  * Returns the item associated with the passed key or index.
14507  * @method
14508  * @param {String/Number} key The key or index of the item.
14509  * @return {Object} The item associated with the passed key.
14510  */
14511 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14512  * Based on:
14513  * Ext JS Library 1.1.1
14514  * Copyright(c) 2006-2007, Ext JS, LLC.
14515  *
14516  * Originally Released Under LGPL - original licence link has changed is not relivant.
14517  *
14518  * Fork - LGPL
14519  * <script type="text/javascript">
14520  */
14521 /**
14522  * @class Roo.util.JSON
14523  * Modified version of Douglas Crockford"s json.js that doesn"t
14524  * mess with the Object prototype 
14525  * http://www.json.org/js.html
14526  * @static
14527  */
14528 Roo.util.JSON = new (function(){
14529     var useHasOwn = {}.hasOwnProperty ? true : false;
14530     
14531     // crashes Safari in some instances
14532     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14533     
14534     var pad = function(n) {
14535         return n < 10 ? "0" + n : n;
14536     };
14537     
14538     var m = {
14539         "\b": '\\b',
14540         "\t": '\\t',
14541         "\n": '\\n',
14542         "\f": '\\f',
14543         "\r": '\\r',
14544         '"' : '\\"',
14545         "\\": '\\\\'
14546     };
14547
14548     var encodeString = function(s){
14549         if (/["\\\x00-\x1f]/.test(s)) {
14550             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14551                 var c = m[b];
14552                 if(c){
14553                     return c;
14554                 }
14555                 c = b.charCodeAt();
14556                 return "\\u00" +
14557                     Math.floor(c / 16).toString(16) +
14558                     (c % 16).toString(16);
14559             }) + '"';
14560         }
14561         return '"' + s + '"';
14562     };
14563     
14564     var encodeArray = function(o){
14565         var a = ["["], b, i, l = o.length, v;
14566             for (i = 0; i < l; i += 1) {
14567                 v = o[i];
14568                 switch (typeof v) {
14569                     case "undefined":
14570                     case "function":
14571                     case "unknown":
14572                         break;
14573                     default:
14574                         if (b) {
14575                             a.push(',');
14576                         }
14577                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14578                         b = true;
14579                 }
14580             }
14581             a.push("]");
14582             return a.join("");
14583     };
14584     
14585     var encodeDate = function(o){
14586         return '"' + o.getFullYear() + "-" +
14587                 pad(o.getMonth() + 1) + "-" +
14588                 pad(o.getDate()) + "T" +
14589                 pad(o.getHours()) + ":" +
14590                 pad(o.getMinutes()) + ":" +
14591                 pad(o.getSeconds()) + '"';
14592     };
14593     
14594     /**
14595      * Encodes an Object, Array or other value
14596      * @param {Mixed} o The variable to encode
14597      * @return {String} The JSON string
14598      */
14599     this.encode = function(o)
14600     {
14601         // should this be extended to fully wrap stringify..
14602         
14603         if(typeof o == "undefined" || o === null){
14604             return "null";
14605         }else if(o instanceof Array){
14606             return encodeArray(o);
14607         }else if(o instanceof Date){
14608             return encodeDate(o);
14609         }else if(typeof o == "string"){
14610             return encodeString(o);
14611         }else if(typeof o == "number"){
14612             return isFinite(o) ? String(o) : "null";
14613         }else if(typeof o == "boolean"){
14614             return String(o);
14615         }else {
14616             var a = ["{"], b, i, v;
14617             for (i in o) {
14618                 if(!useHasOwn || o.hasOwnProperty(i)) {
14619                     v = o[i];
14620                     switch (typeof v) {
14621                     case "undefined":
14622                     case "function":
14623                     case "unknown":
14624                         break;
14625                     default:
14626                         if(b){
14627                             a.push(',');
14628                         }
14629                         a.push(this.encode(i), ":",
14630                                 v === null ? "null" : this.encode(v));
14631                         b = true;
14632                     }
14633                 }
14634             }
14635             a.push("}");
14636             return a.join("");
14637         }
14638     };
14639     
14640     /**
14641      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14642      * @param {String} json The JSON string
14643      * @return {Object} The resulting object
14644      */
14645     this.decode = function(json){
14646         
14647         return  /** eval:var:json */ eval("(" + json + ')');
14648     };
14649 })();
14650 /** 
14651  * Shorthand for {@link Roo.util.JSON#encode}
14652  * @member Roo encode 
14653  * @method */
14654 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14655 /** 
14656  * Shorthand for {@link Roo.util.JSON#decode}
14657  * @member Roo decode 
14658  * @method */
14659 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14660 /*
14661  * Based on:
14662  * Ext JS Library 1.1.1
14663  * Copyright(c) 2006-2007, Ext JS, LLC.
14664  *
14665  * Originally Released Under LGPL - original licence link has changed is not relivant.
14666  *
14667  * Fork - LGPL
14668  * <script type="text/javascript">
14669  */
14670  
14671 /**
14672  * @class Roo.util.Format
14673  * Reusable data formatting functions
14674  * @static
14675  */
14676 Roo.util.Format = function(){
14677     var trimRe = /^\s+|\s+$/g;
14678     return {
14679         /**
14680          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14681          * @param {String} value The string to truncate
14682          * @param {Number} length The maximum length to allow before truncating
14683          * @return {String} The converted text
14684          */
14685         ellipsis : function(value, len){
14686             if(value && value.length > len){
14687                 return value.substr(0, len-3)+"...";
14688             }
14689             return value;
14690         },
14691
14692         /**
14693          * Checks a reference and converts it to empty string if it is undefined
14694          * @param {Mixed} value Reference to check
14695          * @return {Mixed} Empty string if converted, otherwise the original value
14696          */
14697         undef : function(value){
14698             return typeof value != "undefined" ? value : "";
14699         },
14700
14701         /**
14702          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14703          * @param {String} value The string to encode
14704          * @return {String} The encoded text
14705          */
14706         htmlEncode : function(value){
14707             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
14708         },
14709
14710         /**
14711          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14712          * @param {String} value The string to decode
14713          * @return {String} The decoded text
14714          */
14715         htmlDecode : function(value){
14716             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
14717         },
14718
14719         /**
14720          * Trims any whitespace from either side of a string
14721          * @param {String} value The text to trim
14722          * @return {String} The trimmed text
14723          */
14724         trim : function(value){
14725             return String(value).replace(trimRe, "");
14726         },
14727
14728         /**
14729          * Returns a substring from within an original string
14730          * @param {String} value The original text
14731          * @param {Number} start The start index of the substring
14732          * @param {Number} length The length of the substring
14733          * @return {String} The substring
14734          */
14735         substr : function(value, start, length){
14736             return String(value).substr(start, length);
14737         },
14738
14739         /**
14740          * Converts a string to all lower case letters
14741          * @param {String} value The text to convert
14742          * @return {String} The converted text
14743          */
14744         lowercase : function(value){
14745             return String(value).toLowerCase();
14746         },
14747
14748         /**
14749          * Converts a string to all upper case letters
14750          * @param {String} value The text to convert
14751          * @return {String} The converted text
14752          */
14753         uppercase : function(value){
14754             return String(value).toUpperCase();
14755         },
14756
14757         /**
14758          * Converts the first character only of a string to upper case
14759          * @param {String} value The text to convert
14760          * @return {String} The converted text
14761          */
14762         capitalize : function(value){
14763             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14764         },
14765
14766         // private
14767         call : function(value, fn){
14768             if(arguments.length > 2){
14769                 var args = Array.prototype.slice.call(arguments, 2);
14770                 args.unshift(value);
14771                  
14772                 return /** eval:var:value */  eval(fn).apply(window, args);
14773             }else{
14774                 /** eval:var:value */
14775                 return /** eval:var:value */ eval(fn).call(window, value);
14776             }
14777         },
14778
14779        
14780         /**
14781          * safer version of Math.toFixed..??/
14782          * @param {Number/String} value The numeric value to format
14783          * @param {Number/String} value Decimal places 
14784          * @return {String} The formatted currency string
14785          */
14786         toFixed : function(v, n)
14787         {
14788             // why not use to fixed - precision is buggered???
14789             if (!n) {
14790                 return Math.round(v-0);
14791             }
14792             var fact = Math.pow(10,n+1);
14793             v = (Math.round((v-0)*fact))/fact;
14794             var z = (''+fact).substring(2);
14795             if (v == Math.floor(v)) {
14796                 return Math.floor(v) + '.' + z;
14797             }
14798             
14799             // now just padd decimals..
14800             var ps = String(v).split('.');
14801             var fd = (ps[1] + z);
14802             var r = fd.substring(0,n); 
14803             var rm = fd.substring(n); 
14804             if (rm < 5) {
14805                 return ps[0] + '.' + r;
14806             }
14807             r*=1; // turn it into a number;
14808             r++;
14809             if (String(r).length != n) {
14810                 ps[0]*=1;
14811                 ps[0]++;
14812                 r = String(r).substring(1); // chop the end off.
14813             }
14814             
14815             return ps[0] + '.' + r;
14816              
14817         },
14818         
14819         /**
14820          * Format a number as US currency
14821          * @param {Number/String} value The numeric value to format
14822          * @return {String} The formatted currency string
14823          */
14824         usMoney : function(v){
14825             return '$' + Roo.util.Format.number(v);
14826         },
14827         
14828         /**
14829          * Format a number
14830          * eventually this should probably emulate php's number_format
14831          * @param {Number/String} value The numeric value to format
14832          * @param {Number} decimals number of decimal places
14833          * @param {String} delimiter for thousands (default comma)
14834          * @return {String} The formatted currency string
14835          */
14836         number : function(v, decimals, thousandsDelimiter)
14837         {
14838             // multiply and round.
14839             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14840             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14841             
14842             var mul = Math.pow(10, decimals);
14843             var zero = String(mul).substring(1);
14844             v = (Math.round((v-0)*mul))/mul;
14845             
14846             // if it's '0' number.. then
14847             
14848             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14849             v = String(v);
14850             var ps = v.split('.');
14851             var whole = ps[0];
14852             
14853             var r = /(\d+)(\d{3})/;
14854             // add comma's
14855             
14856             if(thousandsDelimiter.length != 0) {
14857                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14858             } 
14859             
14860             var sub = ps[1] ?
14861                     // has decimals..
14862                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14863                     // does not have decimals
14864                     (decimals ? ('.' + zero) : '');
14865             
14866             
14867             return whole + sub ;
14868         },
14869         
14870         /**
14871          * Parse a value into a formatted date using the specified format pattern.
14872          * @param {Mixed} value The value to format
14873          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14874          * @return {String} The formatted date string
14875          */
14876         date : function(v, format){
14877             if(!v){
14878                 return "";
14879             }
14880             if(!(v instanceof Date)){
14881                 v = new Date(Date.parse(v));
14882             }
14883             return v.dateFormat(format || Roo.util.Format.defaults.date);
14884         },
14885
14886         /**
14887          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14888          * @param {String} format Any valid date format string
14889          * @return {Function} The date formatting function
14890          */
14891         dateRenderer : function(format){
14892             return function(v){
14893                 return Roo.util.Format.date(v, format);  
14894             };
14895         },
14896
14897         // private
14898         stripTagsRE : /<\/?[^>]+>/gi,
14899         
14900         /**
14901          * Strips all HTML tags
14902          * @param {Mixed} value The text from which to strip tags
14903          * @return {String} The stripped text
14904          */
14905         stripTags : function(v){
14906             return !v ? v : String(v).replace(this.stripTagsRE, "");
14907         },
14908         
14909         /**
14910          * Size in Mb,Gb etc.
14911          * @param {Number} value The number to be formated
14912          * @param {number} decimals how many decimal places
14913          * @return {String} the formated string
14914          */
14915         size : function(value, decimals)
14916         {
14917             var sizes = ['b', 'k', 'M', 'G', 'T'];
14918             if (value == 0) {
14919                 return 0;
14920             }
14921             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14922             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
14923         }
14924         
14925         
14926         
14927     };
14928 }();
14929 Roo.util.Format.defaults = {
14930     date : 'd/M/Y'
14931 };/*
14932  * Based on:
14933  * Ext JS Library 1.1.1
14934  * Copyright(c) 2006-2007, Ext JS, LLC.
14935  *
14936  * Originally Released Under LGPL - original licence link has changed is not relivant.
14937  *
14938  * Fork - LGPL
14939  * <script type="text/javascript">
14940  */
14941
14942
14943  
14944
14945 /**
14946  * @class Roo.MasterTemplate
14947  * @extends Roo.Template
14948  * Provides a template that can have child templates. The syntax is:
14949 <pre><code>
14950 var t = new Roo.MasterTemplate(
14951         '&lt;select name="{name}"&gt;',
14952                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
14953         '&lt;/select&gt;'
14954 );
14955 t.add('options', {value: 'foo', text: 'bar'});
14956 // or you can add multiple child elements in one shot
14957 t.addAll('options', [
14958     {value: 'foo', text: 'bar'},
14959     {value: 'foo2', text: 'bar2'},
14960     {value: 'foo3', text: 'bar3'}
14961 ]);
14962 // then append, applying the master template values
14963 t.append('my-form', {name: 'my-select'});
14964 </code></pre>
14965 * A name attribute for the child template is not required if you have only one child
14966 * template or you want to refer to them by index.
14967  */
14968 Roo.MasterTemplate = function(){
14969     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14970     this.originalHtml = this.html;
14971     var st = {};
14972     var m, re = this.subTemplateRe;
14973     re.lastIndex = 0;
14974     var subIndex = 0;
14975     while(m = re.exec(this.html)){
14976         var name = m[1], content = m[2];
14977         st[subIndex] = {
14978             name: name,
14979             index: subIndex,
14980             buffer: [],
14981             tpl : new Roo.Template(content)
14982         };
14983         if(name){
14984             st[name] = st[subIndex];
14985         }
14986         st[subIndex].tpl.compile();
14987         st[subIndex].tpl.call = this.call.createDelegate(this);
14988         subIndex++;
14989     }
14990     this.subCount = subIndex;
14991     this.subs = st;
14992 };
14993 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14994     /**
14995     * The regular expression used to match sub templates
14996     * @type RegExp
14997     * @property
14998     */
14999     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15000
15001     /**
15002      * Applies the passed values to a child template.
15003      * @param {String/Number} name (optional) The name or index of the child template
15004      * @param {Array/Object} values The values to be applied to the template
15005      * @return {MasterTemplate} this
15006      */
15007      add : function(name, values){
15008         if(arguments.length == 1){
15009             values = arguments[0];
15010             name = 0;
15011         }
15012         var s = this.subs[name];
15013         s.buffer[s.buffer.length] = s.tpl.apply(values);
15014         return this;
15015     },
15016
15017     /**
15018      * Applies all the passed values to a child template.
15019      * @param {String/Number} name (optional) The name or index of the child template
15020      * @param {Array} values The values to be applied to the template, this should be an array of objects.
15021      * @param {Boolean} reset (optional) True to reset the template first
15022      * @return {MasterTemplate} this
15023      */
15024     fill : function(name, values, reset){
15025         var a = arguments;
15026         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15027             values = a[0];
15028             name = 0;
15029             reset = a[1];
15030         }
15031         if(reset){
15032             this.reset();
15033         }
15034         for(var i = 0, len = values.length; i < len; i++){
15035             this.add(name, values[i]);
15036         }
15037         return this;
15038     },
15039
15040     /**
15041      * Resets the template for reuse
15042      * @return {MasterTemplate} this
15043      */
15044      reset : function(){
15045         var s = this.subs;
15046         for(var i = 0; i < this.subCount; i++){
15047             s[i].buffer = [];
15048         }
15049         return this;
15050     },
15051
15052     applyTemplate : function(values){
15053         var s = this.subs;
15054         var replaceIndex = -1;
15055         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15056             return s[++replaceIndex].buffer.join("");
15057         });
15058         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15059     },
15060
15061     apply : function(){
15062         return this.applyTemplate.apply(this, arguments);
15063     },
15064
15065     compile : function(){return this;}
15066 });
15067
15068 /**
15069  * Alias for fill().
15070  * @method
15071  */
15072 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15073  /**
15074  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15075  * var tpl = Roo.MasterTemplate.from('element-id');
15076  * @param {String/HTMLElement} el
15077  * @param {Object} config
15078  * @static
15079  */
15080 Roo.MasterTemplate.from = function(el, config){
15081     el = Roo.getDom(el);
15082     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15083 };/*
15084  * Based on:
15085  * Ext JS Library 1.1.1
15086  * Copyright(c) 2006-2007, Ext JS, LLC.
15087  *
15088  * Originally Released Under LGPL - original licence link has changed is not relivant.
15089  *
15090  * Fork - LGPL
15091  * <script type="text/javascript">
15092  */
15093
15094  
15095 /**
15096  * @class Roo.util.CSS
15097  * Utility class for manipulating CSS rules
15098  * @static
15099
15100  */
15101 Roo.util.CSS = function(){
15102         var rules = null;
15103         var doc = document;
15104
15105     var camelRe = /(-[a-z])/gi;
15106     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15107
15108    return {
15109    /**
15110     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15111     * tag and appended to the HEAD of the document.
15112     * @param {String|Object} cssText The text containing the css rules
15113     * @param {String} id An id to add to the stylesheet for later removal
15114     * @return {StyleSheet}
15115     */
15116     createStyleSheet : function(cssText, id){
15117         var ss;
15118         var head = doc.getElementsByTagName("head")[0];
15119         var nrules = doc.createElement("style");
15120         nrules.setAttribute("type", "text/css");
15121         if(id){
15122             nrules.setAttribute("id", id);
15123         }
15124         if (typeof(cssText) != 'string') {
15125             // support object maps..
15126             // not sure if this a good idea.. 
15127             // perhaps it should be merged with the general css handling
15128             // and handle js style props.
15129             var cssTextNew = [];
15130             for(var n in cssText) {
15131                 var citems = [];
15132                 for(var k in cssText[n]) {
15133                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15134                 }
15135                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15136                 
15137             }
15138             cssText = cssTextNew.join("\n");
15139             
15140         }
15141        
15142        
15143        if(Roo.isIE){
15144            head.appendChild(nrules);
15145            ss = nrules.styleSheet;
15146            ss.cssText = cssText;
15147        }else{
15148            try{
15149                 nrules.appendChild(doc.createTextNode(cssText));
15150            }catch(e){
15151                nrules.cssText = cssText; 
15152            }
15153            head.appendChild(nrules);
15154            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15155        }
15156        this.cacheStyleSheet(ss);
15157        return ss;
15158    },
15159
15160    /**
15161     * Removes a style or link tag by id
15162     * @param {String} id The id of the tag
15163     */
15164    removeStyleSheet : function(id){
15165        var existing = doc.getElementById(id);
15166        if(existing){
15167            existing.parentNode.removeChild(existing);
15168        }
15169    },
15170
15171    /**
15172     * Dynamically swaps an existing stylesheet reference for a new one
15173     * @param {String} id The id of an existing link tag to remove
15174     * @param {String} url The href of the new stylesheet to include
15175     */
15176    swapStyleSheet : function(id, url){
15177        this.removeStyleSheet(id);
15178        var ss = doc.createElement("link");
15179        ss.setAttribute("rel", "stylesheet");
15180        ss.setAttribute("type", "text/css");
15181        ss.setAttribute("id", id);
15182        ss.setAttribute("href", url);
15183        doc.getElementsByTagName("head")[0].appendChild(ss);
15184    },
15185    
15186    /**
15187     * Refresh the rule cache if you have dynamically added stylesheets
15188     * @return {Object} An object (hash) of rules indexed by selector
15189     */
15190    refreshCache : function(){
15191        return this.getRules(true);
15192    },
15193
15194    // private
15195    cacheStyleSheet : function(stylesheet){
15196        if(!rules){
15197            rules = {};
15198        }
15199        try{// try catch for cross domain access issue
15200            var ssRules = stylesheet.cssRules || stylesheet.rules;
15201            for(var j = ssRules.length-1; j >= 0; --j){
15202                rules[ssRules[j].selectorText] = ssRules[j];
15203            }
15204        }catch(e){}
15205    },
15206    
15207    /**
15208     * Gets all css rules for the document
15209     * @param {Boolean} refreshCache true to refresh the internal cache
15210     * @return {Object} An object (hash) of rules indexed by selector
15211     */
15212    getRules : function(refreshCache){
15213                 if(rules == null || refreshCache){
15214                         rules = {};
15215                         var ds = doc.styleSheets;
15216                         for(var i =0, len = ds.length; i < len; i++){
15217                             try{
15218                         this.cacheStyleSheet(ds[i]);
15219                     }catch(e){} 
15220                 }
15221                 }
15222                 return rules;
15223         },
15224         
15225         /**
15226     * Gets an an individual CSS rule by selector(s)
15227     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15228     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15229     * @return {CSSRule} The CSS rule or null if one is not found
15230     */
15231    getRule : function(selector, refreshCache){
15232                 var rs = this.getRules(refreshCache);
15233                 if(!(selector instanceof Array)){
15234                     return rs[selector];
15235                 }
15236                 for(var i = 0; i < selector.length; i++){
15237                         if(rs[selector[i]]){
15238                                 return rs[selector[i]];
15239                         }
15240                 }
15241                 return null;
15242         },
15243         
15244         
15245         /**
15246     * Updates a rule property
15247     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15248     * @param {String} property The css property
15249     * @param {String} value The new value for the property
15250     * @return {Boolean} true If a rule was found and updated
15251     */
15252    updateRule : function(selector, property, value){
15253                 if(!(selector instanceof Array)){
15254                         var rule = this.getRule(selector);
15255                         if(rule){
15256                                 rule.style[property.replace(camelRe, camelFn)] = value;
15257                                 return true;
15258                         }
15259                 }else{
15260                         for(var i = 0; i < selector.length; i++){
15261                                 if(this.updateRule(selector[i], property, value)){
15262                                         return true;
15263                                 }
15264                         }
15265                 }
15266                 return false;
15267         }
15268    };   
15269 }();/*
15270  * Based on:
15271  * Ext JS Library 1.1.1
15272  * Copyright(c) 2006-2007, Ext JS, LLC.
15273  *
15274  * Originally Released Under LGPL - original licence link has changed is not relivant.
15275  *
15276  * Fork - LGPL
15277  * <script type="text/javascript">
15278  */
15279
15280  
15281
15282 /**
15283  * @class Roo.util.ClickRepeater
15284  * @extends Roo.util.Observable
15285  * 
15286  * A wrapper class which can be applied to any element. Fires a "click" event while the
15287  * mouse is pressed. The interval between firings may be specified in the config but
15288  * defaults to 10 milliseconds.
15289  * 
15290  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15291  * 
15292  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15293  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15294  * Similar to an autorepeat key delay.
15295  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15296  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15297  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15298  *           "interval" and "delay" are ignored. "immediate" is honored.
15299  * @cfg {Boolean} preventDefault True to prevent the default click event
15300  * @cfg {Boolean} stopDefault True to stop the default click event
15301  * 
15302  * @history
15303  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15304  *     2007-02-02 jvs Renamed to ClickRepeater
15305  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15306  *
15307  *  @constructor
15308  * @param {String/HTMLElement/Element} el The element to listen on
15309  * @param {Object} config
15310  **/
15311 Roo.util.ClickRepeater = function(el, config)
15312 {
15313     this.el = Roo.get(el);
15314     this.el.unselectable();
15315
15316     Roo.apply(this, config);
15317
15318     this.addEvents({
15319     /**
15320      * @event mousedown
15321      * Fires when the mouse button is depressed.
15322      * @param {Roo.util.ClickRepeater} this
15323      */
15324         "mousedown" : true,
15325     /**
15326      * @event click
15327      * Fires on a specified interval during the time the element is pressed.
15328      * @param {Roo.util.ClickRepeater} this
15329      */
15330         "click" : true,
15331     /**
15332      * @event mouseup
15333      * Fires when the mouse key is released.
15334      * @param {Roo.util.ClickRepeater} this
15335      */
15336         "mouseup" : true
15337     });
15338
15339     this.el.on("mousedown", this.handleMouseDown, this);
15340     if(this.preventDefault || this.stopDefault){
15341         this.el.on("click", function(e){
15342             if(this.preventDefault){
15343                 e.preventDefault();
15344             }
15345             if(this.stopDefault){
15346                 e.stopEvent();
15347             }
15348         }, this);
15349     }
15350
15351     // allow inline handler
15352     if(this.handler){
15353         this.on("click", this.handler,  this.scope || this);
15354     }
15355
15356     Roo.util.ClickRepeater.superclass.constructor.call(this);
15357 };
15358
15359 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15360     interval : 20,
15361     delay: 250,
15362     preventDefault : true,
15363     stopDefault : false,
15364     timer : 0,
15365
15366     // private
15367     handleMouseDown : function(){
15368         clearTimeout(this.timer);
15369         this.el.blur();
15370         if(this.pressClass){
15371             this.el.addClass(this.pressClass);
15372         }
15373         this.mousedownTime = new Date();
15374
15375         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15376         this.el.on("mouseout", this.handleMouseOut, this);
15377
15378         this.fireEvent("mousedown", this);
15379         this.fireEvent("click", this);
15380         
15381         this.timer = this.click.defer(this.delay || this.interval, this);
15382     },
15383
15384     // private
15385     click : function(){
15386         this.fireEvent("click", this);
15387         this.timer = this.click.defer(this.getInterval(), this);
15388     },
15389
15390     // private
15391     getInterval: function(){
15392         if(!this.accelerate){
15393             return this.interval;
15394         }
15395         var pressTime = this.mousedownTime.getElapsed();
15396         if(pressTime < 500){
15397             return 400;
15398         }else if(pressTime < 1700){
15399             return 320;
15400         }else if(pressTime < 2600){
15401             return 250;
15402         }else if(pressTime < 3500){
15403             return 180;
15404         }else if(pressTime < 4400){
15405             return 140;
15406         }else if(pressTime < 5300){
15407             return 80;
15408         }else if(pressTime < 6200){
15409             return 50;
15410         }else{
15411             return 10;
15412         }
15413     },
15414
15415     // private
15416     handleMouseOut : function(){
15417         clearTimeout(this.timer);
15418         if(this.pressClass){
15419             this.el.removeClass(this.pressClass);
15420         }
15421         this.el.on("mouseover", this.handleMouseReturn, this);
15422     },
15423
15424     // private
15425     handleMouseReturn : function(){
15426         this.el.un("mouseover", this.handleMouseReturn);
15427         if(this.pressClass){
15428             this.el.addClass(this.pressClass);
15429         }
15430         this.click();
15431     },
15432
15433     // private
15434     handleMouseUp : function(){
15435         clearTimeout(this.timer);
15436         this.el.un("mouseover", this.handleMouseReturn);
15437         this.el.un("mouseout", this.handleMouseOut);
15438         Roo.get(document).un("mouseup", this.handleMouseUp);
15439         this.el.removeClass(this.pressClass);
15440         this.fireEvent("mouseup", this);
15441     }
15442 });/**
15443  * @class Roo.util.Clipboard
15444  * @static
15445  * 
15446  * Clipboard UTILS
15447  * 
15448  **/
15449 Roo.util.Clipboard = {
15450     /**
15451      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15452      * @param {String} text to copy to clipboard
15453      */
15454     write : function(text) {
15455         // navigator clipboard api needs a secure context (https)
15456         if (navigator.clipboard && window.isSecureContext) {
15457             // navigator clipboard api method'
15458             navigator.clipboard.writeText(text);
15459             return ;
15460         } 
15461         // text area method
15462         var ta = document.createElement("textarea");
15463         ta.value = text;
15464         // make the textarea out of viewport
15465         ta.style.position = "fixed";
15466         ta.style.left = "-999999px";
15467         ta.style.top = "-999999px";
15468         document.body.appendChild(ta);
15469         ta.focus();
15470         ta.select();
15471         document.execCommand('copy');
15472         (function() {
15473             ta.remove();
15474         }).defer(100);
15475         
15476     }
15477         
15478 }
15479     /*
15480  * Based on:
15481  * Ext JS Library 1.1.1
15482  * Copyright(c) 2006-2007, Ext JS, LLC.
15483  *
15484  * Originally Released Under LGPL - original licence link has changed is not relivant.
15485  *
15486  * Fork - LGPL
15487  * <script type="text/javascript">
15488  */
15489
15490  
15491 /**
15492  * @class Roo.KeyNav
15493  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15494  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15495  * way to implement custom navigation schemes for any UI component.</p>
15496  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15497  * pageUp, pageDown, del, home, end.  Usage:</p>
15498  <pre><code>
15499 var nav = new Roo.KeyNav("my-element", {
15500     "left" : function(e){
15501         this.moveLeft(e.ctrlKey);
15502     },
15503     "right" : function(e){
15504         this.moveRight(e.ctrlKey);
15505     },
15506     "enter" : function(e){
15507         this.save();
15508     },
15509     scope : this
15510 });
15511 </code></pre>
15512  * @constructor
15513  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15514  * @param {Object} config The config
15515  */
15516 Roo.KeyNav = function(el, config){
15517     this.el = Roo.get(el);
15518     Roo.apply(this, config);
15519     if(!this.disabled){
15520         this.disabled = true;
15521         this.enable();
15522     }
15523 };
15524
15525 Roo.KeyNav.prototype = {
15526     /**
15527      * @cfg {Boolean} disabled
15528      * True to disable this KeyNav instance (defaults to false)
15529      */
15530     disabled : false,
15531     /**
15532      * @cfg {String} defaultEventAction
15533      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
15534      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15535      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15536      */
15537     defaultEventAction: "stopEvent",
15538     /**
15539      * @cfg {Boolean} forceKeyDown
15540      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
15541      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15542      * handle keydown instead of keypress.
15543      */
15544     forceKeyDown : false,
15545
15546     // private
15547     prepareEvent : function(e){
15548         var k = e.getKey();
15549         var h = this.keyToHandler[k];
15550         //if(h && this[h]){
15551         //    e.stopPropagation();
15552         //}
15553         if(Roo.isSafari && h && k >= 37 && k <= 40){
15554             e.stopEvent();
15555         }
15556     },
15557
15558     // private
15559     relay : function(e){
15560         var k = e.getKey();
15561         var h = this.keyToHandler[k];
15562         if(h && this[h]){
15563             if(this.doRelay(e, this[h], h) !== true){
15564                 e[this.defaultEventAction]();
15565             }
15566         }
15567     },
15568
15569     // private
15570     doRelay : function(e, h, hname){
15571         return h.call(this.scope || this, e);
15572     },
15573
15574     // possible handlers
15575     enter : false,
15576     left : false,
15577     right : false,
15578     up : false,
15579     down : false,
15580     tab : false,
15581     esc : false,
15582     pageUp : false,
15583     pageDown : false,
15584     del : false,
15585     home : false,
15586     end : false,
15587
15588     // quick lookup hash
15589     keyToHandler : {
15590         37 : "left",
15591         39 : "right",
15592         38 : "up",
15593         40 : "down",
15594         33 : "pageUp",
15595         34 : "pageDown",
15596         46 : "del",
15597         36 : "home",
15598         35 : "end",
15599         13 : "enter",
15600         27 : "esc",
15601         9  : "tab"
15602     },
15603
15604         /**
15605          * Enable this KeyNav
15606          */
15607         enable: function(){
15608                 if(this.disabled){
15609             // ie won't do special keys on keypress, no one else will repeat keys with keydown
15610             // the EventObject will normalize Safari automatically
15611             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15612                 this.el.on("keydown", this.relay,  this);
15613             }else{
15614                 this.el.on("keydown", this.prepareEvent,  this);
15615                 this.el.on("keypress", this.relay,  this);
15616             }
15617                     this.disabled = false;
15618                 }
15619         },
15620
15621         /**
15622          * Disable this KeyNav
15623          */
15624         disable: function(){
15625                 if(!this.disabled){
15626                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15627                 this.el.un("keydown", this.relay);
15628             }else{
15629                 this.el.un("keydown", this.prepareEvent);
15630                 this.el.un("keypress", this.relay);
15631             }
15632                     this.disabled = true;
15633                 }
15634         }
15635 };/*
15636  * Based on:
15637  * Ext JS Library 1.1.1
15638  * Copyright(c) 2006-2007, Ext JS, LLC.
15639  *
15640  * Originally Released Under LGPL - original licence link has changed is not relivant.
15641  *
15642  * Fork - LGPL
15643  * <script type="text/javascript">
15644  */
15645
15646  
15647 /**
15648  * @class Roo.KeyMap
15649  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15650  * The constructor accepts the same config object as defined by {@link #addBinding}.
15651  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15652  * combination it will call the function with this signature (if the match is a multi-key
15653  * combination the callback will still be called only once): (String key, Roo.EventObject e)
15654  * A KeyMap can also handle a string representation of keys.<br />
15655  * Usage:
15656  <pre><code>
15657 // map one key by key code
15658 var map = new Roo.KeyMap("my-element", {
15659     key: 13, // or Roo.EventObject.ENTER
15660     fn: myHandler,
15661     scope: myObject
15662 });
15663
15664 // map multiple keys to one action by string
15665 var map = new Roo.KeyMap("my-element", {
15666     key: "a\r\n\t",
15667     fn: myHandler,
15668     scope: myObject
15669 });
15670
15671 // map multiple keys to multiple actions by strings and array of codes
15672 var map = new Roo.KeyMap("my-element", [
15673     {
15674         key: [10,13],
15675         fn: function(){ alert("Return was pressed"); }
15676     }, {
15677         key: "abc",
15678         fn: function(){ alert('a, b or c was pressed'); }
15679     }, {
15680         key: "\t",
15681         ctrl:true,
15682         shift:true,
15683         fn: function(){ alert('Control + shift + tab was pressed.'); }
15684     }
15685 ]);
15686 </code></pre>
15687  * <b>Note: A KeyMap starts enabled</b>
15688  * @constructor
15689  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15690  * @param {Object} config The config (see {@link #addBinding})
15691  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15692  */
15693 Roo.KeyMap = function(el, config, eventName){
15694     this.el  = Roo.get(el);
15695     this.eventName = eventName || "keydown";
15696     this.bindings = [];
15697     if(config){
15698         this.addBinding(config);
15699     }
15700     this.enable();
15701 };
15702
15703 Roo.KeyMap.prototype = {
15704     /**
15705      * True to stop the event from bubbling and prevent the default browser action if the
15706      * key was handled by the KeyMap (defaults to false)
15707      * @type Boolean
15708      */
15709     stopEvent : false,
15710
15711     /**
15712      * Add a new binding to this KeyMap. The following config object properties are supported:
15713      * <pre>
15714 Property    Type             Description
15715 ----------  ---------------  ----------------------------------------------------------------------
15716 key         String/Array     A single keycode or an array of keycodes to handle
15717 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
15718 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
15719 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
15720 fn          Function         The function to call when KeyMap finds the expected key combination
15721 scope       Object           The scope of the callback function
15722 </pre>
15723      *
15724      * Usage:
15725      * <pre><code>
15726 // Create a KeyMap
15727 var map = new Roo.KeyMap(document, {
15728     key: Roo.EventObject.ENTER,
15729     fn: handleKey,
15730     scope: this
15731 });
15732
15733 //Add a new binding to the existing KeyMap later
15734 map.addBinding({
15735     key: 'abc',
15736     shift: true,
15737     fn: handleKey,
15738     scope: this
15739 });
15740 </code></pre>
15741      * @param {Object/Array} config A single KeyMap config or an array of configs
15742      */
15743         addBinding : function(config){
15744         if(config instanceof Array){
15745             for(var i = 0, len = config.length; i < len; i++){
15746                 this.addBinding(config[i]);
15747             }
15748             return;
15749         }
15750         var keyCode = config.key,
15751             shift = config.shift, 
15752             ctrl = config.ctrl, 
15753             alt = config.alt,
15754             fn = config.fn,
15755             scope = config.scope;
15756         if(typeof keyCode == "string"){
15757             var ks = [];
15758             var keyString = keyCode.toUpperCase();
15759             for(var j = 0, len = keyString.length; j < len; j++){
15760                 ks.push(keyString.charCodeAt(j));
15761             }
15762             keyCode = ks;
15763         }
15764         var keyArray = keyCode instanceof Array;
15765         var handler = function(e){
15766             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
15767                 var k = e.getKey();
15768                 if(keyArray){
15769                     for(var i = 0, len = keyCode.length; i < len; i++){
15770                         if(keyCode[i] == k){
15771                           if(this.stopEvent){
15772                               e.stopEvent();
15773                           }
15774                           fn.call(scope || window, k, e);
15775                           return;
15776                         }
15777                     }
15778                 }else{
15779                     if(k == keyCode){
15780                         if(this.stopEvent){
15781                            e.stopEvent();
15782                         }
15783                         fn.call(scope || window, k, e);
15784                     }
15785                 }
15786             }
15787         };
15788         this.bindings.push(handler);  
15789         },
15790
15791     /**
15792      * Shorthand for adding a single key listener
15793      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15794      * following options:
15795      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15796      * @param {Function} fn The function to call
15797      * @param {Object} scope (optional) The scope of the function
15798      */
15799     on : function(key, fn, scope){
15800         var keyCode, shift, ctrl, alt;
15801         if(typeof key == "object" && !(key instanceof Array)){
15802             keyCode = key.key;
15803             shift = key.shift;
15804             ctrl = key.ctrl;
15805             alt = key.alt;
15806         }else{
15807             keyCode = key;
15808         }
15809         this.addBinding({
15810             key: keyCode,
15811             shift: shift,
15812             ctrl: ctrl,
15813             alt: alt,
15814             fn: fn,
15815             scope: scope
15816         })
15817     },
15818
15819     // private
15820     handleKeyDown : function(e){
15821             if(this.enabled){ //just in case
15822             var b = this.bindings;
15823             for(var i = 0, len = b.length; i < len; i++){
15824                 b[i].call(this, e);
15825             }
15826             }
15827         },
15828         
15829         /**
15830          * Returns true if this KeyMap is enabled
15831          * @return {Boolean} 
15832          */
15833         isEnabled : function(){
15834             return this.enabled;  
15835         },
15836         
15837         /**
15838          * Enables this KeyMap
15839          */
15840         enable: function(){
15841                 if(!this.enabled){
15842                     this.el.on(this.eventName, this.handleKeyDown, this);
15843                     this.enabled = true;
15844                 }
15845         },
15846
15847         /**
15848          * Disable this KeyMap
15849          */
15850         disable: function(){
15851                 if(this.enabled){
15852                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
15853                     this.enabled = false;
15854                 }
15855         }
15856 };/*
15857  * Based on:
15858  * Ext JS Library 1.1.1
15859  * Copyright(c) 2006-2007, Ext JS, LLC.
15860  *
15861  * Originally Released Under LGPL - original licence link has changed is not relivant.
15862  *
15863  * Fork - LGPL
15864  * <script type="text/javascript">
15865  */
15866
15867  
15868 /**
15869  * @class Roo.util.TextMetrics
15870  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15871  * wide, in pixels, a given block of text will be.
15872  * @static
15873  */
15874 Roo.util.TextMetrics = function(){
15875     var shared;
15876     return {
15877         /**
15878          * Measures the size of the specified text
15879          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15880          * that can affect the size of the rendered text
15881          * @param {String} text The text to measure
15882          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15883          * in order to accurately measure the text height
15884          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15885          */
15886         measure : function(el, text, fixedWidth){
15887             if(!shared){
15888                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15889             }
15890             shared.bind(el);
15891             shared.setFixedWidth(fixedWidth || 'auto');
15892             return shared.getSize(text);
15893         },
15894
15895         /**
15896          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
15897          * the overhead of multiple calls to initialize the style properties on each measurement.
15898          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15899          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15900          * in order to accurately measure the text height
15901          * @return {Roo.util.TextMetrics.Instance} instance The new instance
15902          */
15903         createInstance : function(el, fixedWidth){
15904             return Roo.util.TextMetrics.Instance(el, fixedWidth);
15905         }
15906     };
15907 }();
15908
15909 /**
15910  * @class Roo.util.TextMetrics.Instance
15911  * Instance of  TextMetrics Calcuation
15912  * @constructor
15913  * Create a new TextMetrics Instance
15914  * @param {Object} bindto
15915  * @param {Boolean} fixedWidth
15916  */
15917
15918 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
15919 {
15920     var ml = new Roo.Element(document.createElement('div'));
15921     document.body.appendChild(ml.dom);
15922     ml.position('absolute');
15923     ml.setLeftTop(-1000, -1000);
15924     ml.hide();
15925
15926     if(fixedWidth){
15927         ml.setWidth(fixedWidth);
15928     }
15929      
15930     var instance = {
15931         /**
15932          * Returns the size of the specified text based on the internal element's style and width properties
15933          * @param {String} text The text to measure
15934          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15935          */
15936         getSize : function(text){
15937             ml.update(text);
15938             var s = ml.getSize();
15939             ml.update('');
15940             return s;
15941         },
15942
15943         /**
15944          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15945          * that can affect the size of the rendered text
15946          * @param {String/HTMLElement} el The element, dom node or id
15947          */
15948         bind : function(el){
15949             ml.setStyle(
15950                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15951             );
15952         },
15953
15954         /**
15955          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
15956          * to set a fixed width in order to accurately measure the text height.
15957          * @param {Number} width The width to set on the element
15958          */
15959         setFixedWidth : function(width){
15960             ml.setWidth(width);
15961         },
15962
15963         /**
15964          * Returns the measured width of the specified text
15965          * @param {String} text The text to measure
15966          * @return {Number} width The width in pixels
15967          */
15968         getWidth : function(text){
15969             ml.dom.style.width = 'auto';
15970             return this.getSize(text).width;
15971         },
15972
15973         /**
15974          * Returns the measured height of the specified text.  For multiline text, be sure to call
15975          * {@link #setFixedWidth} if necessary.
15976          * @param {String} text The text to measure
15977          * @return {Number} height The height in pixels
15978          */
15979         getHeight : function(text){
15980             return this.getSize(text).height;
15981         }
15982     };
15983
15984     instance.bind(bindTo);
15985
15986     return instance;
15987 };
15988
15989 // backwards compat
15990 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15991  * Based on:
15992  * Ext JS Library 1.1.1
15993  * Copyright(c) 2006-2007, Ext JS, LLC.
15994  *
15995  * Originally Released Under LGPL - original licence link has changed is not relivant.
15996  *
15997  * Fork - LGPL
15998  * <script type="text/javascript">
15999  */
16000
16001 /**
16002  * @class Roo.state.Provider
16003  * Abstract base class for state provider implementations. This class provides methods
16004  * for encoding and decoding <b>typed</b> variables including dates and defines the 
16005  * Provider interface.
16006  */
16007 Roo.state.Provider = function(){
16008     /**
16009      * @event statechange
16010      * Fires when a state change occurs.
16011      * @param {Provider} this This state provider
16012      * @param {String} key The state key which was changed
16013      * @param {String} value The encoded value for the state
16014      */
16015     this.addEvents({
16016         "statechange": true
16017     });
16018     this.state = {};
16019     Roo.state.Provider.superclass.constructor.call(this);
16020 };
16021 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16022     /**
16023      * Returns the current value for a key
16024      * @param {String} name The key name
16025      * @param {Mixed} defaultValue A default value to return if the key's value is not found
16026      * @return {Mixed} The state data
16027      */
16028     get : function(name, defaultValue){
16029         return typeof this.state[name] == "undefined" ?
16030             defaultValue : this.state[name];
16031     },
16032     
16033     /**
16034      * Clears a value from the state
16035      * @param {String} name The key name
16036      */
16037     clear : function(name){
16038         delete this.state[name];
16039         this.fireEvent("statechange", this, name, null);
16040     },
16041     
16042     /**
16043      * Sets the value for a key
16044      * @param {String} name The key name
16045      * @param {Mixed} value The value to set
16046      */
16047     set : function(name, value){
16048         this.state[name] = value;
16049         this.fireEvent("statechange", this, name, value);
16050     },
16051     
16052     /**
16053      * Decodes a string previously encoded with {@link #encodeValue}.
16054      * @param {String} value The value to decode
16055      * @return {Mixed} The decoded value
16056      */
16057     decodeValue : function(cookie){
16058         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16059         var matches = re.exec(unescape(cookie));
16060         if(!matches || !matches[1]) {
16061             return; // non state cookie
16062         }
16063         var type = matches[1];
16064         var v = matches[2];
16065         switch(type){
16066             case "n":
16067                 return parseFloat(v);
16068             case "d":
16069                 return new Date(Date.parse(v));
16070             case "b":
16071                 return (v == "1");
16072             case "a":
16073                 var all = [];
16074                 var values = v.split("^");
16075                 for(var i = 0, len = values.length; i < len; i++){
16076                     all.push(this.decodeValue(values[i]));
16077                 }
16078                 return all;
16079            case "o":
16080                 var all = {};
16081                 var values = v.split("^");
16082                 for(var i = 0, len = values.length; i < len; i++){
16083                     var kv = values[i].split("=");
16084                     all[kv[0]] = this.decodeValue(kv[1]);
16085                 }
16086                 return all;
16087            default:
16088                 return v;
16089         }
16090     },
16091     
16092     /**
16093      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16094      * @param {Mixed} value The value to encode
16095      * @return {String} The encoded value
16096      */
16097     encodeValue : function(v){
16098         var enc;
16099         if(typeof v == "number"){
16100             enc = "n:" + v;
16101         }else if(typeof v == "boolean"){
16102             enc = "b:" + (v ? "1" : "0");
16103         }else if(v instanceof Date){
16104             enc = "d:" + v.toGMTString();
16105         }else if(v instanceof Array){
16106             var flat = "";
16107             for(var i = 0, len = v.length; i < len; i++){
16108                 flat += this.encodeValue(v[i]);
16109                 if(i != len-1) {
16110                     flat += "^";
16111                 }
16112             }
16113             enc = "a:" + flat;
16114         }else if(typeof v == "object"){
16115             var flat = "";
16116             for(var key in v){
16117                 if(typeof v[key] != "function"){
16118                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16119                 }
16120             }
16121             enc = "o:" + flat.substring(0, flat.length-1);
16122         }else{
16123             enc = "s:" + v;
16124         }
16125         return escape(enc);        
16126     }
16127 });
16128
16129 /*
16130  * Based on:
16131  * Ext JS Library 1.1.1
16132  * Copyright(c) 2006-2007, Ext JS, LLC.
16133  *
16134  * Originally Released Under LGPL - original licence link has changed is not relivant.
16135  *
16136  * Fork - LGPL
16137  * <script type="text/javascript">
16138  */
16139 /**
16140  * @class Roo.state.Manager
16141  * This is the global state manager. By default all components that are "state aware" check this class
16142  * for state information if you don't pass them a custom state provider. In order for this class
16143  * to be useful, it must be initialized with a provider when your application initializes.
16144  <pre><code>
16145 // in your initialization function
16146 init : function(){
16147    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16148    ...
16149    // supposed you have a {@link Roo.BorderLayout}
16150    var layout = new Roo.BorderLayout(...);
16151    layout.restoreState();
16152    // or a {Roo.BasicDialog}
16153    var dialog = new Roo.BasicDialog(...);
16154    dialog.restoreState();
16155  </code></pre>
16156  * @static
16157  */
16158 Roo.state.Manager = function(){
16159     var provider = new Roo.state.Provider();
16160     
16161     return {
16162         /**
16163          * Configures the default state provider for your application
16164          * @param {Provider} stateProvider The state provider to set
16165          */
16166         setProvider : function(stateProvider){
16167             provider = stateProvider;
16168         },
16169         
16170         /**
16171          * Returns the current value for a key
16172          * @param {String} name The key name
16173          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16174          * @return {Mixed} The state data
16175          */
16176         get : function(key, defaultValue){
16177             return provider.get(key, defaultValue);
16178         },
16179         
16180         /**
16181          * Sets the value for a key
16182          * @param {String} name The key name
16183          * @param {Mixed} value The state data
16184          */
16185          set : function(key, value){
16186             provider.set(key, value);
16187         },
16188         
16189         /**
16190          * Clears a value from the state
16191          * @param {String} name The key name
16192          */
16193         clear : function(key){
16194             provider.clear(key);
16195         },
16196         
16197         /**
16198          * Gets the currently configured state provider
16199          * @return {Provider} The state provider
16200          */
16201         getProvider : function(){
16202             return provider;
16203         }
16204     };
16205 }();
16206 /*
16207  * Based on:
16208  * Ext JS Library 1.1.1
16209  * Copyright(c) 2006-2007, Ext JS, LLC.
16210  *
16211  * Originally Released Under LGPL - original licence link has changed is not relivant.
16212  *
16213  * Fork - LGPL
16214  * <script type="text/javascript">
16215  */
16216 /**
16217  * @class Roo.state.CookieProvider
16218  * @extends Roo.state.Provider
16219  * The default Provider implementation which saves state via cookies.
16220  * <br />Usage:
16221  <pre><code>
16222    var cp = new Roo.state.CookieProvider({
16223        path: "/cgi-bin/",
16224        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16225        domain: "roojs.com"
16226    })
16227    Roo.state.Manager.setProvider(cp);
16228  </code></pre>
16229  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16230  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16231  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16232  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16233  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16234  * domain the page is running on including the 'www' like 'www.roojs.com')
16235  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16236  * @constructor
16237  * Create a new CookieProvider
16238  * @param {Object} config The configuration object
16239  */
16240 Roo.state.CookieProvider = function(config){
16241     Roo.state.CookieProvider.superclass.constructor.call(this);
16242     this.path = "/";
16243     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16244     this.domain = null;
16245     this.secure = false;
16246     Roo.apply(this, config);
16247     this.state = this.readCookies();
16248 };
16249
16250 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16251     // private
16252     set : function(name, value){
16253         if(typeof value == "undefined" || value === null){
16254             this.clear(name);
16255             return;
16256         }
16257         this.setCookie(name, value);
16258         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16259     },
16260
16261     // private
16262     clear : function(name){
16263         this.clearCookie(name);
16264         Roo.state.CookieProvider.superclass.clear.call(this, name);
16265     },
16266
16267     // private
16268     readCookies : function(){
16269         var cookies = {};
16270         var c = document.cookie + ";";
16271         var re = /\s?(.*?)=(.*?);/g;
16272         var matches;
16273         while((matches = re.exec(c)) != null){
16274             var name = matches[1];
16275             var value = matches[2];
16276             if(name && name.substring(0,3) == "ys-"){
16277                 cookies[name.substr(3)] = this.decodeValue(value);
16278             }
16279         }
16280         return cookies;
16281     },
16282
16283     // private
16284     setCookie : function(name, value){
16285         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16286            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16287            ((this.path == null) ? "" : ("; path=" + this.path)) +
16288            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16289            ((this.secure == true) ? "; secure" : "");
16290     },
16291
16292     // private
16293     clearCookie : function(name){
16294         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16295            ((this.path == null) ? "" : ("; path=" + this.path)) +
16296            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16297            ((this.secure == true) ? "; secure" : "");
16298     }
16299 });/*
16300  * Based on:
16301  * Ext JS Library 1.1.1
16302  * Copyright(c) 2006-2007, Ext JS, LLC.
16303  *
16304  * Originally Released Under LGPL - original licence link has changed is not relivant.
16305  *
16306  * Fork - LGPL
16307  * <script type="text/javascript">
16308  */
16309  
16310
16311 /**
16312  * @class Roo.ComponentMgr
16313  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16314  * @static
16315  */
16316 Roo.ComponentMgr = function(){
16317     var all = new Roo.util.MixedCollection();
16318
16319     return {
16320         /**
16321          * Registers a component.
16322          * @param {Roo.Component} c The component
16323          */
16324         register : function(c){
16325             all.add(c);
16326         },
16327
16328         /**
16329          * Unregisters a component.
16330          * @param {Roo.Component} c The component
16331          */
16332         unregister : function(c){
16333             all.remove(c);
16334         },
16335
16336         /**
16337          * Returns a component by id
16338          * @param {String} id The component id
16339          */
16340         get : function(id){
16341             return all.get(id);
16342         },
16343
16344         /**
16345          * Registers a function that will be called when a specified component is added to ComponentMgr
16346          * @param {String} id The component id
16347          * @param {Funtction} fn The callback function
16348          * @param {Object} scope The scope of the callback
16349          */
16350         onAvailable : function(id, fn, scope){
16351             all.on("add", function(index, o){
16352                 if(o.id == id){
16353                     fn.call(scope || o, o);
16354                     all.un("add", fn, scope);
16355                 }
16356             });
16357         }
16358     };
16359 }();/*
16360  * Based on:
16361  * Ext JS Library 1.1.1
16362  * Copyright(c) 2006-2007, Ext JS, LLC.
16363  *
16364  * Originally Released Under LGPL - original licence link has changed is not relivant.
16365  *
16366  * Fork - LGPL
16367  * <script type="text/javascript">
16368  */
16369  
16370 /**
16371  * @class Roo.Component
16372  * @extends Roo.util.Observable
16373  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16374  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16375  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16376  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16377  * All visual components (widgets) that require rendering into a layout should subclass Component.
16378  * @constructor
16379  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16380  * 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
16381  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16382  */
16383 Roo.Component = function(config){
16384     config = config || {};
16385     if(config.tagName || config.dom || typeof config == "string"){ // element object
16386         config = {el: config, id: config.id || config};
16387     }
16388     this.initialConfig = config;
16389
16390     Roo.apply(this, config);
16391     this.addEvents({
16392         /**
16393          * @event disable
16394          * Fires after the component is disabled.
16395              * @param {Roo.Component} this
16396              */
16397         disable : true,
16398         /**
16399          * @event enable
16400          * Fires after the component is enabled.
16401              * @param {Roo.Component} this
16402              */
16403         enable : true,
16404         /**
16405          * @event beforeshow
16406          * Fires before the component is shown.  Return false to stop the show.
16407              * @param {Roo.Component} this
16408              */
16409         beforeshow : true,
16410         /**
16411          * @event show
16412          * Fires after the component is shown.
16413              * @param {Roo.Component} this
16414              */
16415         show : true,
16416         /**
16417          * @event beforehide
16418          * Fires before the component is hidden. Return false to stop the hide.
16419              * @param {Roo.Component} this
16420              */
16421         beforehide : true,
16422         /**
16423          * @event hide
16424          * Fires after the component is hidden.
16425              * @param {Roo.Component} this
16426              */
16427         hide : true,
16428         /**
16429          * @event beforerender
16430          * Fires before the component is rendered. Return false to stop the render.
16431              * @param {Roo.Component} this
16432              */
16433         beforerender : true,
16434         /**
16435          * @event render
16436          * Fires after the component is rendered.
16437              * @param {Roo.Component} this
16438              */
16439         render : true,
16440         /**
16441          * @event beforedestroy
16442          * Fires before the component is destroyed. Return false to stop the destroy.
16443              * @param {Roo.Component} this
16444              */
16445         beforedestroy : true,
16446         /**
16447          * @event destroy
16448          * Fires after the component is destroyed.
16449              * @param {Roo.Component} this
16450              */
16451         destroy : true
16452     });
16453     if(!this.id){
16454         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16455     }
16456     Roo.ComponentMgr.register(this);
16457     Roo.Component.superclass.constructor.call(this);
16458     this.initComponent();
16459     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16460         this.render(this.renderTo);
16461         delete this.renderTo;
16462     }
16463 };
16464
16465 /** @private */
16466 Roo.Component.AUTO_ID = 1000;
16467
16468 Roo.extend(Roo.Component, Roo.util.Observable, {
16469     /**
16470      * @scope Roo.Component.prototype
16471      * @type {Boolean}
16472      * true if this component is hidden. Read-only.
16473      */
16474     hidden : false,
16475     /**
16476      * @type {Boolean}
16477      * true if this component is disabled. Read-only.
16478      */
16479     disabled : false,
16480     /**
16481      * @type {Boolean}
16482      * true if this component has been rendered. Read-only.
16483      */
16484     rendered : false,
16485     
16486     /** @cfg {String} disableClass
16487      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16488      */
16489     disabledClass : "x-item-disabled",
16490         /** @cfg {Boolean} allowDomMove
16491          * Whether the component can move the Dom node when rendering (defaults to true).
16492          */
16493     allowDomMove : true,
16494     /** @cfg {String} hideMode (display|visibility)
16495      * How this component should hidden. Supported values are
16496      * "visibility" (css visibility), "offsets" (negative offset position) and
16497      * "display" (css display) - defaults to "display".
16498      */
16499     hideMode: 'display',
16500
16501     /** @private */
16502     ctype : "Roo.Component",
16503
16504     /**
16505      * @cfg {String} actionMode 
16506      * which property holds the element that used for  hide() / show() / disable() / enable()
16507      * default is 'el' for forms you probably want to set this to fieldEl 
16508      */
16509     actionMode : "el",
16510
16511     /** @private */
16512     getActionEl : function(){
16513         return this[this.actionMode];
16514     },
16515
16516     initComponent : Roo.emptyFn,
16517     /**
16518      * If this is a lazy rendering component, render it to its container element.
16519      * @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.
16520      */
16521     render : function(container, position){
16522         
16523         if(this.rendered){
16524             return this;
16525         }
16526         
16527         if(this.fireEvent("beforerender", this) === false){
16528             return false;
16529         }
16530         
16531         if(!container && this.el){
16532             this.el = Roo.get(this.el);
16533             container = this.el.dom.parentNode;
16534             this.allowDomMove = false;
16535         }
16536         this.container = Roo.get(container);
16537         this.rendered = true;
16538         if(position !== undefined){
16539             if(typeof position == 'number'){
16540                 position = this.container.dom.childNodes[position];
16541             }else{
16542                 position = Roo.getDom(position);
16543             }
16544         }
16545         this.onRender(this.container, position || null);
16546         if(this.cls){
16547             this.el.addClass(this.cls);
16548             delete this.cls;
16549         }
16550         if(this.style){
16551             this.el.applyStyles(this.style);
16552             delete this.style;
16553         }
16554         this.fireEvent("render", this);
16555         this.afterRender(this.container);
16556         if(this.hidden){
16557             this.hide();
16558         }
16559         if(this.disabled){
16560             this.disable();
16561         }
16562
16563         return this;
16564         
16565     },
16566
16567     /** @private */
16568     // default function is not really useful
16569     onRender : function(ct, position){
16570         if(this.el){
16571             this.el = Roo.get(this.el);
16572             if(this.allowDomMove !== false){
16573                 ct.dom.insertBefore(this.el.dom, position);
16574             }
16575         }
16576     },
16577
16578     /** @private */
16579     getAutoCreate : function(){
16580         var cfg = typeof this.autoCreate == "object" ?
16581                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16582         if(this.id && !cfg.id){
16583             cfg.id = this.id;
16584         }
16585         return cfg;
16586     },
16587
16588     /** @private */
16589     afterRender : Roo.emptyFn,
16590
16591     /**
16592      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16593      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16594      */
16595     destroy : function(){
16596         if(this.fireEvent("beforedestroy", this) !== false){
16597             this.purgeListeners();
16598             this.beforeDestroy();
16599             if(this.rendered){
16600                 this.el.removeAllListeners();
16601                 this.el.remove();
16602                 if(this.actionMode == "container"){
16603                     this.container.remove();
16604                 }
16605             }
16606             this.onDestroy();
16607             Roo.ComponentMgr.unregister(this);
16608             this.fireEvent("destroy", this);
16609         }
16610     },
16611
16612         /** @private */
16613     beforeDestroy : function(){
16614
16615     },
16616
16617         /** @private */
16618         onDestroy : function(){
16619
16620     },
16621
16622     /**
16623      * Returns the underlying {@link Roo.Element}.
16624      * @return {Roo.Element} The element
16625      */
16626     getEl : function(){
16627         return this.el;
16628     },
16629
16630     /**
16631      * Returns the id of this component.
16632      * @return {String}
16633      */
16634     getId : function(){
16635         return this.id;
16636     },
16637
16638     /**
16639      * Try to focus this component.
16640      * @param {Boolean} selectText True to also select the text in this component (if applicable)
16641      * @return {Roo.Component} this
16642      */
16643     focus : function(selectText){
16644         if(this.rendered){
16645             this.el.focus();
16646             if(selectText === true){
16647                 this.el.dom.select();
16648             }
16649         }
16650         return this;
16651     },
16652
16653     /** @private */
16654     blur : function(){
16655         if(this.rendered){
16656             this.el.blur();
16657         }
16658         return this;
16659     },
16660
16661     /**
16662      * Disable this component.
16663      * @return {Roo.Component} this
16664      */
16665     disable : function(){
16666         if(this.rendered){
16667             this.onDisable();
16668         }
16669         this.disabled = true;
16670         this.fireEvent("disable", this);
16671         return this;
16672     },
16673
16674         // private
16675     onDisable : function(){
16676         this.getActionEl().addClass(this.disabledClass);
16677         this.el.dom.disabled = true;
16678     },
16679
16680     /**
16681      * Enable this component.
16682      * @return {Roo.Component} this
16683      */
16684     enable : function(){
16685         if(this.rendered){
16686             this.onEnable();
16687         }
16688         this.disabled = false;
16689         this.fireEvent("enable", this);
16690         return this;
16691     },
16692
16693         // private
16694     onEnable : function(){
16695         this.getActionEl().removeClass(this.disabledClass);
16696         this.el.dom.disabled = false;
16697     },
16698
16699     /**
16700      * Convenience function for setting disabled/enabled by boolean.
16701      * @param {Boolean} disabled
16702      */
16703     setDisabled : function(disabled){
16704         this[disabled ? "disable" : "enable"]();
16705     },
16706
16707     /**
16708      * Show this component.
16709      * @return {Roo.Component} this
16710      */
16711     show: function(){
16712         if(this.fireEvent("beforeshow", this) !== false){
16713             this.hidden = false;
16714             if(this.rendered){
16715                 this.onShow();
16716             }
16717             this.fireEvent("show", this);
16718         }
16719         return this;
16720     },
16721
16722     // private
16723     onShow : function(){
16724         var ae = this.getActionEl();
16725         if(this.hideMode == 'visibility'){
16726             ae.dom.style.visibility = "visible";
16727         }else if(this.hideMode == 'offsets'){
16728             ae.removeClass('x-hidden');
16729         }else{
16730             ae.dom.style.display = "";
16731         }
16732     },
16733
16734     /**
16735      * Hide this component.
16736      * @return {Roo.Component} this
16737      */
16738     hide: function(){
16739         if(this.fireEvent("beforehide", this) !== false){
16740             this.hidden = true;
16741             if(this.rendered){
16742                 this.onHide();
16743             }
16744             this.fireEvent("hide", this);
16745         }
16746         return this;
16747     },
16748
16749     // private
16750     onHide : function(){
16751         var ae = this.getActionEl();
16752         if(this.hideMode == 'visibility'){
16753             ae.dom.style.visibility = "hidden";
16754         }else if(this.hideMode == 'offsets'){
16755             ae.addClass('x-hidden');
16756         }else{
16757             ae.dom.style.display = "none";
16758         }
16759     },
16760
16761     /**
16762      * Convenience function to hide or show this component by boolean.
16763      * @param {Boolean} visible True to show, false to hide
16764      * @return {Roo.Component} this
16765      */
16766     setVisible: function(visible){
16767         if(visible) {
16768             this.show();
16769         }else{
16770             this.hide();
16771         }
16772         return this;
16773     },
16774
16775     /**
16776      * Returns true if this component is visible.
16777      */
16778     isVisible : function(){
16779         return this.getActionEl().isVisible();
16780     },
16781
16782     cloneConfig : function(overrides){
16783         overrides = overrides || {};
16784         var id = overrides.id || Roo.id();
16785         var cfg = Roo.applyIf(overrides, this.initialConfig);
16786         cfg.id = id; // prevent dup id
16787         return new this.constructor(cfg);
16788     }
16789 });/*
16790  * Based on:
16791  * Ext JS Library 1.1.1
16792  * Copyright(c) 2006-2007, Ext JS, LLC.
16793  *
16794  * Originally Released Under LGPL - original licence link has changed is not relivant.
16795  *
16796  * Fork - LGPL
16797  * <script type="text/javascript">
16798  */
16799
16800 /**
16801  * @class Roo.BoxComponent
16802  * @extends Roo.Component
16803  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
16804  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
16805  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16806  * layout containers.
16807  * @constructor
16808  * @param {Roo.Element/String/Object} config The configuration options.
16809  */
16810 Roo.BoxComponent = function(config){
16811     Roo.Component.call(this, config);
16812     this.addEvents({
16813         /**
16814          * @event resize
16815          * Fires after the component is resized.
16816              * @param {Roo.Component} this
16817              * @param {Number} adjWidth The box-adjusted width that was set
16818              * @param {Number} adjHeight The box-adjusted height that was set
16819              * @param {Number} rawWidth The width that was originally specified
16820              * @param {Number} rawHeight The height that was originally specified
16821              */
16822         resize : true,
16823         /**
16824          * @event move
16825          * Fires after the component is moved.
16826              * @param {Roo.Component} this
16827              * @param {Number} x The new x position
16828              * @param {Number} y The new y position
16829              */
16830         move : true
16831     });
16832 };
16833
16834 Roo.extend(Roo.BoxComponent, Roo.Component, {
16835     // private, set in afterRender to signify that the component has been rendered
16836     boxReady : false,
16837     // private, used to defer height settings to subclasses
16838     deferHeight: false,
16839     /** @cfg {Number} width
16840      * width (optional) size of component
16841      */
16842      /** @cfg {Number} height
16843      * height (optional) size of component
16844      */
16845      
16846     /**
16847      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
16848      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16849      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16850      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16851      * @return {Roo.BoxComponent} this
16852      */
16853     setSize : function(w, h){
16854         // support for standard size objects
16855         if(typeof w == 'object'){
16856             h = w.height;
16857             w = w.width;
16858         }
16859         // not rendered
16860         if(!this.boxReady){
16861             this.width = w;
16862             this.height = h;
16863             return this;
16864         }
16865
16866         // prevent recalcs when not needed
16867         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16868             return this;
16869         }
16870         this.lastSize = {width: w, height: h};
16871
16872         var adj = this.adjustSize(w, h);
16873         var aw = adj.width, ah = adj.height;
16874         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16875             var rz = this.getResizeEl();
16876             if(!this.deferHeight && aw !== undefined && ah !== undefined){
16877                 rz.setSize(aw, ah);
16878             }else if(!this.deferHeight && ah !== undefined){
16879                 rz.setHeight(ah);
16880             }else if(aw !== undefined){
16881                 rz.setWidth(aw);
16882             }
16883             this.onResize(aw, ah, w, h);
16884             this.fireEvent('resize', this, aw, ah, w, h);
16885         }
16886         return this;
16887     },
16888
16889     /**
16890      * Gets the current size of the component's underlying element.
16891      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16892      */
16893     getSize : function(){
16894         return this.el.getSize();
16895     },
16896
16897     /**
16898      * Gets the current XY position of the component's underlying element.
16899      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16900      * @return {Array} The XY position of the element (e.g., [100, 200])
16901      */
16902     getPosition : function(local){
16903         if(local === true){
16904             return [this.el.getLeft(true), this.el.getTop(true)];
16905         }
16906         return this.xy || this.el.getXY();
16907     },
16908
16909     /**
16910      * Gets the current box measurements of the component's underlying element.
16911      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16912      * @returns {Object} box An object in the format {x, y, width, height}
16913      */
16914     getBox : function(local){
16915         var s = this.el.getSize();
16916         if(local){
16917             s.x = this.el.getLeft(true);
16918             s.y = this.el.getTop(true);
16919         }else{
16920             var xy = this.xy || this.el.getXY();
16921             s.x = xy[0];
16922             s.y = xy[1];
16923         }
16924         return s;
16925     },
16926
16927     /**
16928      * Sets the current box measurements of the component's underlying element.
16929      * @param {Object} box An object in the format {x, y, width, height}
16930      * @returns {Roo.BoxComponent} this
16931      */
16932     updateBox : function(box){
16933         this.setSize(box.width, box.height);
16934         this.setPagePosition(box.x, box.y);
16935         return this;
16936     },
16937
16938     // protected
16939     getResizeEl : function(){
16940         return this.resizeEl || this.el;
16941     },
16942
16943     // protected
16944     getPositionEl : function(){
16945         return this.positionEl || this.el;
16946     },
16947
16948     /**
16949      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
16950      * This method fires the move event.
16951      * @param {Number} left The new left
16952      * @param {Number} top The new top
16953      * @returns {Roo.BoxComponent} this
16954      */
16955     setPosition : function(x, y){
16956         this.x = x;
16957         this.y = y;
16958         if(!this.boxReady){
16959             return this;
16960         }
16961         var adj = this.adjustPosition(x, y);
16962         var ax = adj.x, ay = adj.y;
16963
16964         var el = this.getPositionEl();
16965         if(ax !== undefined || ay !== undefined){
16966             if(ax !== undefined && ay !== undefined){
16967                 el.setLeftTop(ax, ay);
16968             }else if(ax !== undefined){
16969                 el.setLeft(ax);
16970             }else if(ay !== undefined){
16971                 el.setTop(ay);
16972             }
16973             this.onPosition(ax, ay);
16974             this.fireEvent('move', this, ax, ay);
16975         }
16976         return this;
16977     },
16978
16979     /**
16980      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
16981      * This method fires the move event.
16982      * @param {Number} x The new x position
16983      * @param {Number} y The new y position
16984      * @returns {Roo.BoxComponent} this
16985      */
16986     setPagePosition : function(x, y){
16987         this.pageX = x;
16988         this.pageY = y;
16989         if(!this.boxReady){
16990             return;
16991         }
16992         if(x === undefined || y === undefined){ // cannot translate undefined points
16993             return;
16994         }
16995         var p = this.el.translatePoints(x, y);
16996         this.setPosition(p.left, p.top);
16997         return this;
16998     },
16999
17000     // private
17001     onRender : function(ct, position){
17002         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17003         if(this.resizeEl){
17004             this.resizeEl = Roo.get(this.resizeEl);
17005         }
17006         if(this.positionEl){
17007             this.positionEl = Roo.get(this.positionEl);
17008         }
17009     },
17010
17011     // private
17012     afterRender : function(){
17013         Roo.BoxComponent.superclass.afterRender.call(this);
17014         this.boxReady = true;
17015         this.setSize(this.width, this.height);
17016         if(this.x || this.y){
17017             this.setPosition(this.x, this.y);
17018         }
17019         if(this.pageX || this.pageY){
17020             this.setPagePosition(this.pageX, this.pageY);
17021         }
17022     },
17023
17024     /**
17025      * Force the component's size to recalculate based on the underlying element's current height and width.
17026      * @returns {Roo.BoxComponent} this
17027      */
17028     syncSize : function(){
17029         delete this.lastSize;
17030         this.setSize(this.el.getWidth(), this.el.getHeight());
17031         return this;
17032     },
17033
17034     /**
17035      * Called after the component is resized, this method is empty by default but can be implemented by any
17036      * subclass that needs to perform custom logic after a resize occurs.
17037      * @param {Number} adjWidth The box-adjusted width that was set
17038      * @param {Number} adjHeight The box-adjusted height that was set
17039      * @param {Number} rawWidth The width that was originally specified
17040      * @param {Number} rawHeight The height that was originally specified
17041      */
17042     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17043
17044     },
17045
17046     /**
17047      * Called after the component is moved, this method is empty by default but can be implemented by any
17048      * subclass that needs to perform custom logic after a move occurs.
17049      * @param {Number} x The new x position
17050      * @param {Number} y The new y position
17051      */
17052     onPosition : function(x, y){
17053
17054     },
17055
17056     // private
17057     adjustSize : function(w, h){
17058         if(this.autoWidth){
17059             w = 'auto';
17060         }
17061         if(this.autoHeight){
17062             h = 'auto';
17063         }
17064         return {width : w, height: h};
17065     },
17066
17067     // private
17068     adjustPosition : function(x, y){
17069         return {x : x, y: y};
17070     }
17071 });/*
17072  * Based on:
17073  * Ext JS Library 1.1.1
17074  * Copyright(c) 2006-2007, Ext JS, LLC.
17075  *
17076  * Originally Released Under LGPL - original licence link has changed is not relivant.
17077  *
17078  * Fork - LGPL
17079  * <script type="text/javascript">
17080  */
17081  (function(){ 
17082 /**
17083  * @class Roo.Layer
17084  * @extends Roo.Element
17085  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17086  * automatic maintaining of shadow/shim positions.
17087  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17088  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17089  * you can pass a string with a CSS class name. False turns off the shadow.
17090  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17091  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17092  * @cfg {String} cls CSS class to add to the element
17093  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17094  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17095  * @constructor
17096  * @param {Object} config An object with config options.
17097  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17098  */
17099
17100 Roo.Layer = function(config, existingEl){
17101     config = config || {};
17102     var dh = Roo.DomHelper;
17103     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17104     if(existingEl){
17105         this.dom = Roo.getDom(existingEl);
17106     }
17107     if(!this.dom){
17108         var o = config.dh || {tag: "div", cls: "x-layer"};
17109         this.dom = dh.append(pel, o);
17110     }
17111     if(config.cls){
17112         this.addClass(config.cls);
17113     }
17114     this.constrain = config.constrain !== false;
17115     this.visibilityMode = Roo.Element.VISIBILITY;
17116     if(config.id){
17117         this.id = this.dom.id = config.id;
17118     }else{
17119         this.id = Roo.id(this.dom);
17120     }
17121     this.zindex = config.zindex || this.getZIndex();
17122     this.position("absolute", this.zindex);
17123     if(config.shadow){
17124         this.shadowOffset = config.shadowOffset || 4;
17125         this.shadow = new Roo.Shadow({
17126             offset : this.shadowOffset,
17127             mode : config.shadow
17128         });
17129     }else{
17130         this.shadowOffset = 0;
17131     }
17132     this.useShim = config.shim !== false && Roo.useShims;
17133     this.useDisplay = config.useDisplay;
17134     this.hide();
17135 };
17136
17137 var supr = Roo.Element.prototype;
17138
17139 // shims are shared among layer to keep from having 100 iframes
17140 var shims = [];
17141
17142 Roo.extend(Roo.Layer, Roo.Element, {
17143
17144     getZIndex : function(){
17145         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17146     },
17147
17148     getShim : function(){
17149         if(!this.useShim){
17150             return null;
17151         }
17152         if(this.shim){
17153             return this.shim;
17154         }
17155         var shim = shims.shift();
17156         if(!shim){
17157             shim = this.createShim();
17158             shim.enableDisplayMode('block');
17159             shim.dom.style.display = 'none';
17160             shim.dom.style.visibility = 'visible';
17161         }
17162         var pn = this.dom.parentNode;
17163         if(shim.dom.parentNode != pn){
17164             pn.insertBefore(shim.dom, this.dom);
17165         }
17166         shim.setStyle('z-index', this.getZIndex()-2);
17167         this.shim = shim;
17168         return shim;
17169     },
17170
17171     hideShim : function(){
17172         if(this.shim){
17173             this.shim.setDisplayed(false);
17174             shims.push(this.shim);
17175             delete this.shim;
17176         }
17177     },
17178
17179     disableShadow : function(){
17180         if(this.shadow){
17181             this.shadowDisabled = true;
17182             this.shadow.hide();
17183             this.lastShadowOffset = this.shadowOffset;
17184             this.shadowOffset = 0;
17185         }
17186     },
17187
17188     enableShadow : function(show){
17189         if(this.shadow){
17190             this.shadowDisabled = false;
17191             this.shadowOffset = this.lastShadowOffset;
17192             delete this.lastShadowOffset;
17193             if(show){
17194                 this.sync(true);
17195             }
17196         }
17197     },
17198
17199     // private
17200     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17201     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17202     sync : function(doShow){
17203         var sw = this.shadow;
17204         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17205             var sh = this.getShim();
17206
17207             var w = this.getWidth(),
17208                 h = this.getHeight();
17209
17210             var l = this.getLeft(true),
17211                 t = this.getTop(true);
17212
17213             if(sw && !this.shadowDisabled){
17214                 if(doShow && !sw.isVisible()){
17215                     sw.show(this);
17216                 }else{
17217                     sw.realign(l, t, w, h);
17218                 }
17219                 if(sh){
17220                     if(doShow){
17221                        sh.show();
17222                     }
17223                     // fit the shim behind the shadow, so it is shimmed too
17224                     var a = sw.adjusts, s = sh.dom.style;
17225                     s.left = (Math.min(l, l+a.l))+"px";
17226                     s.top = (Math.min(t, t+a.t))+"px";
17227                     s.width = (w+a.w)+"px";
17228                     s.height = (h+a.h)+"px";
17229                 }
17230             }else if(sh){
17231                 if(doShow){
17232                    sh.show();
17233                 }
17234                 sh.setSize(w, h);
17235                 sh.setLeftTop(l, t);
17236             }
17237             
17238         }
17239     },
17240
17241     // private
17242     destroy : function(){
17243         this.hideShim();
17244         if(this.shadow){
17245             this.shadow.hide();
17246         }
17247         this.removeAllListeners();
17248         var pn = this.dom.parentNode;
17249         if(pn){
17250             pn.removeChild(this.dom);
17251         }
17252         Roo.Element.uncache(this.id);
17253     },
17254
17255     remove : function(){
17256         this.destroy();
17257     },
17258
17259     // private
17260     beginUpdate : function(){
17261         this.updating = true;
17262     },
17263
17264     // private
17265     endUpdate : function(){
17266         this.updating = false;
17267         this.sync(true);
17268     },
17269
17270     // private
17271     hideUnders : function(negOffset){
17272         if(this.shadow){
17273             this.shadow.hide();
17274         }
17275         this.hideShim();
17276     },
17277
17278     // private
17279     constrainXY : function(){
17280         if(this.constrain){
17281             var vw = Roo.lib.Dom.getViewWidth(),
17282                 vh = Roo.lib.Dom.getViewHeight();
17283             var s = Roo.get(document).getScroll();
17284
17285             var xy = this.getXY();
17286             var x = xy[0], y = xy[1];   
17287             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17288             // only move it if it needs it
17289             var moved = false;
17290             // first validate right/bottom
17291             if((x + w) > vw+s.left){
17292                 x = vw - w - this.shadowOffset;
17293                 moved = true;
17294             }
17295             if((y + h) > vh+s.top){
17296                 y = vh - h - this.shadowOffset;
17297                 moved = true;
17298             }
17299             // then make sure top/left isn't negative
17300             if(x < s.left){
17301                 x = s.left;
17302                 moved = true;
17303             }
17304             if(y < s.top){
17305                 y = s.top;
17306                 moved = true;
17307             }
17308             if(moved){
17309                 if(this.avoidY){
17310                     var ay = this.avoidY;
17311                     if(y <= ay && (y+h) >= ay){
17312                         y = ay-h-5;   
17313                     }
17314                 }
17315                 xy = [x, y];
17316                 this.storeXY(xy);
17317                 supr.setXY.call(this, xy);
17318                 this.sync();
17319             }
17320         }
17321     },
17322
17323     isVisible : function(){
17324         return this.visible;    
17325     },
17326
17327     // private
17328     showAction : function(){
17329         this.visible = true; // track visibility to prevent getStyle calls
17330         if(this.useDisplay === true){
17331             this.setDisplayed("");
17332         }else if(this.lastXY){
17333             supr.setXY.call(this, this.lastXY);
17334         }else if(this.lastLT){
17335             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17336         }
17337     },
17338
17339     // private
17340     hideAction : function(){
17341         this.visible = false;
17342         if(this.useDisplay === true){
17343             this.setDisplayed(false);
17344         }else{
17345             this.setLeftTop(-10000,-10000);
17346         }
17347     },
17348
17349     // overridden Element method
17350     setVisible : function(v, a, d, c, e){
17351         if(v){
17352             this.showAction();
17353         }
17354         if(a && v){
17355             var cb = function(){
17356                 this.sync(true);
17357                 if(c){
17358                     c();
17359                 }
17360             }.createDelegate(this);
17361             supr.setVisible.call(this, true, true, d, cb, e);
17362         }else{
17363             if(!v){
17364                 this.hideUnders(true);
17365             }
17366             var cb = c;
17367             if(a){
17368                 cb = function(){
17369                     this.hideAction();
17370                     if(c){
17371                         c();
17372                     }
17373                 }.createDelegate(this);
17374             }
17375             supr.setVisible.call(this, v, a, d, cb, e);
17376             if(v){
17377                 this.sync(true);
17378             }else if(!a){
17379                 this.hideAction();
17380             }
17381         }
17382     },
17383
17384     storeXY : function(xy){
17385         delete this.lastLT;
17386         this.lastXY = xy;
17387     },
17388
17389     storeLeftTop : function(left, top){
17390         delete this.lastXY;
17391         this.lastLT = [left, top];
17392     },
17393
17394     // private
17395     beforeFx : function(){
17396         this.beforeAction();
17397         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17398     },
17399
17400     // private
17401     afterFx : function(){
17402         Roo.Layer.superclass.afterFx.apply(this, arguments);
17403         this.sync(this.isVisible());
17404     },
17405
17406     // private
17407     beforeAction : function(){
17408         if(!this.updating && this.shadow){
17409             this.shadow.hide();
17410         }
17411     },
17412
17413     // overridden Element method
17414     setLeft : function(left){
17415         this.storeLeftTop(left, this.getTop(true));
17416         supr.setLeft.apply(this, arguments);
17417         this.sync();
17418     },
17419
17420     setTop : function(top){
17421         this.storeLeftTop(this.getLeft(true), top);
17422         supr.setTop.apply(this, arguments);
17423         this.sync();
17424     },
17425
17426     setLeftTop : function(left, top){
17427         this.storeLeftTop(left, top);
17428         supr.setLeftTop.apply(this, arguments);
17429         this.sync();
17430     },
17431
17432     setXY : function(xy, a, d, c, e){
17433         this.fixDisplay();
17434         this.beforeAction();
17435         this.storeXY(xy);
17436         var cb = this.createCB(c);
17437         supr.setXY.call(this, xy, a, d, cb, e);
17438         if(!a){
17439             cb();
17440         }
17441     },
17442
17443     // private
17444     createCB : function(c){
17445         var el = this;
17446         return function(){
17447             el.constrainXY();
17448             el.sync(true);
17449             if(c){
17450                 c();
17451             }
17452         };
17453     },
17454
17455     // overridden Element method
17456     setX : function(x, a, d, c, e){
17457         this.setXY([x, this.getY()], a, d, c, e);
17458     },
17459
17460     // overridden Element method
17461     setY : function(y, a, d, c, e){
17462         this.setXY([this.getX(), y], a, d, c, e);
17463     },
17464
17465     // overridden Element method
17466     setSize : function(w, h, a, d, c, e){
17467         this.beforeAction();
17468         var cb = this.createCB(c);
17469         supr.setSize.call(this, w, h, a, d, cb, e);
17470         if(!a){
17471             cb();
17472         }
17473     },
17474
17475     // overridden Element method
17476     setWidth : function(w, a, d, c, e){
17477         this.beforeAction();
17478         var cb = this.createCB(c);
17479         supr.setWidth.call(this, w, a, d, cb, e);
17480         if(!a){
17481             cb();
17482         }
17483     },
17484
17485     // overridden Element method
17486     setHeight : function(h, a, d, c, e){
17487         this.beforeAction();
17488         var cb = this.createCB(c);
17489         supr.setHeight.call(this, h, a, d, cb, e);
17490         if(!a){
17491             cb();
17492         }
17493     },
17494
17495     // overridden Element method
17496     setBounds : function(x, y, w, h, a, d, c, e){
17497         this.beforeAction();
17498         var cb = this.createCB(c);
17499         if(!a){
17500             this.storeXY([x, y]);
17501             supr.setXY.call(this, [x, y]);
17502             supr.setSize.call(this, w, h, a, d, cb, e);
17503             cb();
17504         }else{
17505             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17506         }
17507         return this;
17508     },
17509     
17510     /**
17511      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17512      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17513      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17514      * @param {Number} zindex The new z-index to set
17515      * @return {this} The Layer
17516      */
17517     setZIndex : function(zindex){
17518         this.zindex = zindex;
17519         this.setStyle("z-index", zindex + 2);
17520         if(this.shadow){
17521             this.shadow.setZIndex(zindex + 1);
17522         }
17523         if(this.shim){
17524             this.shim.setStyle("z-index", zindex);
17525         }
17526     }
17527 });
17528 })();/*
17529  * Original code for Roojs - LGPL
17530  * <script type="text/javascript">
17531  */
17532  
17533 /**
17534  * @class Roo.XComponent
17535  * A delayed Element creator...
17536  * Or a way to group chunks of interface together.
17537  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17538  *  used in conjunction with XComponent.build() it will create an instance of each element,
17539  *  then call addxtype() to build the User interface.
17540  * 
17541  * Mypart.xyx = new Roo.XComponent({
17542
17543     parent : 'Mypart.xyz', // empty == document.element.!!
17544     order : '001',
17545     name : 'xxxx'
17546     region : 'xxxx'
17547     disabled : function() {} 
17548      
17549     tree : function() { // return an tree of xtype declared components
17550         var MODULE = this;
17551         return 
17552         {
17553             xtype : 'NestedLayoutPanel',
17554             // technicall
17555         }
17556      ]
17557  *})
17558  *
17559  *
17560  * It can be used to build a big heiracy, with parent etc.
17561  * or you can just use this to render a single compoent to a dom element
17562  * MYPART.render(Roo.Element | String(id) | dom_element )
17563  *
17564  *
17565  * Usage patterns.
17566  *
17567  * Classic Roo
17568  *
17569  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17570  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17571  *
17572  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17573  *
17574  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17575  * - if mulitple topModules exist, the last one is defined as the top module.
17576  *
17577  * Embeded Roo
17578  * 
17579  * When the top level or multiple modules are to embedded into a existing HTML page,
17580  * the parent element can container '#id' of the element where the module will be drawn.
17581  *
17582  * Bootstrap Roo
17583  *
17584  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17585  * it relies more on a include mechanism, where sub modules are included into an outer page.
17586  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17587  * 
17588  * Bootstrap Roo Included elements
17589  *
17590  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17591  * hence confusing the component builder as it thinks there are multiple top level elements. 
17592  *
17593  * String Over-ride & Translations
17594  *
17595  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17596  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17597  * are needed. @see Roo.XComponent.overlayString  
17598  * 
17599  * 
17600  * 
17601  * @extends Roo.util.Observable
17602  * @constructor
17603  * @param cfg {Object} configuration of component
17604  * 
17605  */
17606 Roo.XComponent = function(cfg) {
17607     Roo.apply(this, cfg);
17608     this.addEvents({ 
17609         /**
17610              * @event built
17611              * Fires when this the componnt is built
17612              * @param {Roo.XComponent} c the component
17613              */
17614         'built' : true
17615         
17616     });
17617     this.region = this.region || 'center'; // default..
17618     Roo.XComponent.register(this);
17619     this.modules = false;
17620     this.el = false; // where the layout goes..
17621     
17622     
17623 }
17624 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17625     /**
17626      * @property el
17627      * The created element (with Roo.factory())
17628      * @type {Roo.Layout}
17629      */
17630     el  : false,
17631     
17632     /**
17633      * @property el
17634      * for BC  - use el in new code
17635      * @type {Roo.Layout}
17636      */
17637     panel : false,
17638     
17639     /**
17640      * @property layout
17641      * for BC  - use el in new code
17642      * @type {Roo.Layout}
17643      */
17644     layout : false,
17645     
17646      /**
17647      * @cfg {Function|boolean} disabled
17648      * If this module is disabled by some rule, return true from the funtion
17649      */
17650     disabled : false,
17651     
17652     /**
17653      * @cfg {String} parent 
17654      * Name of parent element which it get xtype added to..
17655      */
17656     parent: false,
17657     
17658     /**
17659      * @cfg {String} order
17660      * Used to set the order in which elements are created (usefull for multiple tabs)
17661      */
17662     
17663     order : false,
17664     /**
17665      * @cfg {String} name
17666      * String to display while loading.
17667      */
17668     name : false,
17669     /**
17670      * @cfg {String} region
17671      * Region to render component to (defaults to center)
17672      */
17673     region : 'center',
17674     
17675     /**
17676      * @cfg {Array} items
17677      * A single item array - the first element is the root of the tree..
17678      * It's done this way to stay compatible with the Xtype system...
17679      */
17680     items : false,
17681     
17682     /**
17683      * @property _tree
17684      * The method that retuns the tree of parts that make up this compoennt 
17685      * @type {function}
17686      */
17687     _tree  : false,
17688     
17689      /**
17690      * render
17691      * render element to dom or tree
17692      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17693      */
17694     
17695     render : function(el)
17696     {
17697         
17698         el = el || false;
17699         var hp = this.parent ? 1 : 0;
17700         Roo.debug &&  Roo.log(this);
17701         
17702         var tree = this._tree ? this._tree() : this.tree();
17703
17704         
17705         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17706             // if parent is a '#.....' string, then let's use that..
17707             var ename = this.parent.substr(1);
17708             this.parent = false;
17709             Roo.debug && Roo.log(ename);
17710             switch (ename) {
17711                 case 'bootstrap-body':
17712                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
17713                         // this is the BorderLayout standard?
17714                        this.parent = { el : true };
17715                        break;
17716                     }
17717                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
17718                         // need to insert stuff...
17719                         this.parent =  {
17720                              el : new Roo.bootstrap.layout.Border({
17721                                  el : document.body, 
17722                      
17723                                  center: {
17724                                     titlebar: false,
17725                                     autoScroll:false,
17726                                     closeOnTab: true,
17727                                     tabPosition: 'top',
17728                                       //resizeTabs: true,
17729                                     alwaysShowTabs: true,
17730                                     hideTabs: false
17731                                      //minTabWidth: 140
17732                                  }
17733                              })
17734                         
17735                          };
17736                          break;
17737                     }
17738                          
17739                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17740                         this.parent = { el :  new  Roo.bootstrap.Body() };
17741                         Roo.debug && Roo.log("setting el to doc body");
17742                          
17743                     } else {
17744                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17745                     }
17746                     break;
17747                 case 'bootstrap':
17748                     this.parent = { el : true};
17749                     // fall through
17750                 default:
17751                     el = Roo.get(ename);
17752                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17753                         this.parent = { el : true};
17754                     }
17755                     
17756                     break;
17757             }
17758                 
17759             
17760             if (!el && !this.parent) {
17761                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17762                 return;
17763             }
17764         }
17765         
17766         Roo.debug && Roo.log("EL:");
17767         Roo.debug && Roo.log(el);
17768         Roo.debug && Roo.log("this.parent.el:");
17769         Roo.debug && Roo.log(this.parent.el);
17770         
17771
17772         // altertive root elements ??? - we need a better way to indicate these.
17773         var is_alt = Roo.XComponent.is_alt ||
17774                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17775                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17776                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17777         
17778         
17779         
17780         if (!this.parent && is_alt) {
17781             //el = Roo.get(document.body);
17782             this.parent = { el : true };
17783         }
17784             
17785             
17786         
17787         if (!this.parent) {
17788             
17789             Roo.debug && Roo.log("no parent - creating one");
17790             
17791             el = el ? Roo.get(el) : false;      
17792             
17793             if (typeof(Roo.BorderLayout) == 'undefined' ) {
17794                 
17795                 this.parent =  {
17796                     el : new Roo.bootstrap.layout.Border({
17797                         el: el || document.body,
17798                     
17799                         center: {
17800                             titlebar: false,
17801                             autoScroll:false,
17802                             closeOnTab: true,
17803                             tabPosition: 'top',
17804                              //resizeTabs: true,
17805                             alwaysShowTabs: false,
17806                             hideTabs: true,
17807                             minTabWidth: 140,
17808                             overflow: 'visible'
17809                          }
17810                      })
17811                 };
17812             } else {
17813             
17814                 // it's a top level one..
17815                 this.parent =  {
17816                     el : new Roo.BorderLayout(el || document.body, {
17817                         center: {
17818                             titlebar: false,
17819                             autoScroll:false,
17820                             closeOnTab: true,
17821                             tabPosition: 'top',
17822                              //resizeTabs: true,
17823                             alwaysShowTabs: el && hp? false :  true,
17824                             hideTabs: el || !hp ? true :  false,
17825                             minTabWidth: 140
17826                          }
17827                     })
17828                 };
17829             }
17830         }
17831         
17832         if (!this.parent.el) {
17833                 // probably an old style ctor, which has been disabled.
17834                 return;
17835
17836         }
17837                 // The 'tree' method is  '_tree now' 
17838             
17839         tree.region = tree.region || this.region;
17840         var is_body = false;
17841         if (this.parent.el === true) {
17842             // bootstrap... - body..
17843             if (el) {
17844                 tree.el = el;
17845             }
17846             this.parent.el = Roo.factory(tree);
17847             is_body = true;
17848         }
17849         
17850         this.el = this.parent.el.addxtype(tree, undefined, is_body);
17851         this.fireEvent('built', this);
17852         
17853         this.panel = this.el;
17854         this.layout = this.panel.layout;
17855         this.parentLayout = this.parent.layout  || false;  
17856          
17857     }
17858     
17859 });
17860
17861 Roo.apply(Roo.XComponent, {
17862     /**
17863      * @property  hideProgress
17864      * true to disable the building progress bar.. usefull on single page renders.
17865      * @type Boolean
17866      */
17867     hideProgress : false,
17868     /**
17869      * @property  buildCompleted
17870      * True when the builder has completed building the interface.
17871      * @type Boolean
17872      */
17873     buildCompleted : false,
17874      
17875     /**
17876      * @property  topModule
17877      * the upper most module - uses document.element as it's constructor.
17878      * @type Object
17879      */
17880      
17881     topModule  : false,
17882       
17883     /**
17884      * @property  modules
17885      * array of modules to be created by registration system.
17886      * @type {Array} of Roo.XComponent
17887      */
17888     
17889     modules : [],
17890     /**
17891      * @property  elmodules
17892      * array of modules to be created by which use #ID 
17893      * @type {Array} of Roo.XComponent
17894      */
17895      
17896     elmodules : [],
17897
17898      /**
17899      * @property  is_alt
17900      * Is an alternative Root - normally used by bootstrap or other systems,
17901      *    where the top element in the tree can wrap 'body' 
17902      * @type {boolean}  (default false)
17903      */
17904      
17905     is_alt : false,
17906     /**
17907      * @property  build_from_html
17908      * Build elements from html - used by bootstrap HTML stuff 
17909      *    - this is cleared after build is completed
17910      * @type {boolean}    (default false)
17911      */
17912      
17913     build_from_html : false,
17914     /**
17915      * Register components to be built later.
17916      *
17917      * This solves the following issues
17918      * - Building is not done on page load, but after an authentication process has occured.
17919      * - Interface elements are registered on page load
17920      * - Parent Interface elements may not be loaded before child, so this handles that..
17921      * 
17922      *
17923      * example:
17924      * 
17925      * MyApp.register({
17926           order : '000001',
17927           module : 'Pman.Tab.projectMgr',
17928           region : 'center',
17929           parent : 'Pman.layout',
17930           disabled : false,  // or use a function..
17931         })
17932      
17933      * * @param {Object} details about module
17934      */
17935     register : function(obj) {
17936                 
17937         Roo.XComponent.event.fireEvent('register', obj);
17938         switch(typeof(obj.disabled) ) {
17939                 
17940             case 'undefined':
17941                 break;
17942             
17943             case 'function':
17944                 if ( obj.disabled() ) {
17945                         return;
17946                 }
17947                 break;
17948             
17949             default:
17950                 if (obj.disabled || obj.region == '#disabled') {
17951                         return;
17952                 }
17953                 break;
17954         }
17955                 
17956         this.modules.push(obj);
17957          
17958     },
17959     /**
17960      * convert a string to an object..
17961      * eg. 'AAA.BBB' -> finds AAA.BBB
17962
17963      */
17964     
17965     toObject : function(str)
17966     {
17967         if (!str || typeof(str) == 'object') {
17968             return str;
17969         }
17970         if (str.substring(0,1) == '#') {
17971             return str;
17972         }
17973
17974         var ar = str.split('.');
17975         var rt, o;
17976         rt = ar.shift();
17977             /** eval:var:o */
17978         try {
17979             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17980         } catch (e) {
17981             throw "Module not found : " + str;
17982         }
17983         
17984         if (o === false) {
17985             throw "Module not found : " + str;
17986         }
17987         Roo.each(ar, function(e) {
17988             if (typeof(o[e]) == 'undefined') {
17989                 throw "Module not found : " + str;
17990             }
17991             o = o[e];
17992         });
17993         
17994         return o;
17995         
17996     },
17997     
17998     
17999     /**
18000      * move modules into their correct place in the tree..
18001      * 
18002      */
18003     preBuild : function ()
18004     {
18005         var _t = this;
18006         Roo.each(this.modules , function (obj)
18007         {
18008             Roo.XComponent.event.fireEvent('beforebuild', obj);
18009             
18010             var opar = obj.parent;
18011             try { 
18012                 obj.parent = this.toObject(opar);
18013             } catch(e) {
18014                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18015                 return;
18016             }
18017             
18018             if (!obj.parent) {
18019                 Roo.debug && Roo.log("GOT top level module");
18020                 Roo.debug && Roo.log(obj);
18021                 obj.modules = new Roo.util.MixedCollection(false, 
18022                     function(o) { return o.order + '' }
18023                 );
18024                 this.topModule = obj;
18025                 return;
18026             }
18027                         // parent is a string (usually a dom element name..)
18028             if (typeof(obj.parent) == 'string') {
18029                 this.elmodules.push(obj);
18030                 return;
18031             }
18032             if (obj.parent.constructor != Roo.XComponent) {
18033                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18034             }
18035             if (!obj.parent.modules) {
18036                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18037                     function(o) { return o.order + '' }
18038                 );
18039             }
18040             if (obj.parent.disabled) {
18041                 obj.disabled = true;
18042             }
18043             obj.parent.modules.add(obj);
18044         }, this);
18045     },
18046     
18047      /**
18048      * make a list of modules to build.
18049      * @return {Array} list of modules. 
18050      */ 
18051     
18052     buildOrder : function()
18053     {
18054         var _this = this;
18055         var cmp = function(a,b) {   
18056             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18057         };
18058         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18059             throw "No top level modules to build";
18060         }
18061         
18062         // make a flat list in order of modules to build.
18063         var mods = this.topModule ? [ this.topModule ] : [];
18064                 
18065         
18066         // elmodules (is a list of DOM based modules )
18067         Roo.each(this.elmodules, function(e) {
18068             mods.push(e);
18069             if (!this.topModule &&
18070                 typeof(e.parent) == 'string' &&
18071                 e.parent.substring(0,1) == '#' &&
18072                 Roo.get(e.parent.substr(1))
18073                ) {
18074                 
18075                 _this.topModule = e;
18076             }
18077             
18078         });
18079
18080         
18081         // add modules to their parents..
18082         var addMod = function(m) {
18083             Roo.debug && Roo.log("build Order: add: " + m.name);
18084                 
18085             mods.push(m);
18086             if (m.modules && !m.disabled) {
18087                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18088                 m.modules.keySort('ASC',  cmp );
18089                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18090     
18091                 m.modules.each(addMod);
18092             } else {
18093                 Roo.debug && Roo.log("build Order: no child modules");
18094             }
18095             // not sure if this is used any more..
18096             if (m.finalize) {
18097                 m.finalize.name = m.name + " (clean up) ";
18098                 mods.push(m.finalize);
18099             }
18100             
18101         }
18102         if (this.topModule && this.topModule.modules) { 
18103             this.topModule.modules.keySort('ASC',  cmp );
18104             this.topModule.modules.each(addMod);
18105         } 
18106         return mods;
18107     },
18108     
18109      /**
18110      * Build the registered modules.
18111      * @param {Object} parent element.
18112      * @param {Function} optional method to call after module has been added.
18113      * 
18114      */ 
18115    
18116     build : function(opts) 
18117     {
18118         
18119         if (typeof(opts) != 'undefined') {
18120             Roo.apply(this,opts);
18121         }
18122         
18123         this.preBuild();
18124         var mods = this.buildOrder();
18125       
18126         //this.allmods = mods;
18127         //Roo.debug && Roo.log(mods);
18128         //return;
18129         if (!mods.length) { // should not happen
18130             throw "NO modules!!!";
18131         }
18132         
18133         
18134         var msg = "Building Interface...";
18135         // flash it up as modal - so we store the mask!?
18136         if (!this.hideProgress && Roo.MessageBox) {
18137             Roo.MessageBox.show({ title: 'loading' });
18138             Roo.MessageBox.show({
18139                title: "Please wait...",
18140                msg: msg,
18141                width:450,
18142                progress:true,
18143                buttons : false,
18144                closable:false,
18145                modal: false
18146               
18147             });
18148         }
18149         var total = mods.length;
18150         
18151         var _this = this;
18152         var progressRun = function() {
18153             if (!mods.length) {
18154                 Roo.debug && Roo.log('hide?');
18155                 if (!this.hideProgress && Roo.MessageBox) {
18156                     Roo.MessageBox.hide();
18157                 }
18158                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18159                 
18160                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18161                 
18162                 // THE END...
18163                 return false;   
18164             }
18165             
18166             var m = mods.shift();
18167             
18168             
18169             Roo.debug && Roo.log(m);
18170             // not sure if this is supported any more.. - modules that are are just function
18171             if (typeof(m) == 'function') { 
18172                 m.call(this);
18173                 return progressRun.defer(10, _this);
18174             } 
18175             
18176             
18177             msg = "Building Interface " + (total  - mods.length) + 
18178                     " of " + total + 
18179                     (m.name ? (' - ' + m.name) : '');
18180                         Roo.debug && Roo.log(msg);
18181             if (!_this.hideProgress &&  Roo.MessageBox) { 
18182                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18183             }
18184             
18185          
18186             // is the module disabled?
18187             var disabled = (typeof(m.disabled) == 'function') ?
18188                 m.disabled.call(m.module.disabled) : m.disabled;    
18189             
18190             
18191             if (disabled) {
18192                 return progressRun(); // we do not update the display!
18193             }
18194             
18195             // now build 
18196             
18197                         
18198                         
18199             m.render();
18200             // it's 10 on top level, and 1 on others??? why...
18201             return progressRun.defer(10, _this);
18202              
18203         }
18204         progressRun.defer(1, _this);
18205      
18206         
18207         
18208     },
18209     /**
18210      * Overlay a set of modified strings onto a component
18211      * This is dependant on our builder exporting the strings and 'named strings' elements.
18212      * 
18213      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18214      * @param {Object} associative array of 'named' string and it's new value.
18215      * 
18216      */
18217         overlayStrings : function( component, strings )
18218     {
18219         if (typeof(component['_named_strings']) == 'undefined') {
18220             throw "ERROR: component does not have _named_strings";
18221         }
18222         for ( var k in strings ) {
18223             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18224             if (md !== false) {
18225                 component['_strings'][md] = strings[k];
18226             } else {
18227                 Roo.log('could not find named string: ' + k + ' in');
18228                 Roo.log(component);
18229             }
18230             
18231         }
18232         
18233     },
18234     
18235         
18236         /**
18237          * Event Object.
18238          *
18239          *
18240          */
18241         event: false, 
18242     /**
18243          * wrapper for event.on - aliased later..  
18244          * Typically use to register a event handler for register:
18245          *
18246          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18247          *
18248          */
18249     on : false
18250    
18251     
18252     
18253 });
18254
18255 Roo.XComponent.event = new Roo.util.Observable({
18256                 events : { 
18257                         /**
18258                          * @event register
18259                          * Fires when an Component is registered,
18260                          * set the disable property on the Component to stop registration.
18261                          * @param {Roo.XComponent} c the component being registerd.
18262                          * 
18263                          */
18264                         'register' : true,
18265             /**
18266                          * @event beforebuild
18267                          * Fires before each Component is built
18268                          * can be used to apply permissions.
18269                          * @param {Roo.XComponent} c the component being registerd.
18270                          * 
18271                          */
18272                         'beforebuild' : true,
18273                         /**
18274                          * @event buildcomplete
18275                          * Fires on the top level element when all elements have been built
18276                          * @param {Roo.XComponent} the top level component.
18277                          */
18278                         'buildcomplete' : true
18279                         
18280                 }
18281 });
18282
18283 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18284  //
18285  /**
18286  * marked - a markdown parser
18287  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18288  * https://github.com/chjj/marked
18289  */
18290
18291
18292 /**
18293  *
18294  * Roo.Markdown - is a very crude wrapper around marked..
18295  *
18296  * usage:
18297  * 
18298  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18299  * 
18300  * Note: move the sample code to the bottom of this
18301  * file before uncommenting it.
18302  *
18303  */
18304
18305 Roo.Markdown = {};
18306 Roo.Markdown.toHtml = function(text) {
18307     
18308     var c = new Roo.Markdown.marked.setOptions({
18309             renderer: new Roo.Markdown.marked.Renderer(),
18310             gfm: true,
18311             tables: true,
18312             breaks: false,
18313             pedantic: false,
18314             sanitize: false,
18315             smartLists: true,
18316             smartypants: false
18317           });
18318     // A FEW HACKS!!?
18319     
18320     text = text.replace(/\\\n/g,' ');
18321     return Roo.Markdown.marked(text);
18322 };
18323 //
18324 // converter
18325 //
18326 // Wraps all "globals" so that the only thing
18327 // exposed is makeHtml().
18328 //
18329 (function() {
18330     
18331      /**
18332          * eval:var:escape
18333          * eval:var:unescape
18334          * eval:var:replace
18335          */
18336       
18337     /**
18338      * Helpers
18339      */
18340     
18341     var escape = function (html, encode) {
18342       return html
18343         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18344         .replace(/</g, '&lt;')
18345         .replace(/>/g, '&gt;')
18346         .replace(/"/g, '&quot;')
18347         .replace(/'/g, '&#39;');
18348     }
18349     
18350     var unescape = function (html) {
18351         // explicitly match decimal, hex, and named HTML entities 
18352       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18353         n = n.toLowerCase();
18354         if (n === 'colon') { return ':'; }
18355         if (n.charAt(0) === '#') {
18356           return n.charAt(1) === 'x'
18357             ? String.fromCharCode(parseInt(n.substring(2), 16))
18358             : String.fromCharCode(+n.substring(1));
18359         }
18360         return '';
18361       });
18362     }
18363     
18364     var replace = function (regex, opt) {
18365       regex = regex.source;
18366       opt = opt || '';
18367       return function self(name, val) {
18368         if (!name) { return new RegExp(regex, opt); }
18369         val = val.source || val;
18370         val = val.replace(/(^|[^\[])\^/g, '$1');
18371         regex = regex.replace(name, val);
18372         return self;
18373       };
18374     }
18375
18376
18377          /**
18378          * eval:var:noop
18379     */
18380     var noop = function () {}
18381     noop.exec = noop;
18382     
18383          /**
18384          * eval:var:merge
18385     */
18386     var merge = function (obj) {
18387       var i = 1
18388         , target
18389         , key;
18390     
18391       for (; i < arguments.length; i++) {
18392         target = arguments[i];
18393         for (key in target) {
18394           if (Object.prototype.hasOwnProperty.call(target, key)) {
18395             obj[key] = target[key];
18396           }
18397         }
18398       }
18399     
18400       return obj;
18401     }
18402     
18403     
18404     /**
18405      * Block-Level Grammar
18406      */
18407     
18408     
18409     
18410     
18411     var block = {
18412       newline: /^\n+/,
18413       code: /^( {4}[^\n]+\n*)+/,
18414       fences: noop,
18415       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18416       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18417       nptable: noop,
18418       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18419       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18420       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18421       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18422       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18423       table: noop,
18424       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18425       text: /^[^\n]+/
18426     };
18427     
18428     block.bullet = /(?:[*+-]|\d+\.)/;
18429     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18430     block.item = replace(block.item, 'gm')
18431       (/bull/g, block.bullet)
18432       ();
18433     
18434     block.list = replace(block.list)
18435       (/bull/g, block.bullet)
18436       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18437       ('def', '\\n+(?=' + block.def.source + ')')
18438       ();
18439     
18440     block.blockquote = replace(block.blockquote)
18441       ('def', block.def)
18442       ();
18443     
18444     block._tag = '(?!(?:'
18445       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18446       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18447       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18448     
18449     block.html = replace(block.html)
18450       ('comment', /<!--[\s\S]*?-->/)
18451       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18452       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18453       (/tag/g, block._tag)
18454       ();
18455     
18456     block.paragraph = replace(block.paragraph)
18457       ('hr', block.hr)
18458       ('heading', block.heading)
18459       ('lheading', block.lheading)
18460       ('blockquote', block.blockquote)
18461       ('tag', '<' + block._tag)
18462       ('def', block.def)
18463       ();
18464     
18465     /**
18466      * Normal Block Grammar
18467      */
18468     
18469     block.normal = merge({}, block);
18470     
18471     /**
18472      * GFM Block Grammar
18473      */
18474     
18475     block.gfm = merge({}, block.normal, {
18476       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18477       paragraph: /^/,
18478       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18479     });
18480     
18481     block.gfm.paragraph = replace(block.paragraph)
18482       ('(?!', '(?!'
18483         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18484         + block.list.source.replace('\\1', '\\3') + '|')
18485       ();
18486     
18487     /**
18488      * GFM + Tables Block Grammar
18489      */
18490     
18491     block.tables = merge({}, block.gfm, {
18492       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18493       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18494     });
18495     
18496     /**
18497      * Block Lexer
18498      */
18499     
18500     var Lexer = function (options) {
18501       this.tokens = [];
18502       this.tokens.links = {};
18503       this.options = options || marked.defaults;
18504       this.rules = block.normal;
18505     
18506       if (this.options.gfm) {
18507         if (this.options.tables) {
18508           this.rules = block.tables;
18509         } else {
18510           this.rules = block.gfm;
18511         }
18512       }
18513     }
18514     
18515     /**
18516      * Expose Block Rules
18517      */
18518     
18519     Lexer.rules = block;
18520     
18521     /**
18522      * Static Lex Method
18523      */
18524     
18525     Lexer.lex = function(src, options) {
18526       var lexer = new Lexer(options);
18527       return lexer.lex(src);
18528     };
18529     
18530     /**
18531      * Preprocessing
18532      */
18533     
18534     Lexer.prototype.lex = function(src) {
18535       src = src
18536         .replace(/\r\n|\r/g, '\n')
18537         .replace(/\t/g, '    ')
18538         .replace(/\u00a0/g, ' ')
18539         .replace(/\u2424/g, '\n');
18540     
18541       return this.token(src, true);
18542     };
18543     
18544     /**
18545      * Lexing
18546      */
18547     
18548     Lexer.prototype.token = function(src, top, bq) {
18549       var src = src.replace(/^ +$/gm, '')
18550         , next
18551         , loose
18552         , cap
18553         , bull
18554         , b
18555         , item
18556         , space
18557         , i
18558         , l;
18559     
18560       while (src) {
18561         // newline
18562         if (cap = this.rules.newline.exec(src)) {
18563           src = src.substring(cap[0].length);
18564           if (cap[0].length > 1) {
18565             this.tokens.push({
18566               type: 'space'
18567             });
18568           }
18569         }
18570     
18571         // code
18572         if (cap = this.rules.code.exec(src)) {
18573           src = src.substring(cap[0].length);
18574           cap = cap[0].replace(/^ {4}/gm, '');
18575           this.tokens.push({
18576             type: 'code',
18577             text: !this.options.pedantic
18578               ? cap.replace(/\n+$/, '')
18579               : cap
18580           });
18581           continue;
18582         }
18583     
18584         // fences (gfm)
18585         if (cap = this.rules.fences.exec(src)) {
18586           src = src.substring(cap[0].length);
18587           this.tokens.push({
18588             type: 'code',
18589             lang: cap[2],
18590             text: cap[3] || ''
18591           });
18592           continue;
18593         }
18594     
18595         // heading
18596         if (cap = this.rules.heading.exec(src)) {
18597           src = src.substring(cap[0].length);
18598           this.tokens.push({
18599             type: 'heading',
18600             depth: cap[1].length,
18601             text: cap[2]
18602           });
18603           continue;
18604         }
18605     
18606         // table no leading pipe (gfm)
18607         if (top && (cap = this.rules.nptable.exec(src))) {
18608           src = src.substring(cap[0].length);
18609     
18610           item = {
18611             type: 'table',
18612             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18613             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18614             cells: cap[3].replace(/\n$/, '').split('\n')
18615           };
18616     
18617           for (i = 0; i < item.align.length; i++) {
18618             if (/^ *-+: *$/.test(item.align[i])) {
18619               item.align[i] = 'right';
18620             } else if (/^ *:-+: *$/.test(item.align[i])) {
18621               item.align[i] = 'center';
18622             } else if (/^ *:-+ *$/.test(item.align[i])) {
18623               item.align[i] = 'left';
18624             } else {
18625               item.align[i] = null;
18626             }
18627           }
18628     
18629           for (i = 0; i < item.cells.length; i++) {
18630             item.cells[i] = item.cells[i].split(/ *\| */);
18631           }
18632     
18633           this.tokens.push(item);
18634     
18635           continue;
18636         }
18637     
18638         // lheading
18639         if (cap = this.rules.lheading.exec(src)) {
18640           src = src.substring(cap[0].length);
18641           this.tokens.push({
18642             type: 'heading',
18643             depth: cap[2] === '=' ? 1 : 2,
18644             text: cap[1]
18645           });
18646           continue;
18647         }
18648     
18649         // hr
18650         if (cap = this.rules.hr.exec(src)) {
18651           src = src.substring(cap[0].length);
18652           this.tokens.push({
18653             type: 'hr'
18654           });
18655           continue;
18656         }
18657     
18658         // blockquote
18659         if (cap = this.rules.blockquote.exec(src)) {
18660           src = src.substring(cap[0].length);
18661     
18662           this.tokens.push({
18663             type: 'blockquote_start'
18664           });
18665     
18666           cap = cap[0].replace(/^ *> ?/gm, '');
18667     
18668           // Pass `top` to keep the current
18669           // "toplevel" state. This is exactly
18670           // how markdown.pl works.
18671           this.token(cap, top, true);
18672     
18673           this.tokens.push({
18674             type: 'blockquote_end'
18675           });
18676     
18677           continue;
18678         }
18679     
18680         // list
18681         if (cap = this.rules.list.exec(src)) {
18682           src = src.substring(cap[0].length);
18683           bull = cap[2];
18684     
18685           this.tokens.push({
18686             type: 'list_start',
18687             ordered: bull.length > 1
18688           });
18689     
18690           // Get each top-level item.
18691           cap = cap[0].match(this.rules.item);
18692     
18693           next = false;
18694           l = cap.length;
18695           i = 0;
18696     
18697           for (; i < l; i++) {
18698             item = cap[i];
18699     
18700             // Remove the list item's bullet
18701             // so it is seen as the next token.
18702             space = item.length;
18703             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18704     
18705             // Outdent whatever the
18706             // list item contains. Hacky.
18707             if (~item.indexOf('\n ')) {
18708               space -= item.length;
18709               item = !this.options.pedantic
18710                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18711                 : item.replace(/^ {1,4}/gm, '');
18712             }
18713     
18714             // Determine whether the next list item belongs here.
18715             // Backpedal if it does not belong in this list.
18716             if (this.options.smartLists && i !== l - 1) {
18717               b = block.bullet.exec(cap[i + 1])[0];
18718               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18719                 src = cap.slice(i + 1).join('\n') + src;
18720                 i = l - 1;
18721               }
18722             }
18723     
18724             // Determine whether item is loose or not.
18725             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18726             // for discount behavior.
18727             loose = next || /\n\n(?!\s*$)/.test(item);
18728             if (i !== l - 1) {
18729               next = item.charAt(item.length - 1) === '\n';
18730               if (!loose) { loose = next; }
18731             }
18732     
18733             this.tokens.push({
18734               type: loose
18735                 ? 'loose_item_start'
18736                 : 'list_item_start'
18737             });
18738     
18739             // Recurse.
18740             this.token(item, false, bq);
18741     
18742             this.tokens.push({
18743               type: 'list_item_end'
18744             });
18745           }
18746     
18747           this.tokens.push({
18748             type: 'list_end'
18749           });
18750     
18751           continue;
18752         }
18753     
18754         // html
18755         if (cap = this.rules.html.exec(src)) {
18756           src = src.substring(cap[0].length);
18757           this.tokens.push({
18758             type: this.options.sanitize
18759               ? 'paragraph'
18760               : 'html',
18761             pre: !this.options.sanitizer
18762               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18763             text: cap[0]
18764           });
18765           continue;
18766         }
18767     
18768         // def
18769         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18770           src = src.substring(cap[0].length);
18771           this.tokens.links[cap[1].toLowerCase()] = {
18772             href: cap[2],
18773             title: cap[3]
18774           };
18775           continue;
18776         }
18777     
18778         // table (gfm)
18779         if (top && (cap = this.rules.table.exec(src))) {
18780           src = src.substring(cap[0].length);
18781     
18782           item = {
18783             type: 'table',
18784             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18785             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18786             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18787           };
18788     
18789           for (i = 0; i < item.align.length; i++) {
18790             if (/^ *-+: *$/.test(item.align[i])) {
18791               item.align[i] = 'right';
18792             } else if (/^ *:-+: *$/.test(item.align[i])) {
18793               item.align[i] = 'center';
18794             } else if (/^ *:-+ *$/.test(item.align[i])) {
18795               item.align[i] = 'left';
18796             } else {
18797               item.align[i] = null;
18798             }
18799           }
18800     
18801           for (i = 0; i < item.cells.length; i++) {
18802             item.cells[i] = item.cells[i]
18803               .replace(/^ *\| *| *\| *$/g, '')
18804               .split(/ *\| */);
18805           }
18806     
18807           this.tokens.push(item);
18808     
18809           continue;
18810         }
18811     
18812         // top-level paragraph
18813         if (top && (cap = this.rules.paragraph.exec(src))) {
18814           src = src.substring(cap[0].length);
18815           this.tokens.push({
18816             type: 'paragraph',
18817             text: cap[1].charAt(cap[1].length - 1) === '\n'
18818               ? cap[1].slice(0, -1)
18819               : cap[1]
18820           });
18821           continue;
18822         }
18823     
18824         // text
18825         if (cap = this.rules.text.exec(src)) {
18826           // Top-level should never reach here.
18827           src = src.substring(cap[0].length);
18828           this.tokens.push({
18829             type: 'text',
18830             text: cap[0]
18831           });
18832           continue;
18833         }
18834     
18835         if (src) {
18836           throw new
18837             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18838         }
18839       }
18840     
18841       return this.tokens;
18842     };
18843     
18844     /**
18845      * Inline-Level Grammar
18846      */
18847     
18848     var inline = {
18849       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18850       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18851       url: noop,
18852       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18853       link: /^!?\[(inside)\]\(href\)/,
18854       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18855       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18856       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18857       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18858       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18859       br: /^ {2,}\n(?!\s*$)/,
18860       del: noop,
18861       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18862     };
18863     
18864     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18865     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18866     
18867     inline.link = replace(inline.link)
18868       ('inside', inline._inside)
18869       ('href', inline._href)
18870       ();
18871     
18872     inline.reflink = replace(inline.reflink)
18873       ('inside', inline._inside)
18874       ();
18875     
18876     /**
18877      * Normal Inline Grammar
18878      */
18879     
18880     inline.normal = merge({}, inline);
18881     
18882     /**
18883      * Pedantic Inline Grammar
18884      */
18885     
18886     inline.pedantic = merge({}, inline.normal, {
18887       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18888       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18889     });
18890     
18891     /**
18892      * GFM Inline Grammar
18893      */
18894     
18895     inline.gfm = merge({}, inline.normal, {
18896       escape: replace(inline.escape)('])', '~|])')(),
18897       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18898       del: /^~~(?=\S)([\s\S]*?\S)~~/,
18899       text: replace(inline.text)
18900         (']|', '~]|')
18901         ('|', '|https?://|')
18902         ()
18903     });
18904     
18905     /**
18906      * GFM + Line Breaks Inline Grammar
18907      */
18908     
18909     inline.breaks = merge({}, inline.gfm, {
18910       br: replace(inline.br)('{2,}', '*')(),
18911       text: replace(inline.gfm.text)('{2,}', '*')()
18912     });
18913     
18914     /**
18915      * Inline Lexer & Compiler
18916      */
18917     
18918     var InlineLexer  = function (links, options) {
18919       this.options = options || marked.defaults;
18920       this.links = links;
18921       this.rules = inline.normal;
18922       this.renderer = this.options.renderer || new Renderer;
18923       this.renderer.options = this.options;
18924     
18925       if (!this.links) {
18926         throw new
18927           Error('Tokens array requires a `links` property.');
18928       }
18929     
18930       if (this.options.gfm) {
18931         if (this.options.breaks) {
18932           this.rules = inline.breaks;
18933         } else {
18934           this.rules = inline.gfm;
18935         }
18936       } else if (this.options.pedantic) {
18937         this.rules = inline.pedantic;
18938       }
18939     }
18940     
18941     /**
18942      * Expose Inline Rules
18943      */
18944     
18945     InlineLexer.rules = inline;
18946     
18947     /**
18948      * Static Lexing/Compiling Method
18949      */
18950     
18951     InlineLexer.output = function(src, links, options) {
18952       var inline = new InlineLexer(links, options);
18953       return inline.output(src);
18954     };
18955     
18956     /**
18957      * Lexing/Compiling
18958      */
18959     
18960     InlineLexer.prototype.output = function(src) {
18961       var out = ''
18962         , link
18963         , text
18964         , href
18965         , cap;
18966     
18967       while (src) {
18968         // escape
18969         if (cap = this.rules.escape.exec(src)) {
18970           src = src.substring(cap[0].length);
18971           out += cap[1];
18972           continue;
18973         }
18974     
18975         // autolink
18976         if (cap = this.rules.autolink.exec(src)) {
18977           src = src.substring(cap[0].length);
18978           if (cap[2] === '@') {
18979             text = cap[1].charAt(6) === ':'
18980               ? this.mangle(cap[1].substring(7))
18981               : this.mangle(cap[1]);
18982             href = this.mangle('mailto:') + text;
18983           } else {
18984             text = escape(cap[1]);
18985             href = text;
18986           }
18987           out += this.renderer.link(href, null, text);
18988           continue;
18989         }
18990     
18991         // url (gfm)
18992         if (!this.inLink && (cap = this.rules.url.exec(src))) {
18993           src = src.substring(cap[0].length);
18994           text = escape(cap[1]);
18995           href = text;
18996           out += this.renderer.link(href, null, text);
18997           continue;
18998         }
18999     
19000         // tag
19001         if (cap = this.rules.tag.exec(src)) {
19002           if (!this.inLink && /^<a /i.test(cap[0])) {
19003             this.inLink = true;
19004           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19005             this.inLink = false;
19006           }
19007           src = src.substring(cap[0].length);
19008           out += this.options.sanitize
19009             ? this.options.sanitizer
19010               ? this.options.sanitizer(cap[0])
19011               : escape(cap[0])
19012             : cap[0];
19013           continue;
19014         }
19015     
19016         // link
19017         if (cap = this.rules.link.exec(src)) {
19018           src = src.substring(cap[0].length);
19019           this.inLink = true;
19020           out += this.outputLink(cap, {
19021             href: cap[2],
19022             title: cap[3]
19023           });
19024           this.inLink = false;
19025           continue;
19026         }
19027     
19028         // reflink, nolink
19029         if ((cap = this.rules.reflink.exec(src))
19030             || (cap = this.rules.nolink.exec(src))) {
19031           src = src.substring(cap[0].length);
19032           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19033           link = this.links[link.toLowerCase()];
19034           if (!link || !link.href) {
19035             out += cap[0].charAt(0);
19036             src = cap[0].substring(1) + src;
19037             continue;
19038           }
19039           this.inLink = true;
19040           out += this.outputLink(cap, link);
19041           this.inLink = false;
19042           continue;
19043         }
19044     
19045         // strong
19046         if (cap = this.rules.strong.exec(src)) {
19047           src = src.substring(cap[0].length);
19048           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19049           continue;
19050         }
19051     
19052         // em
19053         if (cap = this.rules.em.exec(src)) {
19054           src = src.substring(cap[0].length);
19055           out += this.renderer.em(this.output(cap[2] || cap[1]));
19056           continue;
19057         }
19058     
19059         // code
19060         if (cap = this.rules.code.exec(src)) {
19061           src = src.substring(cap[0].length);
19062           out += this.renderer.codespan(escape(cap[2], true));
19063           continue;
19064         }
19065     
19066         // br
19067         if (cap = this.rules.br.exec(src)) {
19068           src = src.substring(cap[0].length);
19069           out += this.renderer.br();
19070           continue;
19071         }
19072     
19073         // del (gfm)
19074         if (cap = this.rules.del.exec(src)) {
19075           src = src.substring(cap[0].length);
19076           out += this.renderer.del(this.output(cap[1]));
19077           continue;
19078         }
19079     
19080         // text
19081         if (cap = this.rules.text.exec(src)) {
19082           src = src.substring(cap[0].length);
19083           out += this.renderer.text(escape(this.smartypants(cap[0])));
19084           continue;
19085         }
19086     
19087         if (src) {
19088           throw new
19089             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19090         }
19091       }
19092     
19093       return out;
19094     };
19095     
19096     /**
19097      * Compile Link
19098      */
19099     
19100     InlineLexer.prototype.outputLink = function(cap, link) {
19101       var href = escape(link.href)
19102         , title = link.title ? escape(link.title) : null;
19103     
19104       return cap[0].charAt(0) !== '!'
19105         ? this.renderer.link(href, title, this.output(cap[1]))
19106         : this.renderer.image(href, title, escape(cap[1]));
19107     };
19108     
19109     /**
19110      * Smartypants Transformations
19111      */
19112     
19113     InlineLexer.prototype.smartypants = function(text) {
19114       if (!this.options.smartypants)  { return text; }
19115       return text
19116         // em-dashes
19117         .replace(/---/g, '\u2014')
19118         // en-dashes
19119         .replace(/--/g, '\u2013')
19120         // opening singles
19121         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19122         // closing singles & apostrophes
19123         .replace(/'/g, '\u2019')
19124         // opening doubles
19125         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19126         // closing doubles
19127         .replace(/"/g, '\u201d')
19128         // ellipses
19129         .replace(/\.{3}/g, '\u2026');
19130     };
19131     
19132     /**
19133      * Mangle Links
19134      */
19135     
19136     InlineLexer.prototype.mangle = function(text) {
19137       if (!this.options.mangle) { return text; }
19138       var out = ''
19139         , l = text.length
19140         , i = 0
19141         , ch;
19142     
19143       for (; i < l; i++) {
19144         ch = text.charCodeAt(i);
19145         if (Math.random() > 0.5) {
19146           ch = 'x' + ch.toString(16);
19147         }
19148         out += '&#' + ch + ';';
19149       }
19150     
19151       return out;
19152     };
19153     
19154     /**
19155      * Renderer
19156      */
19157     
19158      /**
19159          * eval:var:Renderer
19160     */
19161     
19162     var Renderer   = function (options) {
19163       this.options = options || {};
19164     }
19165     
19166     Renderer.prototype.code = function(code, lang, escaped) {
19167       if (this.options.highlight) {
19168         var out = this.options.highlight(code, lang);
19169         if (out != null && out !== code) {
19170           escaped = true;
19171           code = out;
19172         }
19173       } else {
19174             // hack!!! - it's already escapeD?
19175             escaped = true;
19176       }
19177     
19178       if (!lang) {
19179         return '<pre><code>'
19180           + (escaped ? code : escape(code, true))
19181           + '\n</code></pre>';
19182       }
19183     
19184       return '<pre><code class="'
19185         + this.options.langPrefix
19186         + escape(lang, true)
19187         + '">'
19188         + (escaped ? code : escape(code, true))
19189         + '\n</code></pre>\n';
19190     };
19191     
19192     Renderer.prototype.blockquote = function(quote) {
19193       return '<blockquote>\n' + quote + '</blockquote>\n';
19194     };
19195     
19196     Renderer.prototype.html = function(html) {
19197       return html;
19198     };
19199     
19200     Renderer.prototype.heading = function(text, level, raw) {
19201       return '<h'
19202         + level
19203         + ' id="'
19204         + this.options.headerPrefix
19205         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19206         + '">'
19207         + text
19208         + '</h'
19209         + level
19210         + '>\n';
19211     };
19212     
19213     Renderer.prototype.hr = function() {
19214       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19215     };
19216     
19217     Renderer.prototype.list = function(body, ordered) {
19218       var type = ordered ? 'ol' : 'ul';
19219       return '<' + type + '>\n' + body + '</' + type + '>\n';
19220     };
19221     
19222     Renderer.prototype.listitem = function(text) {
19223       return '<li>' + text + '</li>\n';
19224     };
19225     
19226     Renderer.prototype.paragraph = function(text) {
19227       return '<p>' + text + '</p>\n';
19228     };
19229     
19230     Renderer.prototype.table = function(header, body) {
19231       return '<table class="table table-striped">\n'
19232         + '<thead>\n'
19233         + header
19234         + '</thead>\n'
19235         + '<tbody>\n'
19236         + body
19237         + '</tbody>\n'
19238         + '</table>\n';
19239     };
19240     
19241     Renderer.prototype.tablerow = function(content) {
19242       return '<tr>\n' + content + '</tr>\n';
19243     };
19244     
19245     Renderer.prototype.tablecell = function(content, flags) {
19246       var type = flags.header ? 'th' : 'td';
19247       var tag = flags.align
19248         ? '<' + type + ' style="text-align:' + flags.align + '">'
19249         : '<' + type + '>';
19250       return tag + content + '</' + type + '>\n';
19251     };
19252     
19253     // span level renderer
19254     Renderer.prototype.strong = function(text) {
19255       return '<strong>' + text + '</strong>';
19256     };
19257     
19258     Renderer.prototype.em = function(text) {
19259       return '<em>' + text + '</em>';
19260     };
19261     
19262     Renderer.prototype.codespan = function(text) {
19263       return '<code>' + text + '</code>';
19264     };
19265     
19266     Renderer.prototype.br = function() {
19267       return this.options.xhtml ? '<br/>' : '<br>';
19268     };
19269     
19270     Renderer.prototype.del = function(text) {
19271       return '<del>' + text + '</del>';
19272     };
19273     
19274     Renderer.prototype.link = function(href, title, text) {
19275       if (this.options.sanitize) {
19276         try {
19277           var prot = decodeURIComponent(unescape(href))
19278             .replace(/[^\w:]/g, '')
19279             .toLowerCase();
19280         } catch (e) {
19281           return '';
19282         }
19283         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19284           return '';
19285         }
19286       }
19287       var out = '<a href="' + href + '"';
19288       if (title) {
19289         out += ' title="' + title + '"';
19290       }
19291       out += '>' + text + '</a>';
19292       return out;
19293     };
19294     
19295     Renderer.prototype.image = function(href, title, text) {
19296       var out = '<img src="' + href + '" alt="' + text + '"';
19297       if (title) {
19298         out += ' title="' + title + '"';
19299       }
19300       out += this.options.xhtml ? '/>' : '>';
19301       return out;
19302     };
19303     
19304     Renderer.prototype.text = function(text) {
19305       return text;
19306     };
19307     
19308     /**
19309      * Parsing & Compiling
19310      */
19311          /**
19312          * eval:var:Parser
19313     */
19314     
19315     var Parser= function (options) {
19316       this.tokens = [];
19317       this.token = null;
19318       this.options = options || marked.defaults;
19319       this.options.renderer = this.options.renderer || new Renderer;
19320       this.renderer = this.options.renderer;
19321       this.renderer.options = this.options;
19322     }
19323     
19324     /**
19325      * Static Parse Method
19326      */
19327     
19328     Parser.parse = function(src, options, renderer) {
19329       var parser = new Parser(options, renderer);
19330       return parser.parse(src);
19331     };
19332     
19333     /**
19334      * Parse Loop
19335      */
19336     
19337     Parser.prototype.parse = function(src) {
19338       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19339       this.tokens = src.reverse();
19340     
19341       var out = '';
19342       while (this.next()) {
19343         out += this.tok();
19344       }
19345     
19346       return out;
19347     };
19348     
19349     /**
19350      * Next Token
19351      */
19352     
19353     Parser.prototype.next = function() {
19354       return this.token = this.tokens.pop();
19355     };
19356     
19357     /**
19358      * Preview Next Token
19359      */
19360     
19361     Parser.prototype.peek = function() {
19362       return this.tokens[this.tokens.length - 1] || 0;
19363     };
19364     
19365     /**
19366      * Parse Text Tokens
19367      */
19368     
19369     Parser.prototype.parseText = function() {
19370       var body = this.token.text;
19371     
19372       while (this.peek().type === 'text') {
19373         body += '\n' + this.next().text;
19374       }
19375     
19376       return this.inline.output(body);
19377     };
19378     
19379     /**
19380      * Parse Current Token
19381      */
19382     
19383     Parser.prototype.tok = function() {
19384       switch (this.token.type) {
19385         case 'space': {
19386           return '';
19387         }
19388         case 'hr': {
19389           return this.renderer.hr();
19390         }
19391         case 'heading': {
19392           return this.renderer.heading(
19393             this.inline.output(this.token.text),
19394             this.token.depth,
19395             this.token.text);
19396         }
19397         case 'code': {
19398           return this.renderer.code(this.token.text,
19399             this.token.lang,
19400             this.token.escaped);
19401         }
19402         case 'table': {
19403           var header = ''
19404             , body = ''
19405             , i
19406             , row
19407             , cell
19408             , flags
19409             , j;
19410     
19411           // header
19412           cell = '';
19413           for (i = 0; i < this.token.header.length; i++) {
19414             flags = { header: true, align: this.token.align[i] };
19415             cell += this.renderer.tablecell(
19416               this.inline.output(this.token.header[i]),
19417               { header: true, align: this.token.align[i] }
19418             );
19419           }
19420           header += this.renderer.tablerow(cell);
19421     
19422           for (i = 0; i < this.token.cells.length; i++) {
19423             row = this.token.cells[i];
19424     
19425             cell = '';
19426             for (j = 0; j < row.length; j++) {
19427               cell += this.renderer.tablecell(
19428                 this.inline.output(row[j]),
19429                 { header: false, align: this.token.align[j] }
19430               );
19431             }
19432     
19433             body += this.renderer.tablerow(cell);
19434           }
19435           return this.renderer.table(header, body);
19436         }
19437         case 'blockquote_start': {
19438           var body = '';
19439     
19440           while (this.next().type !== 'blockquote_end') {
19441             body += this.tok();
19442           }
19443     
19444           return this.renderer.blockquote(body);
19445         }
19446         case 'list_start': {
19447           var body = ''
19448             , ordered = this.token.ordered;
19449     
19450           while (this.next().type !== 'list_end') {
19451             body += this.tok();
19452           }
19453     
19454           return this.renderer.list(body, ordered);
19455         }
19456         case 'list_item_start': {
19457           var body = '';
19458     
19459           while (this.next().type !== 'list_item_end') {
19460             body += this.token.type === 'text'
19461               ? this.parseText()
19462               : this.tok();
19463           }
19464     
19465           return this.renderer.listitem(body);
19466         }
19467         case 'loose_item_start': {
19468           var body = '';
19469     
19470           while (this.next().type !== 'list_item_end') {
19471             body += this.tok();
19472           }
19473     
19474           return this.renderer.listitem(body);
19475         }
19476         case 'html': {
19477           var html = !this.token.pre && !this.options.pedantic
19478             ? this.inline.output(this.token.text)
19479             : this.token.text;
19480           return this.renderer.html(html);
19481         }
19482         case 'paragraph': {
19483           return this.renderer.paragraph(this.inline.output(this.token.text));
19484         }
19485         case 'text': {
19486           return this.renderer.paragraph(this.parseText());
19487         }
19488       }
19489     };
19490   
19491     
19492     /**
19493      * Marked
19494      */
19495          /**
19496          * eval:var:marked
19497     */
19498     var marked = function (src, opt, callback) {
19499       if (callback || typeof opt === 'function') {
19500         if (!callback) {
19501           callback = opt;
19502           opt = null;
19503         }
19504     
19505         opt = merge({}, marked.defaults, opt || {});
19506     
19507         var highlight = opt.highlight
19508           , tokens
19509           , pending
19510           , i = 0;
19511     
19512         try {
19513           tokens = Lexer.lex(src, opt)
19514         } catch (e) {
19515           return callback(e);
19516         }
19517     
19518         pending = tokens.length;
19519          /**
19520          * eval:var:done
19521     */
19522         var done = function(err) {
19523           if (err) {
19524             opt.highlight = highlight;
19525             return callback(err);
19526           }
19527     
19528           var out;
19529     
19530           try {
19531             out = Parser.parse(tokens, opt);
19532           } catch (e) {
19533             err = e;
19534           }
19535     
19536           opt.highlight = highlight;
19537     
19538           return err
19539             ? callback(err)
19540             : callback(null, out);
19541         };
19542     
19543         if (!highlight || highlight.length < 3) {
19544           return done();
19545         }
19546     
19547         delete opt.highlight;
19548     
19549         if (!pending) { return done(); }
19550     
19551         for (; i < tokens.length; i++) {
19552           (function(token) {
19553             if (token.type !== 'code') {
19554               return --pending || done();
19555             }
19556             return highlight(token.text, token.lang, function(err, code) {
19557               if (err) { return done(err); }
19558               if (code == null || code === token.text) {
19559                 return --pending || done();
19560               }
19561               token.text = code;
19562               token.escaped = true;
19563               --pending || done();
19564             });
19565           })(tokens[i]);
19566         }
19567     
19568         return;
19569       }
19570       try {
19571         if (opt) { opt = merge({}, marked.defaults, opt); }
19572         return Parser.parse(Lexer.lex(src, opt), opt);
19573       } catch (e) {
19574         e.message += '\nPlease report this to https://github.com/chjj/marked.';
19575         if ((opt || marked.defaults).silent) {
19576           return '<p>An error occured:</p><pre>'
19577             + escape(e.message + '', true)
19578             + '</pre>';
19579         }
19580         throw e;
19581       }
19582     }
19583     
19584     /**
19585      * Options
19586      */
19587     
19588     marked.options =
19589     marked.setOptions = function(opt) {
19590       merge(marked.defaults, opt);
19591       return marked;
19592     };
19593     
19594     marked.defaults = {
19595       gfm: true,
19596       tables: true,
19597       breaks: false,
19598       pedantic: false,
19599       sanitize: false,
19600       sanitizer: null,
19601       mangle: true,
19602       smartLists: false,
19603       silent: false,
19604       highlight: null,
19605       langPrefix: 'lang-',
19606       smartypants: false,
19607       headerPrefix: '',
19608       renderer: new Renderer,
19609       xhtml: false
19610     };
19611     
19612     /**
19613      * Expose
19614      */
19615     
19616     marked.Parser = Parser;
19617     marked.parser = Parser.parse;
19618     
19619     marked.Renderer = Renderer;
19620     
19621     marked.Lexer = Lexer;
19622     marked.lexer = Lexer.lex;
19623     
19624     marked.InlineLexer = InlineLexer;
19625     marked.inlineLexer = InlineLexer.output;
19626     
19627     marked.parse = marked;
19628     
19629     Roo.Markdown.marked = marked;
19630
19631 })();/*
19632  * Based on:
19633  * Ext JS Library 1.1.1
19634  * Copyright(c) 2006-2007, Ext JS, LLC.
19635  *
19636  * Originally Released Under LGPL - original licence link has changed is not relivant.
19637  *
19638  * Fork - LGPL
19639  * <script type="text/javascript">
19640  */
19641
19642
19643
19644 /*
19645  * These classes are derivatives of the similarly named classes in the YUI Library.
19646  * The original license:
19647  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19648  * Code licensed under the BSD License:
19649  * http://developer.yahoo.net/yui/license.txt
19650  */
19651
19652 (function() {
19653
19654 var Event=Roo.EventManager;
19655 var Dom=Roo.lib.Dom;
19656
19657 /**
19658  * @class Roo.dd.DragDrop
19659  * @extends Roo.util.Observable
19660  * Defines the interface and base operation of items that that can be
19661  * dragged or can be drop targets.  It was designed to be extended, overriding
19662  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19663  * Up to three html elements can be associated with a DragDrop instance:
19664  * <ul>
19665  * <li>linked element: the element that is passed into the constructor.
19666  * This is the element which defines the boundaries for interaction with
19667  * other DragDrop objects.</li>
19668  * <li>handle element(s): The drag operation only occurs if the element that
19669  * was clicked matches a handle element.  By default this is the linked
19670  * element, but there are times that you will want only a portion of the
19671  * linked element to initiate the drag operation, and the setHandleElId()
19672  * method provides a way to define this.</li>
19673  * <li>drag element: this represents the element that would be moved along
19674  * with the cursor during a drag operation.  By default, this is the linked
19675  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
19676  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19677  * </li>
19678  * </ul>
19679  * This class should not be instantiated until the onload event to ensure that
19680  * the associated elements are available.
19681  * The following would define a DragDrop obj that would interact with any
19682  * other DragDrop obj in the "group1" group:
19683  * <pre>
19684  *  dd = new Roo.dd.DragDrop("div1", "group1");
19685  * </pre>
19686  * Since none of the event handlers have been implemented, nothing would
19687  * actually happen if you were to run the code above.  Normally you would
19688  * override this class or one of the default implementations, but you can
19689  * also override the methods you want on an instance of the class...
19690  * <pre>
19691  *  dd.onDragDrop = function(e, id) {
19692  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
19693  *  }
19694  * </pre>
19695  * @constructor
19696  * @param {String} id of the element that is linked to this instance
19697  * @param {String} sGroup the group of related DragDrop objects
19698  * @param {object} config an object containing configurable attributes
19699  *                Valid properties for DragDrop:
19700  *                    padding, isTarget, maintainOffset, primaryButtonOnly
19701  */
19702 Roo.dd.DragDrop = function(id, sGroup, config) {
19703     if (id) {
19704         this.init(id, sGroup, config);
19705     }
19706     
19707 };
19708
19709 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19710
19711     /**
19712      * The id of the element associated with this object.  This is what we
19713      * refer to as the "linked element" because the size and position of
19714      * this element is used to determine when the drag and drop objects have
19715      * interacted.
19716      * @property id
19717      * @type String
19718      */
19719     id: null,
19720
19721     /**
19722      * Configuration attributes passed into the constructor
19723      * @property config
19724      * @type object
19725      */
19726     config: null,
19727
19728     /**
19729      * The id of the element that will be dragged.  By default this is same
19730      * as the linked element , but could be changed to another element. Ex:
19731      * Roo.dd.DDProxy
19732      * @property dragElId
19733      * @type String
19734      * @private
19735      */
19736     dragElId: null,
19737
19738     /**
19739      * the id of the element that initiates the drag operation.  By default
19740      * this is the linked element, but could be changed to be a child of this
19741      * element.  This lets us do things like only starting the drag when the
19742      * header element within the linked html element is clicked.
19743      * @property handleElId
19744      * @type String
19745      * @private
19746      */
19747     handleElId: null,
19748
19749     /**
19750      * An associative array of HTML tags that will be ignored if clicked.
19751      * @property invalidHandleTypes
19752      * @type {string: string}
19753      */
19754     invalidHandleTypes: null,
19755
19756     /**
19757      * An associative array of ids for elements that will be ignored if clicked
19758      * @property invalidHandleIds
19759      * @type {string: string}
19760      */
19761     invalidHandleIds: null,
19762
19763     /**
19764      * An indexted array of css class names for elements that will be ignored
19765      * if clicked.
19766      * @property invalidHandleClasses
19767      * @type string[]
19768      */
19769     invalidHandleClasses: null,
19770
19771     /**
19772      * The linked element's absolute X position at the time the drag was
19773      * started
19774      * @property startPageX
19775      * @type int
19776      * @private
19777      */
19778     startPageX: 0,
19779
19780     /**
19781      * The linked element's absolute X position at the time the drag was
19782      * started
19783      * @property startPageY
19784      * @type int
19785      * @private
19786      */
19787     startPageY: 0,
19788
19789     /**
19790      * The group defines a logical collection of DragDrop objects that are
19791      * related.  Instances only get events when interacting with other
19792      * DragDrop object in the same group.  This lets us define multiple
19793      * groups using a single DragDrop subclass if we want.
19794      * @property groups
19795      * @type {string: string}
19796      */
19797     groups: null,
19798
19799     /**
19800      * Individual drag/drop instances can be locked.  This will prevent
19801      * onmousedown start drag.
19802      * @property locked
19803      * @type boolean
19804      * @private
19805      */
19806     locked: false,
19807
19808     /**
19809      * Lock this instance
19810      * @method lock
19811      */
19812     lock: function() { this.locked = true; },
19813
19814     /**
19815      * Unlock this instace
19816      * @method unlock
19817      */
19818     unlock: function() { this.locked = false; },
19819
19820     /**
19821      * By default, all insances can be a drop target.  This can be disabled by
19822      * setting isTarget to false.
19823      * @method isTarget
19824      * @type boolean
19825      */
19826     isTarget: true,
19827
19828     /**
19829      * The padding configured for this drag and drop object for calculating
19830      * the drop zone intersection with this object.
19831      * @method padding
19832      * @type int[]
19833      */
19834     padding: null,
19835
19836     /**
19837      * Cached reference to the linked element
19838      * @property _domRef
19839      * @private
19840      */
19841     _domRef: null,
19842
19843     /**
19844      * Internal typeof flag
19845      * @property __ygDragDrop
19846      * @private
19847      */
19848     __ygDragDrop: true,
19849
19850     /**
19851      * Set to true when horizontal contraints are applied
19852      * @property constrainX
19853      * @type boolean
19854      * @private
19855      */
19856     constrainX: false,
19857
19858     /**
19859      * Set to true when vertical contraints are applied
19860      * @property constrainY
19861      * @type boolean
19862      * @private
19863      */
19864     constrainY: false,
19865
19866     /**
19867      * The left constraint
19868      * @property minX
19869      * @type int
19870      * @private
19871      */
19872     minX: 0,
19873
19874     /**
19875      * The right constraint
19876      * @property maxX
19877      * @type int
19878      * @private
19879      */
19880     maxX: 0,
19881
19882     /**
19883      * The up constraint
19884      * @property minY
19885      * @type int
19886      * @type int
19887      * @private
19888      */
19889     minY: 0,
19890
19891     /**
19892      * The down constraint
19893      * @property maxY
19894      * @type int
19895      * @private
19896      */
19897     maxY: 0,
19898
19899     /**
19900      * Maintain offsets when we resetconstraints.  Set to true when you want
19901      * the position of the element relative to its parent to stay the same
19902      * when the page changes
19903      *
19904      * @property maintainOffset
19905      * @type boolean
19906      */
19907     maintainOffset: false,
19908
19909     /**
19910      * Array of pixel locations the element will snap to if we specified a
19911      * horizontal graduation/interval.  This array is generated automatically
19912      * when you define a tick interval.
19913      * @property xTicks
19914      * @type int[]
19915      */
19916     xTicks: null,
19917
19918     /**
19919      * Array of pixel locations the element will snap to if we specified a
19920      * vertical graduation/interval.  This array is generated automatically
19921      * when you define a tick interval.
19922      * @property yTicks
19923      * @type int[]
19924      */
19925     yTicks: null,
19926
19927     /**
19928      * By default the drag and drop instance will only respond to the primary
19929      * button click (left button for a right-handed mouse).  Set to true to
19930      * allow drag and drop to start with any mouse click that is propogated
19931      * by the browser
19932      * @property primaryButtonOnly
19933      * @type boolean
19934      */
19935     primaryButtonOnly: true,
19936
19937     /**
19938      * The availabe property is false until the linked dom element is accessible.
19939      * @property available
19940      * @type boolean
19941      */
19942     available: false,
19943
19944     /**
19945      * By default, drags can only be initiated if the mousedown occurs in the
19946      * region the linked element is.  This is done in part to work around a
19947      * bug in some browsers that mis-report the mousedown if the previous
19948      * mouseup happened outside of the window.  This property is set to true
19949      * if outer handles are defined.
19950      *
19951      * @property hasOuterHandles
19952      * @type boolean
19953      * @default false
19954      */
19955     hasOuterHandles: false,
19956
19957     /**
19958      * Code that executes immediately before the startDrag event
19959      * @method b4StartDrag
19960      * @private
19961      */
19962     b4StartDrag: function(x, y) { },
19963
19964     /**
19965      * Abstract method called after a drag/drop object is clicked
19966      * and the drag or mousedown time thresholds have beeen met.
19967      * @method startDrag
19968      * @param {int} X click location
19969      * @param {int} Y click location
19970      */
19971     startDrag: function(x, y) { /* override this */ },
19972
19973     /**
19974      * Code that executes immediately before the onDrag event
19975      * @method b4Drag
19976      * @private
19977      */
19978     b4Drag: function(e) { },
19979
19980     /**
19981      * Abstract method called during the onMouseMove event while dragging an
19982      * object.
19983      * @method onDrag
19984      * @param {Event} e the mousemove event
19985      */
19986     onDrag: function(e) { /* override this */ },
19987
19988     /**
19989      * Abstract method called when this element fist begins hovering over
19990      * another DragDrop obj
19991      * @method onDragEnter
19992      * @param {Event} e the mousemove event
19993      * @param {String|DragDrop[]} id In POINT mode, the element
19994      * id this is hovering over.  In INTERSECT mode, an array of one or more
19995      * dragdrop items being hovered over.
19996      */
19997     onDragEnter: function(e, id) { /* override this */ },
19998
19999     /**
20000      * Code that executes immediately before the onDragOver event
20001      * @method b4DragOver
20002      * @private
20003      */
20004     b4DragOver: function(e) { },
20005
20006     /**
20007      * Abstract method called when this element is hovering over another
20008      * DragDrop obj
20009      * @method onDragOver
20010      * @param {Event} e the mousemove event
20011      * @param {String|DragDrop[]} id In POINT mode, the element
20012      * id this is hovering over.  In INTERSECT mode, an array of dd items
20013      * being hovered over.
20014      */
20015     onDragOver: function(e, id) { /* override this */ },
20016
20017     /**
20018      * Code that executes immediately before the onDragOut event
20019      * @method b4DragOut
20020      * @private
20021      */
20022     b4DragOut: function(e) { },
20023
20024     /**
20025      * Abstract method called when we are no longer hovering over an element
20026      * @method onDragOut
20027      * @param {Event} e the mousemove event
20028      * @param {String|DragDrop[]} id In POINT mode, the element
20029      * id this was hovering over.  In INTERSECT mode, an array of dd items
20030      * that the mouse is no longer over.
20031      */
20032     onDragOut: function(e, id) { /* override this */ },
20033
20034     /**
20035      * Code that executes immediately before the onDragDrop event
20036      * @method b4DragDrop
20037      * @private
20038      */
20039     b4DragDrop: function(e) { },
20040
20041     /**
20042      * Abstract method called when this item is dropped on another DragDrop
20043      * obj
20044      * @method onDragDrop
20045      * @param {Event} e the mouseup event
20046      * @param {String|DragDrop[]} id In POINT mode, the element
20047      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20048      * was dropped on.
20049      */
20050     onDragDrop: function(e, id) { /* override this */ },
20051
20052     /**
20053      * Abstract method called when this item is dropped on an area with no
20054      * drop target
20055      * @method onInvalidDrop
20056      * @param {Event} e the mouseup event
20057      */
20058     onInvalidDrop: function(e) { /* override this */ },
20059
20060     /**
20061      * Code that executes immediately before the endDrag event
20062      * @method b4EndDrag
20063      * @private
20064      */
20065     b4EndDrag: function(e) { },
20066
20067     /**
20068      * Fired when we are done dragging the object
20069      * @method endDrag
20070      * @param {Event} e the mouseup event
20071      */
20072     endDrag: function(e) { /* override this */ },
20073
20074     /**
20075      * Code executed immediately before the onMouseDown event
20076      * @method b4MouseDown
20077      * @param {Event} e the mousedown event
20078      * @private
20079      */
20080     b4MouseDown: function(e) {  },
20081
20082     /**
20083      * Event handler that fires when a drag/drop obj gets a mousedown
20084      * @method onMouseDown
20085      * @param {Event} e the mousedown event
20086      */
20087     onMouseDown: function(e) { /* override this */ },
20088
20089     /**
20090      * Event handler that fires when a drag/drop obj gets a mouseup
20091      * @method onMouseUp
20092      * @param {Event} e the mouseup event
20093      */
20094     onMouseUp: function(e) { /* override this */ },
20095
20096     /**
20097      * Override the onAvailable method to do what is needed after the initial
20098      * position was determined.
20099      * @method onAvailable
20100      */
20101     onAvailable: function () {
20102     },
20103
20104     /*
20105      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20106      * @type Object
20107      */
20108     defaultPadding : {left:0, right:0, top:0, bottom:0},
20109
20110     /*
20111      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20112  *
20113  * Usage:
20114  <pre><code>
20115  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20116                 { dragElId: "existingProxyDiv" });
20117  dd.startDrag = function(){
20118      this.constrainTo("parent-id");
20119  };
20120  </code></pre>
20121  * Or you can initalize it using the {@link Roo.Element} object:
20122  <pre><code>
20123  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20124      startDrag : function(){
20125          this.constrainTo("parent-id");
20126      }
20127  });
20128  </code></pre>
20129      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20130      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20131      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20132      * an object containing the sides to pad. For example: {right:10, bottom:10}
20133      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20134      */
20135     constrainTo : function(constrainTo, pad, inContent){
20136         if(typeof pad == "number"){
20137             pad = {left: pad, right:pad, top:pad, bottom:pad};
20138         }
20139         pad = pad || this.defaultPadding;
20140         var b = Roo.get(this.getEl()).getBox();
20141         var ce = Roo.get(constrainTo);
20142         var s = ce.getScroll();
20143         var c, cd = ce.dom;
20144         if(cd == document.body){
20145             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20146         }else{
20147             xy = ce.getXY();
20148             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20149         }
20150
20151
20152         var topSpace = b.y - c.y;
20153         var leftSpace = b.x - c.x;
20154
20155         this.resetConstraints();
20156         this.setXConstraint(leftSpace - (pad.left||0), // left
20157                 c.width - leftSpace - b.width - (pad.right||0) //right
20158         );
20159         this.setYConstraint(topSpace - (pad.top||0), //top
20160                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20161         );
20162     },
20163
20164     /**
20165      * Returns a reference to the linked element
20166      * @method getEl
20167      * @return {HTMLElement} the html element
20168      */
20169     getEl: function() {
20170         if (!this._domRef) {
20171             this._domRef = Roo.getDom(this.id);
20172         }
20173
20174         return this._domRef;
20175     },
20176
20177     /**
20178      * Returns a reference to the actual element to drag.  By default this is
20179      * the same as the html element, but it can be assigned to another
20180      * element. An example of this can be found in Roo.dd.DDProxy
20181      * @method getDragEl
20182      * @return {HTMLElement} the html element
20183      */
20184     getDragEl: function() {
20185         return Roo.getDom(this.dragElId);
20186     },
20187
20188     /**
20189      * Sets up the DragDrop object.  Must be called in the constructor of any
20190      * Roo.dd.DragDrop subclass
20191      * @method init
20192      * @param id the id of the linked element
20193      * @param {String} sGroup the group of related items
20194      * @param {object} config configuration attributes
20195      */
20196     init: function(id, sGroup, config) {
20197         this.initTarget(id, sGroup, config);
20198         if (!Roo.isTouch) {
20199             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20200         }
20201         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20202         // Event.on(this.id, "selectstart", Event.preventDefault);
20203     },
20204
20205     /**
20206      * Initializes Targeting functionality only... the object does not
20207      * get a mousedown handler.
20208      * @method initTarget
20209      * @param id the id of the linked element
20210      * @param {String} sGroup the group of related items
20211      * @param {object} config configuration attributes
20212      */
20213     initTarget: function(id, sGroup, config) {
20214
20215         // configuration attributes
20216         this.config = config || {};
20217
20218         // create a local reference to the drag and drop manager
20219         this.DDM = Roo.dd.DDM;
20220         // initialize the groups array
20221         this.groups = {};
20222
20223         // assume that we have an element reference instead of an id if the
20224         // parameter is not a string
20225         if (typeof id !== "string") {
20226             id = Roo.id(id);
20227         }
20228
20229         // set the id
20230         this.id = id;
20231
20232         // add to an interaction group
20233         this.addToGroup((sGroup) ? sGroup : "default");
20234
20235         // We don't want to register this as the handle with the manager
20236         // so we just set the id rather than calling the setter.
20237         this.handleElId = id;
20238
20239         // the linked element is the element that gets dragged by default
20240         this.setDragElId(id);
20241
20242         // by default, clicked anchors will not start drag operations.
20243         this.invalidHandleTypes = { A: "A" };
20244         this.invalidHandleIds = {};
20245         this.invalidHandleClasses = [];
20246
20247         this.applyConfig();
20248
20249         this.handleOnAvailable();
20250     },
20251
20252     /**
20253      * Applies the configuration parameters that were passed into the constructor.
20254      * This is supposed to happen at each level through the inheritance chain.  So
20255      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20256      * DragDrop in order to get all of the parameters that are available in
20257      * each object.
20258      * @method applyConfig
20259      */
20260     applyConfig: function() {
20261
20262         // configurable properties:
20263         //    padding, isTarget, maintainOffset, primaryButtonOnly
20264         this.padding           = this.config.padding || [0, 0, 0, 0];
20265         this.isTarget          = (this.config.isTarget !== false);
20266         this.maintainOffset    = (this.config.maintainOffset);
20267         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20268
20269     },
20270
20271     /**
20272      * Executed when the linked element is available
20273      * @method handleOnAvailable
20274      * @private
20275      */
20276     handleOnAvailable: function() {
20277         this.available = true;
20278         this.resetConstraints();
20279         this.onAvailable();
20280     },
20281
20282      /**
20283      * Configures the padding for the target zone in px.  Effectively expands
20284      * (or reduces) the virtual object size for targeting calculations.
20285      * Supports css-style shorthand; if only one parameter is passed, all sides
20286      * will have that padding, and if only two are passed, the top and bottom
20287      * will have the first param, the left and right the second.
20288      * @method setPadding
20289      * @param {int} iTop    Top pad
20290      * @param {int} iRight  Right pad
20291      * @param {int} iBot    Bot pad
20292      * @param {int} iLeft   Left pad
20293      */
20294     setPadding: function(iTop, iRight, iBot, iLeft) {
20295         // this.padding = [iLeft, iRight, iTop, iBot];
20296         if (!iRight && 0 !== iRight) {
20297             this.padding = [iTop, iTop, iTop, iTop];
20298         } else if (!iBot && 0 !== iBot) {
20299             this.padding = [iTop, iRight, iTop, iRight];
20300         } else {
20301             this.padding = [iTop, iRight, iBot, iLeft];
20302         }
20303     },
20304
20305     /**
20306      * Stores the initial placement of the linked element.
20307      * @method setInitialPosition
20308      * @param {int} diffX   the X offset, default 0
20309      * @param {int} diffY   the Y offset, default 0
20310      */
20311     setInitPosition: function(diffX, diffY) {
20312         var el = this.getEl();
20313
20314         if (!this.DDM.verifyEl(el)) {
20315             return;
20316         }
20317
20318         var dx = diffX || 0;
20319         var dy = diffY || 0;
20320
20321         var p = Dom.getXY( el );
20322
20323         this.initPageX = p[0] - dx;
20324         this.initPageY = p[1] - dy;
20325
20326         this.lastPageX = p[0];
20327         this.lastPageY = p[1];
20328
20329
20330         this.setStartPosition(p);
20331     },
20332
20333     /**
20334      * Sets the start position of the element.  This is set when the obj
20335      * is initialized, the reset when a drag is started.
20336      * @method setStartPosition
20337      * @param pos current position (from previous lookup)
20338      * @private
20339      */
20340     setStartPosition: function(pos) {
20341         var p = pos || Dom.getXY( this.getEl() );
20342         this.deltaSetXY = null;
20343
20344         this.startPageX = p[0];
20345         this.startPageY = p[1];
20346     },
20347
20348     /**
20349      * Add this instance to a group of related drag/drop objects.  All
20350      * instances belong to at least one group, and can belong to as many
20351      * groups as needed.
20352      * @method addToGroup
20353      * @param sGroup {string} the name of the group
20354      */
20355     addToGroup: function(sGroup) {
20356         this.groups[sGroup] = true;
20357         this.DDM.regDragDrop(this, sGroup);
20358     },
20359
20360     /**
20361      * Remove's this instance from the supplied interaction group
20362      * @method removeFromGroup
20363      * @param {string}  sGroup  The group to drop
20364      */
20365     removeFromGroup: function(sGroup) {
20366         if (this.groups[sGroup]) {
20367             delete this.groups[sGroup];
20368         }
20369
20370         this.DDM.removeDDFromGroup(this, sGroup);
20371     },
20372
20373     /**
20374      * Allows you to specify that an element other than the linked element
20375      * will be moved with the cursor during a drag
20376      * @method setDragElId
20377      * @param id {string} the id of the element that will be used to initiate the drag
20378      */
20379     setDragElId: function(id) {
20380         this.dragElId = id;
20381     },
20382
20383     /**
20384      * Allows you to specify a child of the linked element that should be
20385      * used to initiate the drag operation.  An example of this would be if
20386      * you have a content div with text and links.  Clicking anywhere in the
20387      * content area would normally start the drag operation.  Use this method
20388      * to specify that an element inside of the content div is the element
20389      * that starts the drag operation.
20390      * @method setHandleElId
20391      * @param id {string} the id of the element that will be used to
20392      * initiate the drag.
20393      */
20394     setHandleElId: function(id) {
20395         if (typeof id !== "string") {
20396             id = Roo.id(id);
20397         }
20398         this.handleElId = id;
20399         this.DDM.regHandle(this.id, id);
20400     },
20401
20402     /**
20403      * Allows you to set an element outside of the linked element as a drag
20404      * handle
20405      * @method setOuterHandleElId
20406      * @param id the id of the element that will be used to initiate the drag
20407      */
20408     setOuterHandleElId: function(id) {
20409         if (typeof id !== "string") {
20410             id = Roo.id(id);
20411         }
20412         Event.on(id, "mousedown",
20413                 this.handleMouseDown, this);
20414         this.setHandleElId(id);
20415
20416         this.hasOuterHandles = true;
20417     },
20418
20419     /**
20420      * Remove all drag and drop hooks for this element
20421      * @method unreg
20422      */
20423     unreg: function() {
20424         Event.un(this.id, "mousedown",
20425                 this.handleMouseDown);
20426         Event.un(this.id, "touchstart",
20427                 this.handleMouseDown);
20428         this._domRef = null;
20429         this.DDM._remove(this);
20430     },
20431
20432     destroy : function(){
20433         this.unreg();
20434     },
20435
20436     /**
20437      * Returns true if this instance is locked, or the drag drop mgr is locked
20438      * (meaning that all drag/drop is disabled on the page.)
20439      * @method isLocked
20440      * @return {boolean} true if this obj or all drag/drop is locked, else
20441      * false
20442      */
20443     isLocked: function() {
20444         return (this.DDM.isLocked() || this.locked);
20445     },
20446
20447     /**
20448      * Fired when this object is clicked
20449      * @method handleMouseDown
20450      * @param {Event} e
20451      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20452      * @private
20453      */
20454     handleMouseDown: function(e, oDD){
20455      
20456         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20457             //Roo.log('not touch/ button !=0');
20458             return;
20459         }
20460         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20461             return; // double touch..
20462         }
20463         
20464
20465         if (this.isLocked()) {
20466             //Roo.log('locked');
20467             return;
20468         }
20469
20470         this.DDM.refreshCache(this.groups);
20471 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20472         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20473         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20474             //Roo.log('no outer handes or not over target');
20475                 // do nothing.
20476         } else {
20477 //            Roo.log('check validator');
20478             if (this.clickValidator(e)) {
20479 //                Roo.log('validate success');
20480                 // set the initial element position
20481                 this.setStartPosition();
20482
20483
20484                 this.b4MouseDown(e);
20485                 this.onMouseDown(e);
20486
20487                 this.DDM.handleMouseDown(e, this);
20488
20489                 this.DDM.stopEvent(e);
20490             } else {
20491
20492
20493             }
20494         }
20495     },
20496
20497     clickValidator: function(e) {
20498         var target = e.getTarget();
20499         return ( this.isValidHandleChild(target) &&
20500                     (this.id == this.handleElId ||
20501                         this.DDM.handleWasClicked(target, this.id)) );
20502     },
20503
20504     /**
20505      * Allows you to specify a tag name that should not start a drag operation
20506      * when clicked.  This is designed to facilitate embedding links within a
20507      * drag handle that do something other than start the drag.
20508      * @method addInvalidHandleType
20509      * @param {string} tagName the type of element to exclude
20510      */
20511     addInvalidHandleType: function(tagName) {
20512         var type = tagName.toUpperCase();
20513         this.invalidHandleTypes[type] = type;
20514     },
20515
20516     /**
20517      * Lets you to specify an element id for a child of a drag handle
20518      * that should not initiate a drag
20519      * @method addInvalidHandleId
20520      * @param {string} id the element id of the element you wish to ignore
20521      */
20522     addInvalidHandleId: function(id) {
20523         if (typeof id !== "string") {
20524             id = Roo.id(id);
20525         }
20526         this.invalidHandleIds[id] = id;
20527     },
20528
20529     /**
20530      * Lets you specify a css class of elements that will not initiate a drag
20531      * @method addInvalidHandleClass
20532      * @param {string} cssClass the class of the elements you wish to ignore
20533      */
20534     addInvalidHandleClass: function(cssClass) {
20535         this.invalidHandleClasses.push(cssClass);
20536     },
20537
20538     /**
20539      * Unsets an excluded tag name set by addInvalidHandleType
20540      * @method removeInvalidHandleType
20541      * @param {string} tagName the type of element to unexclude
20542      */
20543     removeInvalidHandleType: function(tagName) {
20544         var type = tagName.toUpperCase();
20545         // this.invalidHandleTypes[type] = null;
20546         delete this.invalidHandleTypes[type];
20547     },
20548
20549     /**
20550      * Unsets an invalid handle id
20551      * @method removeInvalidHandleId
20552      * @param {string} id the id of the element to re-enable
20553      */
20554     removeInvalidHandleId: function(id) {
20555         if (typeof id !== "string") {
20556             id = Roo.id(id);
20557         }
20558         delete this.invalidHandleIds[id];
20559     },
20560
20561     /**
20562      * Unsets an invalid css class
20563      * @method removeInvalidHandleClass
20564      * @param {string} cssClass the class of the element(s) you wish to
20565      * re-enable
20566      */
20567     removeInvalidHandleClass: function(cssClass) {
20568         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20569             if (this.invalidHandleClasses[i] == cssClass) {
20570                 delete this.invalidHandleClasses[i];
20571             }
20572         }
20573     },
20574
20575     /**
20576      * Checks the tag exclusion list to see if this click should be ignored
20577      * @method isValidHandleChild
20578      * @param {HTMLElement} node the HTMLElement to evaluate
20579      * @return {boolean} true if this is a valid tag type, false if not
20580      */
20581     isValidHandleChild: function(node) {
20582
20583         var valid = true;
20584         // var n = (node.nodeName == "#text") ? node.parentNode : node;
20585         var nodeName;
20586         try {
20587             nodeName = node.nodeName.toUpperCase();
20588         } catch(e) {
20589             nodeName = node.nodeName;
20590         }
20591         valid = valid && !this.invalidHandleTypes[nodeName];
20592         valid = valid && !this.invalidHandleIds[node.id];
20593
20594         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20595             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20596         }
20597
20598
20599         return valid;
20600
20601     },
20602
20603     /**
20604      * Create the array of horizontal tick marks if an interval was specified
20605      * in setXConstraint().
20606      * @method setXTicks
20607      * @private
20608      */
20609     setXTicks: function(iStartX, iTickSize) {
20610         this.xTicks = [];
20611         this.xTickSize = iTickSize;
20612
20613         var tickMap = {};
20614
20615         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20616             if (!tickMap[i]) {
20617                 this.xTicks[this.xTicks.length] = i;
20618                 tickMap[i] = true;
20619             }
20620         }
20621
20622         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20623             if (!tickMap[i]) {
20624                 this.xTicks[this.xTicks.length] = i;
20625                 tickMap[i] = true;
20626             }
20627         }
20628
20629         this.xTicks.sort(this.DDM.numericSort) ;
20630     },
20631
20632     /**
20633      * Create the array of vertical tick marks if an interval was specified in
20634      * setYConstraint().
20635      * @method setYTicks
20636      * @private
20637      */
20638     setYTicks: function(iStartY, iTickSize) {
20639         this.yTicks = [];
20640         this.yTickSize = iTickSize;
20641
20642         var tickMap = {};
20643
20644         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20645             if (!tickMap[i]) {
20646                 this.yTicks[this.yTicks.length] = i;
20647                 tickMap[i] = true;
20648             }
20649         }
20650
20651         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20652             if (!tickMap[i]) {
20653                 this.yTicks[this.yTicks.length] = i;
20654                 tickMap[i] = true;
20655             }
20656         }
20657
20658         this.yTicks.sort(this.DDM.numericSort) ;
20659     },
20660
20661     /**
20662      * By default, the element can be dragged any place on the screen.  Use
20663      * this method to limit the horizontal travel of the element.  Pass in
20664      * 0,0 for the parameters if you want to lock the drag to the y axis.
20665      * @method setXConstraint
20666      * @param {int} iLeft the number of pixels the element can move to the left
20667      * @param {int} iRight the number of pixels the element can move to the
20668      * right
20669      * @param {int} iTickSize optional parameter for specifying that the
20670      * element
20671      * should move iTickSize pixels at a time.
20672      */
20673     setXConstraint: function(iLeft, iRight, iTickSize) {
20674         this.leftConstraint = iLeft;
20675         this.rightConstraint = iRight;
20676
20677         this.minX = this.initPageX - iLeft;
20678         this.maxX = this.initPageX + iRight;
20679         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20680
20681         this.constrainX = true;
20682     },
20683
20684     /**
20685      * Clears any constraints applied to this instance.  Also clears ticks
20686      * since they can't exist independent of a constraint at this time.
20687      * @method clearConstraints
20688      */
20689     clearConstraints: function() {
20690         this.constrainX = false;
20691         this.constrainY = false;
20692         this.clearTicks();
20693     },
20694
20695     /**
20696      * Clears any tick interval defined for this instance
20697      * @method clearTicks
20698      */
20699     clearTicks: function() {
20700         this.xTicks = null;
20701         this.yTicks = null;
20702         this.xTickSize = 0;
20703         this.yTickSize = 0;
20704     },
20705
20706     /**
20707      * By default, the element can be dragged any place on the screen.  Set
20708      * this to limit the vertical travel of the element.  Pass in 0,0 for the
20709      * parameters if you want to lock the drag to the x axis.
20710      * @method setYConstraint
20711      * @param {int} iUp the number of pixels the element can move up
20712      * @param {int} iDown the number of pixels the element can move down
20713      * @param {int} iTickSize optional parameter for specifying that the
20714      * element should move iTickSize pixels at a time.
20715      */
20716     setYConstraint: function(iUp, iDown, iTickSize) {
20717         this.topConstraint = iUp;
20718         this.bottomConstraint = iDown;
20719
20720         this.minY = this.initPageY - iUp;
20721         this.maxY = this.initPageY + iDown;
20722         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20723
20724         this.constrainY = true;
20725
20726     },
20727
20728     /**
20729      * resetConstraints must be called if you manually reposition a dd element.
20730      * @method resetConstraints
20731      * @param {boolean} maintainOffset
20732      */
20733     resetConstraints: function() {
20734
20735
20736         // Maintain offsets if necessary
20737         if (this.initPageX || this.initPageX === 0) {
20738             // figure out how much this thing has moved
20739             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20740             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20741
20742             this.setInitPosition(dx, dy);
20743
20744         // This is the first time we have detected the element's position
20745         } else {
20746             this.setInitPosition();
20747         }
20748
20749         if (this.constrainX) {
20750             this.setXConstraint( this.leftConstraint,
20751                                  this.rightConstraint,
20752                                  this.xTickSize        );
20753         }
20754
20755         if (this.constrainY) {
20756             this.setYConstraint( this.topConstraint,
20757                                  this.bottomConstraint,
20758                                  this.yTickSize         );
20759         }
20760     },
20761
20762     /**
20763      * Normally the drag element is moved pixel by pixel, but we can specify
20764      * that it move a number of pixels at a time.  This method resolves the
20765      * location when we have it set up like this.
20766      * @method getTick
20767      * @param {int} val where we want to place the object
20768      * @param {int[]} tickArray sorted array of valid points
20769      * @return {int} the closest tick
20770      * @private
20771      */
20772     getTick: function(val, tickArray) {
20773
20774         if (!tickArray) {
20775             // If tick interval is not defined, it is effectively 1 pixel,
20776             // so we return the value passed to us.
20777             return val;
20778         } else if (tickArray[0] >= val) {
20779             // The value is lower than the first tick, so we return the first
20780             // tick.
20781             return tickArray[0];
20782         } else {
20783             for (var i=0, len=tickArray.length; i<len; ++i) {
20784                 var next = i + 1;
20785                 if (tickArray[next] && tickArray[next] >= val) {
20786                     var diff1 = val - tickArray[i];
20787                     var diff2 = tickArray[next] - val;
20788                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20789                 }
20790             }
20791
20792             // The value is larger than the last tick, so we return the last
20793             // tick.
20794             return tickArray[tickArray.length - 1];
20795         }
20796     },
20797
20798     /**
20799      * toString method
20800      * @method toString
20801      * @return {string} string representation of the dd obj
20802      */
20803     toString: function() {
20804         return ("DragDrop " + this.id);
20805     }
20806
20807 });
20808
20809 })();
20810 /*
20811  * Based on:
20812  * Ext JS Library 1.1.1
20813  * Copyright(c) 2006-2007, Ext JS, LLC.
20814  *
20815  * Originally Released Under LGPL - original licence link has changed is not relivant.
20816  *
20817  * Fork - LGPL
20818  * <script type="text/javascript">
20819  */
20820
20821
20822 /**
20823  * The drag and drop utility provides a framework for building drag and drop
20824  * applications.  In addition to enabling drag and drop for specific elements,
20825  * the drag and drop elements are tracked by the manager class, and the
20826  * interactions between the various elements are tracked during the drag and
20827  * the implementing code is notified about these important moments.
20828  */
20829
20830 // Only load the library once.  Rewriting the manager class would orphan
20831 // existing drag and drop instances.
20832 if (!Roo.dd.DragDropMgr) {
20833
20834 /**
20835  * @class Roo.dd.DragDropMgr
20836  * DragDropMgr is a singleton that tracks the element interaction for
20837  * all DragDrop items in the window.  Generally, you will not call
20838  * this class directly, but it does have helper methods that could
20839  * be useful in your DragDrop implementations.
20840  * @static
20841  */
20842 Roo.dd.DragDropMgr = function() {
20843
20844     var Event = Roo.EventManager;
20845
20846     return {
20847
20848         /**
20849          * Two dimensional Array of registered DragDrop objects.  The first
20850          * dimension is the DragDrop item group, the second the DragDrop
20851          * object.
20852          * @property ids
20853          * @type {string: string}
20854          * @private
20855          * @static
20856          */
20857         ids: {},
20858
20859         /**
20860          * Array of element ids defined as drag handles.  Used to determine
20861          * if the element that generated the mousedown event is actually the
20862          * handle and not the html element itself.
20863          * @property handleIds
20864          * @type {string: string}
20865          * @private
20866          * @static
20867          */
20868         handleIds: {},
20869
20870         /**
20871          * the DragDrop object that is currently being dragged
20872          * @property dragCurrent
20873          * @type DragDrop
20874          * @private
20875          * @static
20876          **/
20877         dragCurrent: null,
20878
20879         /**
20880          * the DragDrop object(s) that are being hovered over
20881          * @property dragOvers
20882          * @type Array
20883          * @private
20884          * @static
20885          */
20886         dragOvers: {},
20887
20888         /**
20889          * the X distance between the cursor and the object being dragged
20890          * @property deltaX
20891          * @type int
20892          * @private
20893          * @static
20894          */
20895         deltaX: 0,
20896
20897         /**
20898          * the Y distance between the cursor and the object being dragged
20899          * @property deltaY
20900          * @type int
20901          * @private
20902          * @static
20903          */
20904         deltaY: 0,
20905
20906         /**
20907          * Flag to determine if we should prevent the default behavior of the
20908          * events we define. By default this is true, but this can be set to
20909          * false if you need the default behavior (not recommended)
20910          * @property preventDefault
20911          * @type boolean
20912          * @static
20913          */
20914         preventDefault: true,
20915
20916         /**
20917          * Flag to determine if we should stop the propagation of the events
20918          * we generate. This is true by default but you may want to set it to
20919          * false if the html element contains other features that require the
20920          * mouse click.
20921          * @property stopPropagation
20922          * @type boolean
20923          * @static
20924          */
20925         stopPropagation: true,
20926
20927         /**
20928          * Internal flag that is set to true when drag and drop has been
20929          * intialized
20930          * @property initialized
20931          * @private
20932          * @static
20933          */
20934         initalized: false,
20935
20936         /**
20937          * All drag and drop can be disabled.
20938          * @property locked
20939          * @private
20940          * @static
20941          */
20942         locked: false,
20943
20944         /**
20945          * Called the first time an element is registered.
20946          * @method init
20947          * @private
20948          * @static
20949          */
20950         init: function() {
20951             this.initialized = true;
20952         },
20953
20954         /**
20955          * In point mode, drag and drop interaction is defined by the
20956          * location of the cursor during the drag/drop
20957          * @property POINT
20958          * @type int
20959          * @static
20960          */
20961         POINT: 0,
20962
20963         /**
20964          * In intersect mode, drag and drop interactio nis defined by the
20965          * overlap of two or more drag and drop objects.
20966          * @property INTERSECT
20967          * @type int
20968          * @static
20969          */
20970         INTERSECT: 1,
20971
20972         /**
20973          * The current drag and drop mode.  Default: POINT
20974          * @property mode
20975          * @type int
20976          * @static
20977          */
20978         mode: 0,
20979
20980         /**
20981          * Runs method on all drag and drop objects
20982          * @method _execOnAll
20983          * @private
20984          * @static
20985          */
20986         _execOnAll: function(sMethod, args) {
20987             for (var i in this.ids) {
20988                 for (var j in this.ids[i]) {
20989                     var oDD = this.ids[i][j];
20990                     if (! this.isTypeOfDD(oDD)) {
20991                         continue;
20992                     }
20993                     oDD[sMethod].apply(oDD, args);
20994                 }
20995             }
20996         },
20997
20998         /**
20999          * Drag and drop initialization.  Sets up the global event handlers
21000          * @method _onLoad
21001          * @private
21002          * @static
21003          */
21004         _onLoad: function() {
21005
21006             this.init();
21007
21008             if (!Roo.isTouch) {
21009                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21010                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21011             }
21012             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21013             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21014             
21015             Event.on(window,   "unload",    this._onUnload, this, true);
21016             Event.on(window,   "resize",    this._onResize, this, true);
21017             // Event.on(window,   "mouseout",    this._test);
21018
21019         },
21020
21021         /**
21022          * Reset constraints on all drag and drop objs
21023          * @method _onResize
21024          * @private
21025          * @static
21026          */
21027         _onResize: function(e) {
21028             this._execOnAll("resetConstraints", []);
21029         },
21030
21031         /**
21032          * Lock all drag and drop functionality
21033          * @method lock
21034          * @static
21035          */
21036         lock: function() { this.locked = true; },
21037
21038         /**
21039          * Unlock all drag and drop functionality
21040          * @method unlock
21041          * @static
21042          */
21043         unlock: function() { this.locked = false; },
21044
21045         /**
21046          * Is drag and drop locked?
21047          * @method isLocked
21048          * @return {boolean} True if drag and drop is locked, false otherwise.
21049          * @static
21050          */
21051         isLocked: function() { return this.locked; },
21052
21053         /**
21054          * Location cache that is set for all drag drop objects when a drag is
21055          * initiated, cleared when the drag is finished.
21056          * @property locationCache
21057          * @private
21058          * @static
21059          */
21060         locationCache: {},
21061
21062         /**
21063          * Set useCache to false if you want to force object the lookup of each
21064          * drag and drop linked element constantly during a drag.
21065          * @property useCache
21066          * @type boolean
21067          * @static
21068          */
21069         useCache: true,
21070
21071         /**
21072          * The number of pixels that the mouse needs to move after the
21073          * mousedown before the drag is initiated.  Default=3;
21074          * @property clickPixelThresh
21075          * @type int
21076          * @static
21077          */
21078         clickPixelThresh: 3,
21079
21080         /**
21081          * The number of milliseconds after the mousedown event to initiate the
21082          * drag if we don't get a mouseup event. Default=1000
21083          * @property clickTimeThresh
21084          * @type int
21085          * @static
21086          */
21087         clickTimeThresh: 350,
21088
21089         /**
21090          * Flag that indicates that either the drag pixel threshold or the
21091          * mousdown time threshold has been met
21092          * @property dragThreshMet
21093          * @type boolean
21094          * @private
21095          * @static
21096          */
21097         dragThreshMet: false,
21098
21099         /**
21100          * Timeout used for the click time threshold
21101          * @property clickTimeout
21102          * @type Object
21103          * @private
21104          * @static
21105          */
21106         clickTimeout: null,
21107
21108         /**
21109          * The X position of the mousedown event stored for later use when a
21110          * drag threshold is met.
21111          * @property startX
21112          * @type int
21113          * @private
21114          * @static
21115          */
21116         startX: 0,
21117
21118         /**
21119          * The Y position of the mousedown event stored for later use when a
21120          * drag threshold is met.
21121          * @property startY
21122          * @type int
21123          * @private
21124          * @static
21125          */
21126         startY: 0,
21127
21128         /**
21129          * Each DragDrop instance must be registered with the DragDropMgr.
21130          * This is executed in DragDrop.init()
21131          * @method regDragDrop
21132          * @param {DragDrop} oDD the DragDrop object to register
21133          * @param {String} sGroup the name of the group this element belongs to
21134          * @static
21135          */
21136         regDragDrop: function(oDD, sGroup) {
21137             if (!this.initialized) { this.init(); }
21138
21139             if (!this.ids[sGroup]) {
21140                 this.ids[sGroup] = {};
21141             }
21142             this.ids[sGroup][oDD.id] = oDD;
21143         },
21144
21145         /**
21146          * Removes the supplied dd instance from the supplied group. Executed
21147          * by DragDrop.removeFromGroup, so don't call this function directly.
21148          * @method removeDDFromGroup
21149          * @private
21150          * @static
21151          */
21152         removeDDFromGroup: function(oDD, sGroup) {
21153             if (!this.ids[sGroup]) {
21154                 this.ids[sGroup] = {};
21155             }
21156
21157             var obj = this.ids[sGroup];
21158             if (obj && obj[oDD.id]) {
21159                 delete obj[oDD.id];
21160             }
21161         },
21162
21163         /**
21164          * Unregisters a drag and drop item.  This is executed in
21165          * DragDrop.unreg, use that method instead of calling this directly.
21166          * @method _remove
21167          * @private
21168          * @static
21169          */
21170         _remove: function(oDD) {
21171             for (var g in oDD.groups) {
21172                 if (g && this.ids[g][oDD.id]) {
21173                     delete this.ids[g][oDD.id];
21174                 }
21175             }
21176             delete this.handleIds[oDD.id];
21177         },
21178
21179         /**
21180          * Each DragDrop handle element must be registered.  This is done
21181          * automatically when executing DragDrop.setHandleElId()
21182          * @method regHandle
21183          * @param {String} sDDId the DragDrop id this element is a handle for
21184          * @param {String} sHandleId the id of the element that is the drag
21185          * handle
21186          * @static
21187          */
21188         regHandle: function(sDDId, sHandleId) {
21189             if (!this.handleIds[sDDId]) {
21190                 this.handleIds[sDDId] = {};
21191             }
21192             this.handleIds[sDDId][sHandleId] = sHandleId;
21193         },
21194
21195         /**
21196          * Utility function to determine if a given element has been
21197          * registered as a drag drop item.
21198          * @method isDragDrop
21199          * @param {String} id the element id to check
21200          * @return {boolean} true if this element is a DragDrop item,
21201          * false otherwise
21202          * @static
21203          */
21204         isDragDrop: function(id) {
21205             return ( this.getDDById(id) ) ? true : false;
21206         },
21207
21208         /**
21209          * Returns the drag and drop instances that are in all groups the
21210          * passed in instance belongs to.
21211          * @method getRelated
21212          * @param {DragDrop} p_oDD the obj to get related data for
21213          * @param {boolean} bTargetsOnly if true, only return targetable objs
21214          * @return {DragDrop[]} the related instances
21215          * @static
21216          */
21217         getRelated: function(p_oDD, bTargetsOnly) {
21218             var oDDs = [];
21219             for (var i in p_oDD.groups) {
21220                 for (j in this.ids[i]) {
21221                     var dd = this.ids[i][j];
21222                     if (! this.isTypeOfDD(dd)) {
21223                         continue;
21224                     }
21225                     if (!bTargetsOnly || dd.isTarget) {
21226                         oDDs[oDDs.length] = dd;
21227                     }
21228                 }
21229             }
21230
21231             return oDDs;
21232         },
21233
21234         /**
21235          * Returns true if the specified dd target is a legal target for
21236          * the specifice drag obj
21237          * @method isLegalTarget
21238          * @param {DragDrop} the drag obj
21239          * @param {DragDrop} the target
21240          * @return {boolean} true if the target is a legal target for the
21241          * dd obj
21242          * @static
21243          */
21244         isLegalTarget: function (oDD, oTargetDD) {
21245             var targets = this.getRelated(oDD, true);
21246             for (var i=0, len=targets.length;i<len;++i) {
21247                 if (targets[i].id == oTargetDD.id) {
21248                     return true;
21249                 }
21250             }
21251
21252             return false;
21253         },
21254
21255         /**
21256          * My goal is to be able to transparently determine if an object is
21257          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21258          * returns "object", oDD.constructor.toString() always returns
21259          * "DragDrop" and not the name of the subclass.  So for now it just
21260          * evaluates a well-known variable in DragDrop.
21261          * @method isTypeOfDD
21262          * @param {Object} the object to evaluate
21263          * @return {boolean} true if typeof oDD = DragDrop
21264          * @static
21265          */
21266         isTypeOfDD: function (oDD) {
21267             return (oDD && oDD.__ygDragDrop);
21268         },
21269
21270         /**
21271          * Utility function to determine if a given element has been
21272          * registered as a drag drop handle for the given Drag Drop object.
21273          * @method isHandle
21274          * @param {String} id the element id to check
21275          * @return {boolean} true if this element is a DragDrop handle, false
21276          * otherwise
21277          * @static
21278          */
21279         isHandle: function(sDDId, sHandleId) {
21280             return ( this.handleIds[sDDId] &&
21281                             this.handleIds[sDDId][sHandleId] );
21282         },
21283
21284         /**
21285          * Returns the DragDrop instance for a given id
21286          * @method getDDById
21287          * @param {String} id the id of the DragDrop object
21288          * @return {DragDrop} the drag drop object, null if it is not found
21289          * @static
21290          */
21291         getDDById: function(id) {
21292             for (var i in this.ids) {
21293                 if (this.ids[i][id]) {
21294                     return this.ids[i][id];
21295                 }
21296             }
21297             return null;
21298         },
21299
21300         /**
21301          * Fired after a registered DragDrop object gets the mousedown event.
21302          * Sets up the events required to track the object being dragged
21303          * @method handleMouseDown
21304          * @param {Event} e the event
21305          * @param oDD the DragDrop object being dragged
21306          * @private
21307          * @static
21308          */
21309         handleMouseDown: function(e, oDD) {
21310             if(Roo.QuickTips){
21311                 Roo.QuickTips.disable();
21312             }
21313             this.currentTarget = e.getTarget();
21314
21315             this.dragCurrent = oDD;
21316
21317             var el = oDD.getEl();
21318
21319             // track start position
21320             this.startX = e.getPageX();
21321             this.startY = e.getPageY();
21322
21323             this.deltaX = this.startX - el.offsetLeft;
21324             this.deltaY = this.startY - el.offsetTop;
21325
21326             this.dragThreshMet = false;
21327
21328             this.clickTimeout = setTimeout(
21329                     function() {
21330                         var DDM = Roo.dd.DDM;
21331                         DDM.startDrag(DDM.startX, DDM.startY);
21332                     },
21333                     this.clickTimeThresh );
21334         },
21335
21336         /**
21337          * Fired when either the drag pixel threshol or the mousedown hold
21338          * time threshold has been met.
21339          * @method startDrag
21340          * @param x {int} the X position of the original mousedown
21341          * @param y {int} the Y position of the original mousedown
21342          * @static
21343          */
21344         startDrag: function(x, y) {
21345             clearTimeout(this.clickTimeout);
21346             if (this.dragCurrent) {
21347                 this.dragCurrent.b4StartDrag(x, y);
21348                 this.dragCurrent.startDrag(x, y);
21349             }
21350             this.dragThreshMet = true;
21351         },
21352
21353         /**
21354          * Internal function to handle the mouseup event.  Will be invoked
21355          * from the context of the document.
21356          * @method handleMouseUp
21357          * @param {Event} e the event
21358          * @private
21359          * @static
21360          */
21361         handleMouseUp: function(e) {
21362
21363             if(Roo.QuickTips){
21364                 Roo.QuickTips.enable();
21365             }
21366             if (! this.dragCurrent) {
21367                 return;
21368             }
21369
21370             clearTimeout(this.clickTimeout);
21371
21372             if (this.dragThreshMet) {
21373                 this.fireEvents(e, true);
21374             } else {
21375             }
21376
21377             this.stopDrag(e);
21378
21379             this.stopEvent(e);
21380         },
21381
21382         /**
21383          * Utility to stop event propagation and event default, if these
21384          * features are turned on.
21385          * @method stopEvent
21386          * @param {Event} e the event as returned by this.getEvent()
21387          * @static
21388          */
21389         stopEvent: function(e){
21390             if(this.stopPropagation) {
21391                 e.stopPropagation();
21392             }
21393
21394             if (this.preventDefault) {
21395                 e.preventDefault();
21396             }
21397         },
21398
21399         /**
21400          * Internal function to clean up event handlers after the drag
21401          * operation is complete
21402          * @method stopDrag
21403          * @param {Event} e the event
21404          * @private
21405          * @static
21406          */
21407         stopDrag: function(e) {
21408             // Fire the drag end event for the item that was dragged
21409             if (this.dragCurrent) {
21410                 if (this.dragThreshMet) {
21411                     this.dragCurrent.b4EndDrag(e);
21412                     this.dragCurrent.endDrag(e);
21413                 }
21414
21415                 this.dragCurrent.onMouseUp(e);
21416             }
21417
21418             this.dragCurrent = null;
21419             this.dragOvers = {};
21420         },
21421
21422         /**
21423          * Internal function to handle the mousemove event.  Will be invoked
21424          * from the context of the html element.
21425          *
21426          * @TODO figure out what we can do about mouse events lost when the
21427          * user drags objects beyond the window boundary.  Currently we can
21428          * detect this in internet explorer by verifying that the mouse is
21429          * down during the mousemove event.  Firefox doesn't give us the
21430          * button state on the mousemove event.
21431          * @method handleMouseMove
21432          * @param {Event} e the event
21433          * @private
21434          * @static
21435          */
21436         handleMouseMove: function(e) {
21437             if (! this.dragCurrent) {
21438                 return true;
21439             }
21440
21441             // var button = e.which || e.button;
21442
21443             // check for IE mouseup outside of page boundary
21444             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21445                 this.stopEvent(e);
21446                 return this.handleMouseUp(e);
21447             }
21448
21449             if (!this.dragThreshMet) {
21450                 var diffX = Math.abs(this.startX - e.getPageX());
21451                 var diffY = Math.abs(this.startY - e.getPageY());
21452                 if (diffX > this.clickPixelThresh ||
21453                             diffY > this.clickPixelThresh) {
21454                     this.startDrag(this.startX, this.startY);
21455                 }
21456             }
21457
21458             if (this.dragThreshMet) {
21459                 this.dragCurrent.b4Drag(e);
21460                 this.dragCurrent.onDrag(e);
21461                 if(!this.dragCurrent.moveOnly){
21462                     this.fireEvents(e, false);
21463                 }
21464             }
21465
21466             this.stopEvent(e);
21467
21468             return true;
21469         },
21470
21471         /**
21472          * Iterates over all of the DragDrop elements to find ones we are
21473          * hovering over or dropping on
21474          * @method fireEvents
21475          * @param {Event} e the event
21476          * @param {boolean} isDrop is this a drop op or a mouseover op?
21477          * @private
21478          * @static
21479          */
21480         fireEvents: function(e, isDrop) {
21481             var dc = this.dragCurrent;
21482
21483             // If the user did the mouse up outside of the window, we could
21484             // get here even though we have ended the drag.
21485             if (!dc || dc.isLocked()) {
21486                 return;
21487             }
21488
21489             var pt = e.getPoint();
21490
21491             // cache the previous dragOver array
21492             var oldOvers = [];
21493
21494             var outEvts   = [];
21495             var overEvts  = [];
21496             var dropEvts  = [];
21497             var enterEvts = [];
21498
21499             // Check to see if the object(s) we were hovering over is no longer
21500             // being hovered over so we can fire the onDragOut event
21501             for (var i in this.dragOvers) {
21502
21503                 var ddo = this.dragOvers[i];
21504
21505                 if (! this.isTypeOfDD(ddo)) {
21506                     continue;
21507                 }
21508
21509                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21510                     outEvts.push( ddo );
21511                 }
21512
21513                 oldOvers[i] = true;
21514                 delete this.dragOvers[i];
21515             }
21516
21517             for (var sGroup in dc.groups) {
21518
21519                 if ("string" != typeof sGroup) {
21520                     continue;
21521                 }
21522
21523                 for (i in this.ids[sGroup]) {
21524                     var oDD = this.ids[sGroup][i];
21525                     if (! this.isTypeOfDD(oDD)) {
21526                         continue;
21527                     }
21528
21529                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21530                         if (this.isOverTarget(pt, oDD, this.mode)) {
21531                             // look for drop interactions
21532                             if (isDrop) {
21533                                 dropEvts.push( oDD );
21534                             // look for drag enter and drag over interactions
21535                             } else {
21536
21537                                 // initial drag over: dragEnter fires
21538                                 if (!oldOvers[oDD.id]) {
21539                                     enterEvts.push( oDD );
21540                                 // subsequent drag overs: dragOver fires
21541                                 } else {
21542                                     overEvts.push( oDD );
21543                                 }
21544
21545                                 this.dragOvers[oDD.id] = oDD;
21546                             }
21547                         }
21548                     }
21549                 }
21550             }
21551
21552             if (this.mode) {
21553                 if (outEvts.length) {
21554                     dc.b4DragOut(e, outEvts);
21555                     dc.onDragOut(e, outEvts);
21556                 }
21557
21558                 if (enterEvts.length) {
21559                     dc.onDragEnter(e, enterEvts);
21560                 }
21561
21562                 if (overEvts.length) {
21563                     dc.b4DragOver(e, overEvts);
21564                     dc.onDragOver(e, overEvts);
21565                 }
21566
21567                 if (dropEvts.length) {
21568                     dc.b4DragDrop(e, dropEvts);
21569                     dc.onDragDrop(e, dropEvts);
21570                 }
21571
21572             } else {
21573                 // fire dragout events
21574                 var len = 0;
21575                 for (i=0, len=outEvts.length; i<len; ++i) {
21576                     dc.b4DragOut(e, outEvts[i].id);
21577                     dc.onDragOut(e, outEvts[i].id);
21578                 }
21579
21580                 // fire enter events
21581                 for (i=0,len=enterEvts.length; i<len; ++i) {
21582                     // dc.b4DragEnter(e, oDD.id);
21583                     dc.onDragEnter(e, enterEvts[i].id);
21584                 }
21585
21586                 // fire over events
21587                 for (i=0,len=overEvts.length; i<len; ++i) {
21588                     dc.b4DragOver(e, overEvts[i].id);
21589                     dc.onDragOver(e, overEvts[i].id);
21590                 }
21591
21592                 // fire drop events
21593                 for (i=0, len=dropEvts.length; i<len; ++i) {
21594                     dc.b4DragDrop(e, dropEvts[i].id);
21595                     dc.onDragDrop(e, dropEvts[i].id);
21596                 }
21597
21598             }
21599
21600             // notify about a drop that did not find a target
21601             if (isDrop && !dropEvts.length) {
21602                 dc.onInvalidDrop(e);
21603             }
21604
21605         },
21606
21607         /**
21608          * Helper function for getting the best match from the list of drag
21609          * and drop objects returned by the drag and drop events when we are
21610          * in INTERSECT mode.  It returns either the first object that the
21611          * cursor is over, or the object that has the greatest overlap with
21612          * the dragged element.
21613          * @method getBestMatch
21614          * @param  {DragDrop[]} dds The array of drag and drop objects
21615          * targeted
21616          * @return {DragDrop}       The best single match
21617          * @static
21618          */
21619         getBestMatch: function(dds) {
21620             var winner = null;
21621             // Return null if the input is not what we expect
21622             //if (!dds || !dds.length || dds.length == 0) {
21623                // winner = null;
21624             // If there is only one item, it wins
21625             //} else if (dds.length == 1) {
21626
21627             var len = dds.length;
21628
21629             if (len == 1) {
21630                 winner = dds[0];
21631             } else {
21632                 // Loop through the targeted items
21633                 for (var i=0; i<len; ++i) {
21634                     var dd = dds[i];
21635                     // If the cursor is over the object, it wins.  If the
21636                     // cursor is over multiple matches, the first one we come
21637                     // to wins.
21638                     if (dd.cursorIsOver) {
21639                         winner = dd;
21640                         break;
21641                     // Otherwise the object with the most overlap wins
21642                     } else {
21643                         if (!winner ||
21644                             winner.overlap.getArea() < dd.overlap.getArea()) {
21645                             winner = dd;
21646                         }
21647                     }
21648                 }
21649             }
21650
21651             return winner;
21652         },
21653
21654         /**
21655          * Refreshes the cache of the top-left and bottom-right points of the
21656          * drag and drop objects in the specified group(s).  This is in the
21657          * format that is stored in the drag and drop instance, so typical
21658          * usage is:
21659          * <code>
21660          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21661          * </code>
21662          * Alternatively:
21663          * <code>
21664          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21665          * </code>
21666          * @TODO this really should be an indexed array.  Alternatively this
21667          * method could accept both.
21668          * @method refreshCache
21669          * @param {Object} groups an associative array of groups to refresh
21670          * @static
21671          */
21672         refreshCache: function(groups) {
21673             for (var sGroup in groups) {
21674                 if ("string" != typeof sGroup) {
21675                     continue;
21676                 }
21677                 for (var i in this.ids[sGroup]) {
21678                     var oDD = this.ids[sGroup][i];
21679
21680                     if (this.isTypeOfDD(oDD)) {
21681                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21682                         var loc = this.getLocation(oDD);
21683                         if (loc) {
21684                             this.locationCache[oDD.id] = loc;
21685                         } else {
21686                             delete this.locationCache[oDD.id];
21687                             // this will unregister the drag and drop object if
21688                             // the element is not in a usable state
21689                             // oDD.unreg();
21690                         }
21691                     }
21692                 }
21693             }
21694         },
21695
21696         /**
21697          * This checks to make sure an element exists and is in the DOM.  The
21698          * main purpose is to handle cases where innerHTML is used to remove
21699          * drag and drop objects from the DOM.  IE provides an 'unspecified
21700          * error' when trying to access the offsetParent of such an element
21701          * @method verifyEl
21702          * @param {HTMLElement} el the element to check
21703          * @return {boolean} true if the element looks usable
21704          * @static
21705          */
21706         verifyEl: function(el) {
21707             if (el) {
21708                 var parent;
21709                 if(Roo.isIE){
21710                     try{
21711                         parent = el.offsetParent;
21712                     }catch(e){}
21713                 }else{
21714                     parent = el.offsetParent;
21715                 }
21716                 if (parent) {
21717                     return true;
21718                 }
21719             }
21720
21721             return false;
21722         },
21723
21724         /**
21725          * Returns a Region object containing the drag and drop element's position
21726          * and size, including the padding configured for it
21727          * @method getLocation
21728          * @param {DragDrop} oDD the drag and drop object to get the
21729          *                       location for
21730          * @return {Roo.lib.Region} a Region object representing the total area
21731          *                             the element occupies, including any padding
21732          *                             the instance is configured for.
21733          * @static
21734          */
21735         getLocation: function(oDD) {
21736             if (! this.isTypeOfDD(oDD)) {
21737                 return null;
21738             }
21739
21740             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21741
21742             try {
21743                 pos= Roo.lib.Dom.getXY(el);
21744             } catch (e) { }
21745
21746             if (!pos) {
21747                 return null;
21748             }
21749
21750             x1 = pos[0];
21751             x2 = x1 + el.offsetWidth;
21752             y1 = pos[1];
21753             y2 = y1 + el.offsetHeight;
21754
21755             t = y1 - oDD.padding[0];
21756             r = x2 + oDD.padding[1];
21757             b = y2 + oDD.padding[2];
21758             l = x1 - oDD.padding[3];
21759
21760             return new Roo.lib.Region( t, r, b, l );
21761         },
21762
21763         /**
21764          * Checks the cursor location to see if it over the target
21765          * @method isOverTarget
21766          * @param {Roo.lib.Point} pt The point to evaluate
21767          * @param {DragDrop} oTarget the DragDrop object we are inspecting
21768          * @return {boolean} true if the mouse is over the target
21769          * @private
21770          * @static
21771          */
21772         isOverTarget: function(pt, oTarget, intersect) {
21773             // use cache if available
21774             var loc = this.locationCache[oTarget.id];
21775             if (!loc || !this.useCache) {
21776                 loc = this.getLocation(oTarget);
21777                 this.locationCache[oTarget.id] = loc;
21778
21779             }
21780
21781             if (!loc) {
21782                 return false;
21783             }
21784
21785             oTarget.cursorIsOver = loc.contains( pt );
21786
21787             // DragDrop is using this as a sanity check for the initial mousedown
21788             // in this case we are done.  In POINT mode, if the drag obj has no
21789             // contraints, we are also done. Otherwise we need to evaluate the
21790             // location of the target as related to the actual location of the
21791             // dragged element.
21792             var dc = this.dragCurrent;
21793             if (!dc || !dc.getTargetCoord ||
21794                     (!intersect && !dc.constrainX && !dc.constrainY)) {
21795                 return oTarget.cursorIsOver;
21796             }
21797
21798             oTarget.overlap = null;
21799
21800             // Get the current location of the drag element, this is the
21801             // location of the mouse event less the delta that represents
21802             // where the original mousedown happened on the element.  We
21803             // need to consider constraints and ticks as well.
21804             var pos = dc.getTargetCoord(pt.x, pt.y);
21805
21806             var el = dc.getDragEl();
21807             var curRegion = new Roo.lib.Region( pos.y,
21808                                                    pos.x + el.offsetWidth,
21809                                                    pos.y + el.offsetHeight,
21810                                                    pos.x );
21811
21812             var overlap = curRegion.intersect(loc);
21813
21814             if (overlap) {
21815                 oTarget.overlap = overlap;
21816                 return (intersect) ? true : oTarget.cursorIsOver;
21817             } else {
21818                 return false;
21819             }
21820         },
21821
21822         /**
21823          * unload event handler
21824          * @method _onUnload
21825          * @private
21826          * @static
21827          */
21828         _onUnload: function(e, me) {
21829             Roo.dd.DragDropMgr.unregAll();
21830         },
21831
21832         /**
21833          * Cleans up the drag and drop events and objects.
21834          * @method unregAll
21835          * @private
21836          * @static
21837          */
21838         unregAll: function() {
21839
21840             if (this.dragCurrent) {
21841                 this.stopDrag();
21842                 this.dragCurrent = null;
21843             }
21844
21845             this._execOnAll("unreg", []);
21846
21847             for (i in this.elementCache) {
21848                 delete this.elementCache[i];
21849             }
21850
21851             this.elementCache = {};
21852             this.ids = {};
21853         },
21854
21855         /**
21856          * A cache of DOM elements
21857          * @property elementCache
21858          * @private
21859          * @static
21860          */
21861         elementCache: {},
21862
21863         /**
21864          * Get the wrapper for the DOM element specified
21865          * @method getElWrapper
21866          * @param {String} id the id of the element to get
21867          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21868          * @private
21869          * @deprecated This wrapper isn't that useful
21870          * @static
21871          */
21872         getElWrapper: function(id) {
21873             var oWrapper = this.elementCache[id];
21874             if (!oWrapper || !oWrapper.el) {
21875                 oWrapper = this.elementCache[id] =
21876                     new this.ElementWrapper(Roo.getDom(id));
21877             }
21878             return oWrapper;
21879         },
21880
21881         /**
21882          * Returns the actual DOM element
21883          * @method getElement
21884          * @param {String} id the id of the elment to get
21885          * @return {Object} The element
21886          * @deprecated use Roo.getDom instead
21887          * @static
21888          */
21889         getElement: function(id) {
21890             return Roo.getDom(id);
21891         },
21892
21893         /**
21894          * Returns the style property for the DOM element (i.e.,
21895          * document.getElById(id).style)
21896          * @method getCss
21897          * @param {String} id the id of the elment to get
21898          * @return {Object} The style property of the element
21899          * @deprecated use Roo.getDom instead
21900          * @static
21901          */
21902         getCss: function(id) {
21903             var el = Roo.getDom(id);
21904             return (el) ? el.style : null;
21905         },
21906
21907         /**
21908          * Inner class for cached elements
21909          * @class DragDropMgr.ElementWrapper
21910          * @for DragDropMgr
21911          * @private
21912          * @deprecated
21913          */
21914         ElementWrapper: function(el) {
21915                 /**
21916                  * The element
21917                  * @property el
21918                  */
21919                 this.el = el || null;
21920                 /**
21921                  * The element id
21922                  * @property id
21923                  */
21924                 this.id = this.el && el.id;
21925                 /**
21926                  * A reference to the style property
21927                  * @property css
21928                  */
21929                 this.css = this.el && el.style;
21930             },
21931
21932         /**
21933          * Returns the X position of an html element
21934          * @method getPosX
21935          * @param el the element for which to get the position
21936          * @return {int} the X coordinate
21937          * @for DragDropMgr
21938          * @deprecated use Roo.lib.Dom.getX instead
21939          * @static
21940          */
21941         getPosX: function(el) {
21942             return Roo.lib.Dom.getX(el);
21943         },
21944
21945         /**
21946          * Returns the Y position of an html element
21947          * @method getPosY
21948          * @param el the element for which to get the position
21949          * @return {int} the Y coordinate
21950          * @deprecated use Roo.lib.Dom.getY instead
21951          * @static
21952          */
21953         getPosY: function(el) {
21954             return Roo.lib.Dom.getY(el);
21955         },
21956
21957         /**
21958          * Swap two nodes.  In IE, we use the native method, for others we
21959          * emulate the IE behavior
21960          * @method swapNode
21961          * @param n1 the first node to swap
21962          * @param n2 the other node to swap
21963          * @static
21964          */
21965         swapNode: function(n1, n2) {
21966             if (n1.swapNode) {
21967                 n1.swapNode(n2);
21968             } else {
21969                 var p = n2.parentNode;
21970                 var s = n2.nextSibling;
21971
21972                 if (s == n1) {
21973                     p.insertBefore(n1, n2);
21974                 } else if (n2 == n1.nextSibling) {
21975                     p.insertBefore(n2, n1);
21976                 } else {
21977                     n1.parentNode.replaceChild(n2, n1);
21978                     p.insertBefore(n1, s);
21979                 }
21980             }
21981         },
21982
21983         /**
21984          * Returns the current scroll position
21985          * @method getScroll
21986          * @private
21987          * @static
21988          */
21989         getScroll: function () {
21990             var t, l, dde=document.documentElement, db=document.body;
21991             if (dde && (dde.scrollTop || dde.scrollLeft)) {
21992                 t = dde.scrollTop;
21993                 l = dde.scrollLeft;
21994             } else if (db) {
21995                 t = db.scrollTop;
21996                 l = db.scrollLeft;
21997             } else {
21998
21999             }
22000             return { top: t, left: l };
22001         },
22002
22003         /**
22004          * Returns the specified element style property
22005          * @method getStyle
22006          * @param {HTMLElement} el          the element
22007          * @param {string}      styleProp   the style property
22008          * @return {string} The value of the style property
22009          * @deprecated use Roo.lib.Dom.getStyle
22010          * @static
22011          */
22012         getStyle: function(el, styleProp) {
22013             return Roo.fly(el).getStyle(styleProp);
22014         },
22015
22016         /**
22017          * Gets the scrollTop
22018          * @method getScrollTop
22019          * @return {int} the document's scrollTop
22020          * @static
22021          */
22022         getScrollTop: function () { return this.getScroll().top; },
22023
22024         /**
22025          * Gets the scrollLeft
22026          * @method getScrollLeft
22027          * @return {int} the document's scrollTop
22028          * @static
22029          */
22030         getScrollLeft: function () { return this.getScroll().left; },
22031
22032         /**
22033          * Sets the x/y position of an element to the location of the
22034          * target element.
22035          * @method moveToEl
22036          * @param {HTMLElement} moveEl      The element to move
22037          * @param {HTMLElement} targetEl    The position reference element
22038          * @static
22039          */
22040         moveToEl: function (moveEl, targetEl) {
22041             var aCoord = Roo.lib.Dom.getXY(targetEl);
22042             Roo.lib.Dom.setXY(moveEl, aCoord);
22043         },
22044
22045         /**
22046          * Numeric array sort function
22047          * @method numericSort
22048          * @static
22049          */
22050         numericSort: function(a, b) { return (a - b); },
22051
22052         /**
22053          * Internal counter
22054          * @property _timeoutCount
22055          * @private
22056          * @static
22057          */
22058         _timeoutCount: 0,
22059
22060         /**
22061          * Trying to make the load order less important.  Without this we get
22062          * an error if this file is loaded before the Event Utility.
22063          * @method _addListeners
22064          * @private
22065          * @static
22066          */
22067         _addListeners: function() {
22068             var DDM = Roo.dd.DDM;
22069             if ( Roo.lib.Event && document ) {
22070                 DDM._onLoad();
22071             } else {
22072                 if (DDM._timeoutCount > 2000) {
22073                 } else {
22074                     setTimeout(DDM._addListeners, 10);
22075                     if (document && document.body) {
22076                         DDM._timeoutCount += 1;
22077                     }
22078                 }
22079             }
22080         },
22081
22082         /**
22083          * Recursively searches the immediate parent and all child nodes for
22084          * the handle element in order to determine wheter or not it was
22085          * clicked.
22086          * @method handleWasClicked
22087          * @param node the html element to inspect
22088          * @static
22089          */
22090         handleWasClicked: function(node, id) {
22091             if (this.isHandle(id, node.id)) {
22092                 return true;
22093             } else {
22094                 // check to see if this is a text node child of the one we want
22095                 var p = node.parentNode;
22096
22097                 while (p) {
22098                     if (this.isHandle(id, p.id)) {
22099                         return true;
22100                     } else {
22101                         p = p.parentNode;
22102                     }
22103                 }
22104             }
22105
22106             return false;
22107         }
22108
22109     };
22110
22111 }();
22112
22113 // shorter alias, save a few bytes
22114 Roo.dd.DDM = Roo.dd.DragDropMgr;
22115 Roo.dd.DDM._addListeners();
22116
22117 }/*
22118  * Based on:
22119  * Ext JS Library 1.1.1
22120  * Copyright(c) 2006-2007, Ext JS, LLC.
22121  *
22122  * Originally Released Under LGPL - original licence link has changed is not relivant.
22123  *
22124  * Fork - LGPL
22125  * <script type="text/javascript">
22126  */
22127
22128 /**
22129  * @class Roo.dd.DD
22130  * A DragDrop implementation where the linked element follows the
22131  * mouse cursor during a drag.
22132  * @extends Roo.dd.DragDrop
22133  * @constructor
22134  * @param {String} id the id of the linked element
22135  * @param {String} sGroup the group of related DragDrop items
22136  * @param {object} config an object containing configurable attributes
22137  *                Valid properties for DD:
22138  *                    scroll
22139  */
22140 Roo.dd.DD = function(id, sGroup, config) {
22141     if (id) {
22142         this.init(id, sGroup, config);
22143     }
22144 };
22145
22146 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22147
22148     /**
22149      * When set to true, the utility automatically tries to scroll the browser
22150      * window wehn a drag and drop element is dragged near the viewport boundary.
22151      * Defaults to true.
22152      * @property scroll
22153      * @type boolean
22154      */
22155     scroll: true,
22156
22157     /**
22158      * Sets the pointer offset to the distance between the linked element's top
22159      * left corner and the location the element was clicked
22160      * @method autoOffset
22161      * @param {int} iPageX the X coordinate of the click
22162      * @param {int} iPageY the Y coordinate of the click
22163      */
22164     autoOffset: function(iPageX, iPageY) {
22165         var x = iPageX - this.startPageX;
22166         var y = iPageY - this.startPageY;
22167         this.setDelta(x, y);
22168     },
22169
22170     /**
22171      * Sets the pointer offset.  You can call this directly to force the
22172      * offset to be in a particular location (e.g., pass in 0,0 to set it
22173      * to the center of the object)
22174      * @method setDelta
22175      * @param {int} iDeltaX the distance from the left
22176      * @param {int} iDeltaY the distance from the top
22177      */
22178     setDelta: function(iDeltaX, iDeltaY) {
22179         this.deltaX = iDeltaX;
22180         this.deltaY = iDeltaY;
22181     },
22182
22183     /**
22184      * Sets the drag element to the location of the mousedown or click event,
22185      * maintaining the cursor location relative to the location on the element
22186      * that was clicked.  Override this if you want to place the element in a
22187      * location other than where the cursor is.
22188      * @method setDragElPos
22189      * @param {int} iPageX the X coordinate of the mousedown or drag event
22190      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22191      */
22192     setDragElPos: function(iPageX, iPageY) {
22193         // the first time we do this, we are going to check to make sure
22194         // the element has css positioning
22195
22196         var el = this.getDragEl();
22197         this.alignElWithMouse(el, iPageX, iPageY);
22198     },
22199
22200     /**
22201      * Sets the element to the location of the mousedown or click event,
22202      * maintaining the cursor location relative to the location on the element
22203      * that was clicked.  Override this if you want to place the element in a
22204      * location other than where the cursor is.
22205      * @method alignElWithMouse
22206      * @param {HTMLElement} el the element to move
22207      * @param {int} iPageX the X coordinate of the mousedown or drag event
22208      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22209      */
22210     alignElWithMouse: function(el, iPageX, iPageY) {
22211         var oCoord = this.getTargetCoord(iPageX, iPageY);
22212         var fly = el.dom ? el : Roo.fly(el);
22213         if (!this.deltaSetXY) {
22214             var aCoord = [oCoord.x, oCoord.y];
22215             fly.setXY(aCoord);
22216             var newLeft = fly.getLeft(true);
22217             var newTop  = fly.getTop(true);
22218             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22219         } else {
22220             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22221         }
22222
22223         this.cachePosition(oCoord.x, oCoord.y);
22224         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22225         return oCoord;
22226     },
22227
22228     /**
22229      * Saves the most recent position so that we can reset the constraints and
22230      * tick marks on-demand.  We need to know this so that we can calculate the
22231      * number of pixels the element is offset from its original position.
22232      * @method cachePosition
22233      * @param iPageX the current x position (optional, this just makes it so we
22234      * don't have to look it up again)
22235      * @param iPageY the current y position (optional, this just makes it so we
22236      * don't have to look it up again)
22237      */
22238     cachePosition: function(iPageX, iPageY) {
22239         if (iPageX) {
22240             this.lastPageX = iPageX;
22241             this.lastPageY = iPageY;
22242         } else {
22243             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22244             this.lastPageX = aCoord[0];
22245             this.lastPageY = aCoord[1];
22246         }
22247     },
22248
22249     /**
22250      * Auto-scroll the window if the dragged object has been moved beyond the
22251      * visible window boundary.
22252      * @method autoScroll
22253      * @param {int} x the drag element's x position
22254      * @param {int} y the drag element's y position
22255      * @param {int} h the height of the drag element
22256      * @param {int} w the width of the drag element
22257      * @private
22258      */
22259     autoScroll: function(x, y, h, w) {
22260
22261         if (this.scroll) {
22262             // The client height
22263             var clientH = Roo.lib.Dom.getViewWidth();
22264
22265             // The client width
22266             var clientW = Roo.lib.Dom.getViewHeight();
22267
22268             // The amt scrolled down
22269             var st = this.DDM.getScrollTop();
22270
22271             // The amt scrolled right
22272             var sl = this.DDM.getScrollLeft();
22273
22274             // Location of the bottom of the element
22275             var bot = h + y;
22276
22277             // Location of the right of the element
22278             var right = w + x;
22279
22280             // The distance from the cursor to the bottom of the visible area,
22281             // adjusted so that we don't scroll if the cursor is beyond the
22282             // element drag constraints
22283             var toBot = (clientH + st - y - this.deltaY);
22284
22285             // The distance from the cursor to the right of the visible area
22286             var toRight = (clientW + sl - x - this.deltaX);
22287
22288
22289             // How close to the edge the cursor must be before we scroll
22290             // var thresh = (document.all) ? 100 : 40;
22291             var thresh = 40;
22292
22293             // How many pixels to scroll per autoscroll op.  This helps to reduce
22294             // clunky scrolling. IE is more sensitive about this ... it needs this
22295             // value to be higher.
22296             var scrAmt = (document.all) ? 80 : 30;
22297
22298             // Scroll down if we are near the bottom of the visible page and the
22299             // obj extends below the crease
22300             if ( bot > clientH && toBot < thresh ) {
22301                 window.scrollTo(sl, st + scrAmt);
22302             }
22303
22304             // Scroll up if the window is scrolled down and the top of the object
22305             // goes above the top border
22306             if ( y < st && st > 0 && y - st < thresh ) {
22307                 window.scrollTo(sl, st - scrAmt);
22308             }
22309
22310             // Scroll right if the obj is beyond the right border and the cursor is
22311             // near the border.
22312             if ( right > clientW && toRight < thresh ) {
22313                 window.scrollTo(sl + scrAmt, st);
22314             }
22315
22316             // Scroll left if the window has been scrolled to the right and the obj
22317             // extends past the left border
22318             if ( x < sl && sl > 0 && x - sl < thresh ) {
22319                 window.scrollTo(sl - scrAmt, st);
22320             }
22321         }
22322     },
22323
22324     /**
22325      * Finds the location the element should be placed if we want to move
22326      * it to where the mouse location less the click offset would place us.
22327      * @method getTargetCoord
22328      * @param {int} iPageX the X coordinate of the click
22329      * @param {int} iPageY the Y coordinate of the click
22330      * @return an object that contains the coordinates (Object.x and Object.y)
22331      * @private
22332      */
22333     getTargetCoord: function(iPageX, iPageY) {
22334
22335
22336         var x = iPageX - this.deltaX;
22337         var y = iPageY - this.deltaY;
22338
22339         if (this.constrainX) {
22340             if (x < this.minX) { x = this.minX; }
22341             if (x > this.maxX) { x = this.maxX; }
22342         }
22343
22344         if (this.constrainY) {
22345             if (y < this.minY) { y = this.minY; }
22346             if (y > this.maxY) { y = this.maxY; }
22347         }
22348
22349         x = this.getTick(x, this.xTicks);
22350         y = this.getTick(y, this.yTicks);
22351
22352
22353         return {x:x, y:y};
22354     },
22355
22356     /*
22357      * Sets up config options specific to this class. Overrides
22358      * Roo.dd.DragDrop, but all versions of this method through the
22359      * inheritance chain are called
22360      */
22361     applyConfig: function() {
22362         Roo.dd.DD.superclass.applyConfig.call(this);
22363         this.scroll = (this.config.scroll !== false);
22364     },
22365
22366     /*
22367      * Event that fires prior to the onMouseDown event.  Overrides
22368      * Roo.dd.DragDrop.
22369      */
22370     b4MouseDown: function(e) {
22371         // this.resetConstraints();
22372         this.autoOffset(e.getPageX(),
22373                             e.getPageY());
22374     },
22375
22376     /*
22377      * Event that fires prior to the onDrag event.  Overrides
22378      * Roo.dd.DragDrop.
22379      */
22380     b4Drag: function(e) {
22381         this.setDragElPos(e.getPageX(),
22382                             e.getPageY());
22383     },
22384
22385     toString: function() {
22386         return ("DD " + this.id);
22387     }
22388
22389     //////////////////////////////////////////////////////////////////////////
22390     // Debugging ygDragDrop events that can be overridden
22391     //////////////////////////////////////////////////////////////////////////
22392     /*
22393     startDrag: function(x, y) {
22394     },
22395
22396     onDrag: function(e) {
22397     },
22398
22399     onDragEnter: function(e, id) {
22400     },
22401
22402     onDragOver: function(e, id) {
22403     },
22404
22405     onDragOut: function(e, id) {
22406     },
22407
22408     onDragDrop: function(e, id) {
22409     },
22410
22411     endDrag: function(e) {
22412     }
22413
22414     */
22415
22416 });/*
22417  * Based on:
22418  * Ext JS Library 1.1.1
22419  * Copyright(c) 2006-2007, Ext JS, LLC.
22420  *
22421  * Originally Released Under LGPL - original licence link has changed is not relivant.
22422  *
22423  * Fork - LGPL
22424  * <script type="text/javascript">
22425  */
22426
22427 /**
22428  * @class Roo.dd.DDProxy
22429  * A DragDrop implementation that inserts an empty, bordered div into
22430  * the document that follows the cursor during drag operations.  At the time of
22431  * the click, the frame div is resized to the dimensions of the linked html
22432  * element, and moved to the exact location of the linked element.
22433  *
22434  * References to the "frame" element refer to the single proxy element that
22435  * was created to be dragged in place of all DDProxy elements on the
22436  * page.
22437  *
22438  * @extends Roo.dd.DD
22439  * @constructor
22440  * @param {String} id the id of the linked html element
22441  * @param {String} sGroup the group of related DragDrop objects
22442  * @param {object} config an object containing configurable attributes
22443  *                Valid properties for DDProxy in addition to those in DragDrop:
22444  *                   resizeFrame, centerFrame, dragElId
22445  */
22446 Roo.dd.DDProxy = function(id, sGroup, config) {
22447     if (id) {
22448         this.init(id, sGroup, config);
22449         this.initFrame();
22450     }
22451 };
22452
22453 /**
22454  * The default drag frame div id
22455  * @property Roo.dd.DDProxy.dragElId
22456  * @type String
22457  * @static
22458  */
22459 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22460
22461 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22462
22463     /**
22464      * By default we resize the drag frame to be the same size as the element
22465      * we want to drag (this is to get the frame effect).  We can turn it off
22466      * if we want a different behavior.
22467      * @property resizeFrame
22468      * @type boolean
22469      */
22470     resizeFrame: true,
22471
22472     /**
22473      * By default the frame is positioned exactly where the drag element is, so
22474      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22475      * you do not have constraints on the obj is to have the drag frame centered
22476      * around the cursor.  Set centerFrame to true for this effect.
22477      * @property centerFrame
22478      * @type boolean
22479      */
22480     centerFrame: false,
22481
22482     /**
22483      * Creates the proxy element if it does not yet exist
22484      * @method createFrame
22485      */
22486     createFrame: function() {
22487         var self = this;
22488         var body = document.body;
22489
22490         if (!body || !body.firstChild) {
22491             setTimeout( function() { self.createFrame(); }, 50 );
22492             return;
22493         }
22494
22495         var div = this.getDragEl();
22496
22497         if (!div) {
22498             div    = document.createElement("div");
22499             div.id = this.dragElId;
22500             var s  = div.style;
22501
22502             s.position   = "absolute";
22503             s.visibility = "hidden";
22504             s.cursor     = "move";
22505             s.border     = "2px solid #aaa";
22506             s.zIndex     = 999;
22507
22508             // appendChild can blow up IE if invoked prior to the window load event
22509             // while rendering a table.  It is possible there are other scenarios
22510             // that would cause this to happen as well.
22511             body.insertBefore(div, body.firstChild);
22512         }
22513     },
22514
22515     /**
22516      * Initialization for the drag frame element.  Must be called in the
22517      * constructor of all subclasses
22518      * @method initFrame
22519      */
22520     initFrame: function() {
22521         this.createFrame();
22522     },
22523
22524     applyConfig: function() {
22525         Roo.dd.DDProxy.superclass.applyConfig.call(this);
22526
22527         this.resizeFrame = (this.config.resizeFrame !== false);
22528         this.centerFrame = (this.config.centerFrame);
22529         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22530     },
22531
22532     /**
22533      * Resizes the drag frame to the dimensions of the clicked object, positions
22534      * it over the object, and finally displays it
22535      * @method showFrame
22536      * @param {int} iPageX X click position
22537      * @param {int} iPageY Y click position
22538      * @private
22539      */
22540     showFrame: function(iPageX, iPageY) {
22541         var el = this.getEl();
22542         var dragEl = this.getDragEl();
22543         var s = dragEl.style;
22544
22545         this._resizeProxy();
22546
22547         if (this.centerFrame) {
22548             this.setDelta( Math.round(parseInt(s.width,  10)/2),
22549                            Math.round(parseInt(s.height, 10)/2) );
22550         }
22551
22552         this.setDragElPos(iPageX, iPageY);
22553
22554         Roo.fly(dragEl).show();
22555     },
22556
22557     /**
22558      * The proxy is automatically resized to the dimensions of the linked
22559      * element when a drag is initiated, unless resizeFrame is set to false
22560      * @method _resizeProxy
22561      * @private
22562      */
22563     _resizeProxy: function() {
22564         if (this.resizeFrame) {
22565             var el = this.getEl();
22566             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22567         }
22568     },
22569
22570     // overrides Roo.dd.DragDrop
22571     b4MouseDown: function(e) {
22572         var x = e.getPageX();
22573         var y = e.getPageY();
22574         this.autoOffset(x, y);
22575         this.setDragElPos(x, y);
22576     },
22577
22578     // overrides Roo.dd.DragDrop
22579     b4StartDrag: function(x, y) {
22580         // show the drag frame
22581         this.showFrame(x, y);
22582     },
22583
22584     // overrides Roo.dd.DragDrop
22585     b4EndDrag: function(e) {
22586         Roo.fly(this.getDragEl()).hide();
22587     },
22588
22589     // overrides Roo.dd.DragDrop
22590     // By default we try to move the element to the last location of the frame.
22591     // This is so that the default behavior mirrors that of Roo.dd.DD.
22592     endDrag: function(e) {
22593
22594         var lel = this.getEl();
22595         var del = this.getDragEl();
22596
22597         // Show the drag frame briefly so we can get its position
22598         del.style.visibility = "";
22599
22600         this.beforeMove();
22601         // Hide the linked element before the move to get around a Safari
22602         // rendering bug.
22603         lel.style.visibility = "hidden";
22604         Roo.dd.DDM.moveToEl(lel, del);
22605         del.style.visibility = "hidden";
22606         lel.style.visibility = "";
22607
22608         this.afterDrag();
22609     },
22610
22611     beforeMove : function(){
22612
22613     },
22614
22615     afterDrag : function(){
22616
22617     },
22618
22619     toString: function() {
22620         return ("DDProxy " + this.id);
22621     }
22622
22623 });
22624 /*
22625  * Based on:
22626  * Ext JS Library 1.1.1
22627  * Copyright(c) 2006-2007, Ext JS, LLC.
22628  *
22629  * Originally Released Under LGPL - original licence link has changed is not relivant.
22630  *
22631  * Fork - LGPL
22632  * <script type="text/javascript">
22633  */
22634
22635  /**
22636  * @class Roo.dd.DDTarget
22637  * A DragDrop implementation that does not move, but can be a drop
22638  * target.  You would get the same result by simply omitting implementation
22639  * for the event callbacks, but this way we reduce the processing cost of the
22640  * event listener and the callbacks.
22641  * @extends Roo.dd.DragDrop
22642  * @constructor
22643  * @param {String} id the id of the element that is a drop target
22644  * @param {String} sGroup the group of related DragDrop objects
22645  * @param {object} config an object containing configurable attributes
22646  *                 Valid properties for DDTarget in addition to those in
22647  *                 DragDrop:
22648  *                    none
22649  */
22650 Roo.dd.DDTarget = function(id, sGroup, config) {
22651     if (id) {
22652         this.initTarget(id, sGroup, config);
22653     }
22654     if (config && (config.listeners || config.events)) { 
22655         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
22656             listeners : config.listeners || {}, 
22657             events : config.events || {} 
22658         });    
22659     }
22660 };
22661
22662 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22663 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22664     toString: function() {
22665         return ("DDTarget " + this.id);
22666     }
22667 });
22668 /*
22669  * Based on:
22670  * Ext JS Library 1.1.1
22671  * Copyright(c) 2006-2007, Ext JS, LLC.
22672  *
22673  * Originally Released Under LGPL - original licence link has changed is not relivant.
22674  *
22675  * Fork - LGPL
22676  * <script type="text/javascript">
22677  */
22678  
22679
22680 /**
22681  * @class Roo.dd.ScrollManager
22682  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22683  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22684  * @static
22685  */
22686 Roo.dd.ScrollManager = function(){
22687     var ddm = Roo.dd.DragDropMgr;
22688     var els = {};
22689     var dragEl = null;
22690     var proc = {};
22691     
22692     
22693     
22694     var onStop = function(e){
22695         dragEl = null;
22696         clearProc();
22697     };
22698     
22699     var triggerRefresh = function(){
22700         if(ddm.dragCurrent){
22701              ddm.refreshCache(ddm.dragCurrent.groups);
22702         }
22703     };
22704     
22705     var doScroll = function(){
22706         if(ddm.dragCurrent){
22707             var dds = Roo.dd.ScrollManager;
22708             if(!dds.animate){
22709                 if(proc.el.scroll(proc.dir, dds.increment)){
22710                     triggerRefresh();
22711                 }
22712             }else{
22713                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22714             }
22715         }
22716     };
22717     
22718     var clearProc = function(){
22719         if(proc.id){
22720             clearInterval(proc.id);
22721         }
22722         proc.id = 0;
22723         proc.el = null;
22724         proc.dir = "";
22725     };
22726     
22727     var startProc = function(el, dir){
22728          Roo.log('scroll startproc');
22729         clearProc();
22730         proc.el = el;
22731         proc.dir = dir;
22732         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22733     };
22734     
22735     var onFire = function(e, isDrop){
22736        
22737         if(isDrop || !ddm.dragCurrent){ return; }
22738         var dds = Roo.dd.ScrollManager;
22739         if(!dragEl || dragEl != ddm.dragCurrent){
22740             dragEl = ddm.dragCurrent;
22741             // refresh regions on drag start
22742             dds.refreshCache();
22743         }
22744         
22745         var xy = Roo.lib.Event.getXY(e);
22746         var pt = new Roo.lib.Point(xy[0], xy[1]);
22747         for(var id in els){
22748             var el = els[id], r = el._region;
22749             if(r && r.contains(pt) && el.isScrollable()){
22750                 if(r.bottom - pt.y <= dds.thresh){
22751                     if(proc.el != el){
22752                         startProc(el, "down");
22753                     }
22754                     return;
22755                 }else if(r.right - pt.x <= dds.thresh){
22756                     if(proc.el != el){
22757                         startProc(el, "left");
22758                     }
22759                     return;
22760                 }else if(pt.y - r.top <= dds.thresh){
22761                     if(proc.el != el){
22762                         startProc(el, "up");
22763                     }
22764                     return;
22765                 }else if(pt.x - r.left <= dds.thresh){
22766                     if(proc.el != el){
22767                         startProc(el, "right");
22768                     }
22769                     return;
22770                 }
22771             }
22772         }
22773         clearProc();
22774     };
22775     
22776     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22777     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22778     
22779     return {
22780         /**
22781          * Registers new overflow element(s) to auto scroll
22782          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22783          */
22784         register : function(el){
22785             if(el instanceof Array){
22786                 for(var i = 0, len = el.length; i < len; i++) {
22787                         this.register(el[i]);
22788                 }
22789             }else{
22790                 el = Roo.get(el);
22791                 els[el.id] = el;
22792             }
22793             Roo.dd.ScrollManager.els = els;
22794         },
22795         
22796         /**
22797          * Unregisters overflow element(s) so they are no longer scrolled
22798          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22799          */
22800         unregister : function(el){
22801             if(el instanceof Array){
22802                 for(var i = 0, len = el.length; i < len; i++) {
22803                         this.unregister(el[i]);
22804                 }
22805             }else{
22806                 el = Roo.get(el);
22807                 delete els[el.id];
22808             }
22809         },
22810         
22811         /**
22812          * The number of pixels from the edge of a container the pointer needs to be to 
22813          * trigger scrolling (defaults to 25)
22814          * @type Number
22815          */
22816         thresh : 25,
22817         
22818         /**
22819          * The number of pixels to scroll in each scroll increment (defaults to 50)
22820          * @type Number
22821          */
22822         increment : 100,
22823         
22824         /**
22825          * The frequency of scrolls in milliseconds (defaults to 500)
22826          * @type Number
22827          */
22828         frequency : 500,
22829         
22830         /**
22831          * True to animate the scroll (defaults to true)
22832          * @type Boolean
22833          */
22834         animate: true,
22835         
22836         /**
22837          * The animation duration in seconds - 
22838          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22839          * @type Number
22840          */
22841         animDuration: .4,
22842         
22843         /**
22844          * Manually trigger a cache refresh.
22845          */
22846         refreshCache : function(){
22847             for(var id in els){
22848                 if(typeof els[id] == 'object'){ // for people extending the object prototype
22849                     els[id]._region = els[id].getRegion();
22850                 }
22851             }
22852         }
22853     };
22854 }();/*
22855  * Based on:
22856  * Ext JS Library 1.1.1
22857  * Copyright(c) 2006-2007, Ext JS, LLC.
22858  *
22859  * Originally Released Under LGPL - original licence link has changed is not relivant.
22860  *
22861  * Fork - LGPL
22862  * <script type="text/javascript">
22863  */
22864  
22865
22866 /**
22867  * @class Roo.dd.Registry
22868  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
22869  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22870  * @static
22871  */
22872 Roo.dd.Registry = function(){
22873     var elements = {}; 
22874     var handles = {}; 
22875     var autoIdSeed = 0;
22876
22877     var getId = function(el, autogen){
22878         if(typeof el == "string"){
22879             return el;
22880         }
22881         var id = el.id;
22882         if(!id && autogen !== false){
22883             id = "roodd-" + (++autoIdSeed);
22884             el.id = id;
22885         }
22886         return id;
22887     };
22888     
22889     return {
22890     /**
22891      * Register a drag drop element
22892      * @param {String|HTMLElement} element The id or DOM node to register
22893      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22894      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
22895      * knows how to interpret, plus there are some specific properties known to the Registry that should be
22896      * populated in the data object (if applicable):
22897      * <pre>
22898 Value      Description<br />
22899 ---------  ------------------------------------------<br />
22900 handles    Array of DOM nodes that trigger dragging<br />
22901            for the element being registered<br />
22902 isHandle   True if the element passed in triggers<br />
22903            dragging itself, else false
22904 </pre>
22905      */
22906         register : function(el, data){
22907             data = data || {};
22908             if(typeof el == "string"){
22909                 el = document.getElementById(el);
22910             }
22911             data.ddel = el;
22912             elements[getId(el)] = data;
22913             if(data.isHandle !== false){
22914                 handles[data.ddel.id] = data;
22915             }
22916             if(data.handles){
22917                 var hs = data.handles;
22918                 for(var i = 0, len = hs.length; i < len; i++){
22919                         handles[getId(hs[i])] = data;
22920                 }
22921             }
22922         },
22923
22924     /**
22925      * Unregister a drag drop element
22926      * @param {String|HTMLElement}  element The id or DOM node to unregister
22927      */
22928         unregister : function(el){
22929             var id = getId(el, false);
22930             var data = elements[id];
22931             if(data){
22932                 delete elements[id];
22933                 if(data.handles){
22934                     var hs = data.handles;
22935                     for(var i = 0, len = hs.length; i < len; i++){
22936                         delete handles[getId(hs[i], false)];
22937                     }
22938                 }
22939             }
22940         },
22941
22942     /**
22943      * Returns the handle registered for a DOM Node by id
22944      * @param {String|HTMLElement} id The DOM node or id to look up
22945      * @return {Object} handle The custom handle data
22946      */
22947         getHandle : function(id){
22948             if(typeof id != "string"){ // must be element?
22949                 id = id.id;
22950             }
22951             return handles[id];
22952         },
22953
22954     /**
22955      * Returns the handle that is registered for the DOM node that is the target of the event
22956      * @param {Event} e The event
22957      * @return {Object} handle The custom handle data
22958      */
22959         getHandleFromEvent : function(e){
22960             var t = Roo.lib.Event.getTarget(e);
22961             return t ? handles[t.id] : null;
22962         },
22963
22964     /**
22965      * Returns a custom data object that is registered for a DOM node by id
22966      * @param {String|HTMLElement} id The DOM node or id to look up
22967      * @return {Object} data The custom data
22968      */
22969         getTarget : function(id){
22970             if(typeof id != "string"){ // must be element?
22971                 id = id.id;
22972             }
22973             return elements[id];
22974         },
22975
22976     /**
22977      * Returns a custom data object that is registered for the DOM node that is the target of the event
22978      * @param {Event} e The event
22979      * @return {Object} data The custom data
22980      */
22981         getTargetFromEvent : function(e){
22982             var t = Roo.lib.Event.getTarget(e);
22983             return t ? elements[t.id] || handles[t.id] : null;
22984         }
22985     };
22986 }();/*
22987  * Based on:
22988  * Ext JS Library 1.1.1
22989  * Copyright(c) 2006-2007, Ext JS, LLC.
22990  *
22991  * Originally Released Under LGPL - original licence link has changed is not relivant.
22992  *
22993  * Fork - LGPL
22994  * <script type="text/javascript">
22995  */
22996  
22997
22998 /**
22999  * @class Roo.dd.StatusProxy
23000  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23001  * default drag proxy used by all Roo.dd components.
23002  * @constructor
23003  * @param {Object} config
23004  */
23005 Roo.dd.StatusProxy = function(config){
23006     Roo.apply(this, config);
23007     this.id = this.id || Roo.id();
23008     this.el = new Roo.Layer({
23009         dh: {
23010             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23011                 {tag: "div", cls: "x-dd-drop-icon"},
23012                 {tag: "div", cls: "x-dd-drag-ghost"}
23013             ]
23014         }, 
23015         shadow: !config || config.shadow !== false
23016     });
23017     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23018     this.dropStatus = this.dropNotAllowed;
23019 };
23020
23021 Roo.dd.StatusProxy.prototype = {
23022     /**
23023      * @cfg {String} dropAllowed
23024      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23025      */
23026     dropAllowed : "x-dd-drop-ok",
23027     /**
23028      * @cfg {String} dropNotAllowed
23029      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23030      */
23031     dropNotAllowed : "x-dd-drop-nodrop",
23032
23033     /**
23034      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23035      * over the current target element.
23036      * @param {String} cssClass The css class for the new drop status indicator image
23037      */
23038     setStatus : function(cssClass){
23039         cssClass = cssClass || this.dropNotAllowed;
23040         if(this.dropStatus != cssClass){
23041             this.el.replaceClass(this.dropStatus, cssClass);
23042             this.dropStatus = cssClass;
23043         }
23044     },
23045
23046     /**
23047      * Resets the status indicator to the default dropNotAllowed value
23048      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23049      */
23050     reset : function(clearGhost){
23051         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23052         this.dropStatus = this.dropNotAllowed;
23053         if(clearGhost){
23054             this.ghost.update("");
23055         }
23056     },
23057
23058     /**
23059      * Updates the contents of the ghost element
23060      * @param {String} html The html that will replace the current innerHTML of the ghost element
23061      */
23062     update : function(html){
23063         if(typeof html == "string"){
23064             this.ghost.update(html);
23065         }else{
23066             this.ghost.update("");
23067             html.style.margin = "0";
23068             this.ghost.dom.appendChild(html);
23069         }
23070         // ensure float = none set?? cant remember why though.
23071         var el = this.ghost.dom.firstChild;
23072                 if(el){
23073                         Roo.fly(el).setStyle('float', 'none');
23074                 }
23075     },
23076     
23077     /**
23078      * Returns the underlying proxy {@link Roo.Layer}
23079      * @return {Roo.Layer} el
23080     */
23081     getEl : function(){
23082         return this.el;
23083     },
23084
23085     /**
23086      * Returns the ghost element
23087      * @return {Roo.Element} el
23088      */
23089     getGhost : function(){
23090         return this.ghost;
23091     },
23092
23093     /**
23094      * Hides the proxy
23095      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23096      */
23097     hide : function(clear){
23098         this.el.hide();
23099         if(clear){
23100             this.reset(true);
23101         }
23102     },
23103
23104     /**
23105      * Stops the repair animation if it's currently running
23106      */
23107     stop : function(){
23108         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23109             this.anim.stop();
23110         }
23111     },
23112
23113     /**
23114      * Displays this proxy
23115      */
23116     show : function(){
23117         this.el.show();
23118     },
23119
23120     /**
23121      * Force the Layer to sync its shadow and shim positions to the element
23122      */
23123     sync : function(){
23124         this.el.sync();
23125     },
23126
23127     /**
23128      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23129      * invalid drop operation by the item being dragged.
23130      * @param {Array} xy The XY position of the element ([x, y])
23131      * @param {Function} callback The function to call after the repair is complete
23132      * @param {Object} scope The scope in which to execute the callback
23133      */
23134     repair : function(xy, callback, scope){
23135         this.callback = callback;
23136         this.scope = scope;
23137         if(xy && this.animRepair !== false){
23138             this.el.addClass("x-dd-drag-repair");
23139             this.el.hideUnders(true);
23140             this.anim = this.el.shift({
23141                 duration: this.repairDuration || .5,
23142                 easing: 'easeOut',
23143                 xy: xy,
23144                 stopFx: true,
23145                 callback: this.afterRepair,
23146                 scope: this
23147             });
23148         }else{
23149             this.afterRepair();
23150         }
23151     },
23152
23153     // private
23154     afterRepair : function(){
23155         this.hide(true);
23156         if(typeof this.callback == "function"){
23157             this.callback.call(this.scope || this);
23158         }
23159         this.callback = null;
23160         this.scope = null;
23161     }
23162 };/*
23163  * Based on:
23164  * Ext JS Library 1.1.1
23165  * Copyright(c) 2006-2007, Ext JS, LLC.
23166  *
23167  * Originally Released Under LGPL - original licence link has changed is not relivant.
23168  *
23169  * Fork - LGPL
23170  * <script type="text/javascript">
23171  */
23172
23173 /**
23174  * @class Roo.dd.DragSource
23175  * @extends Roo.dd.DDProxy
23176  * A simple class that provides the basic implementation needed to make any element draggable.
23177  * @constructor
23178  * @param {String/HTMLElement/Element} el The container element
23179  * @param {Object} config
23180  */
23181 Roo.dd.DragSource = function(el, config){
23182     this.el = Roo.get(el);
23183     this.dragData = {};
23184     
23185     Roo.apply(this, config);
23186     
23187     if(!this.proxy){
23188         this.proxy = new Roo.dd.StatusProxy();
23189     }
23190
23191     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23192           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23193     
23194     this.dragging = false;
23195 };
23196
23197 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23198     /**
23199      * @cfg {String} dropAllowed
23200      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23201      */
23202     dropAllowed : "x-dd-drop-ok",
23203     /**
23204      * @cfg {String} dropNotAllowed
23205      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23206      */
23207     dropNotAllowed : "x-dd-drop-nodrop",
23208
23209     /**
23210      * Returns the data object associated with this drag source
23211      * @return {Object} data An object containing arbitrary data
23212      */
23213     getDragData : function(e){
23214         return this.dragData;
23215     },
23216
23217     // private
23218     onDragEnter : function(e, id){
23219         var target = Roo.dd.DragDropMgr.getDDById(id);
23220         this.cachedTarget = target;
23221         if(this.beforeDragEnter(target, e, id) !== false){
23222             if(target.isNotifyTarget){
23223                 var status = target.notifyEnter(this, e, this.dragData);
23224                 this.proxy.setStatus(status);
23225             }else{
23226                 this.proxy.setStatus(this.dropAllowed);
23227             }
23228             
23229             if(this.afterDragEnter){
23230                 /**
23231                  * An empty function by default, but provided so that you can perform a custom action
23232                  * when the dragged item enters the drop target by providing an implementation.
23233                  * @param {Roo.dd.DragDrop} target The drop target
23234                  * @param {Event} e The event object
23235                  * @param {String} id The id of the dragged element
23236                  * @method afterDragEnter
23237                  */
23238                 this.afterDragEnter(target, e, id);
23239             }
23240         }
23241     },
23242
23243     /**
23244      * An empty function by default, but provided so that you can perform a custom action
23245      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23246      * @param {Roo.dd.DragDrop} target The drop target
23247      * @param {Event} e The event object
23248      * @param {String} id The id of the dragged element
23249      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23250      */
23251     beforeDragEnter : function(target, e, id){
23252         return true;
23253     },
23254
23255     // private
23256     alignElWithMouse: function() {
23257         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23258         this.proxy.sync();
23259     },
23260
23261     // private
23262     onDragOver : function(e, id){
23263         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23264         if(this.beforeDragOver(target, e, id) !== false){
23265             if(target.isNotifyTarget){
23266                 var status = target.notifyOver(this, e, this.dragData);
23267                 this.proxy.setStatus(status);
23268             }
23269
23270             if(this.afterDragOver){
23271                 /**
23272                  * An empty function by default, but provided so that you can perform a custom action
23273                  * while the dragged item is over the drop target by providing an implementation.
23274                  * @param {Roo.dd.DragDrop} target The drop target
23275                  * @param {Event} e The event object
23276                  * @param {String} id The id of the dragged element
23277                  * @method afterDragOver
23278                  */
23279                 this.afterDragOver(target, e, id);
23280             }
23281         }
23282     },
23283
23284     /**
23285      * An empty function by default, but provided so that you can perform a custom action
23286      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23287      * @param {Roo.dd.DragDrop} target The drop target
23288      * @param {Event} e The event object
23289      * @param {String} id The id of the dragged element
23290      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23291      */
23292     beforeDragOver : function(target, e, id){
23293         return true;
23294     },
23295
23296     // private
23297     onDragOut : function(e, id){
23298         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23299         if(this.beforeDragOut(target, e, id) !== false){
23300             if(target.isNotifyTarget){
23301                 target.notifyOut(this, e, this.dragData);
23302             }
23303             this.proxy.reset();
23304             if(this.afterDragOut){
23305                 /**
23306                  * An empty function by default, but provided so that you can perform a custom action
23307                  * after the dragged item is dragged out of the target without dropping.
23308                  * @param {Roo.dd.DragDrop} target The drop target
23309                  * @param {Event} e The event object
23310                  * @param {String} id The id of the dragged element
23311                  * @method afterDragOut
23312                  */
23313                 this.afterDragOut(target, e, id);
23314             }
23315         }
23316         this.cachedTarget = null;
23317     },
23318
23319     /**
23320      * An empty function by default, but provided so that you can perform a custom action before the dragged
23321      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23322      * @param {Roo.dd.DragDrop} target The drop target
23323      * @param {Event} e The event object
23324      * @param {String} id The id of the dragged element
23325      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23326      */
23327     beforeDragOut : function(target, e, id){
23328         return true;
23329     },
23330     
23331     // private
23332     onDragDrop : function(e, id){
23333         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23334         if(this.beforeDragDrop(target, e, id) !== false){
23335             if(target.isNotifyTarget){
23336                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23337                     this.onValidDrop(target, e, id);
23338                 }else{
23339                     this.onInvalidDrop(target, e, id);
23340                 }
23341             }else{
23342                 this.onValidDrop(target, e, id);
23343             }
23344             
23345             if(this.afterDragDrop){
23346                 /**
23347                  * An empty function by default, but provided so that you can perform a custom action
23348                  * after a valid drag drop has occurred by providing an implementation.
23349                  * @param {Roo.dd.DragDrop} target The drop target
23350                  * @param {Event} e The event object
23351                  * @param {String} id The id of the dropped element
23352                  * @method afterDragDrop
23353                  */
23354                 this.afterDragDrop(target, e, id);
23355             }
23356         }
23357         delete this.cachedTarget;
23358     },
23359
23360     /**
23361      * An empty function by default, but provided so that you can perform a custom action before the dragged
23362      * item is dropped onto the target and optionally cancel the onDragDrop.
23363      * @param {Roo.dd.DragDrop} target The drop target
23364      * @param {Event} e The event object
23365      * @param {String} id The id of the dragged element
23366      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23367      */
23368     beforeDragDrop : function(target, e, id){
23369         return true;
23370     },
23371
23372     // private
23373     onValidDrop : function(target, e, id){
23374         this.hideProxy();
23375         if(this.afterValidDrop){
23376             /**
23377              * An empty function by default, but provided so that you can perform a custom action
23378              * after a valid drop has occurred by providing an implementation.
23379              * @param {Object} target The target DD 
23380              * @param {Event} e The event object
23381              * @param {String} id The id of the dropped element
23382              * @method afterInvalidDrop
23383              */
23384             this.afterValidDrop(target, e, id);
23385         }
23386     },
23387
23388     // private
23389     getRepairXY : function(e, data){
23390         return this.el.getXY();  
23391     },
23392
23393     // private
23394     onInvalidDrop : function(target, e, id){
23395         this.beforeInvalidDrop(target, e, id);
23396         if(this.cachedTarget){
23397             if(this.cachedTarget.isNotifyTarget){
23398                 this.cachedTarget.notifyOut(this, e, this.dragData);
23399             }
23400             this.cacheTarget = null;
23401         }
23402         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23403
23404         if(this.afterInvalidDrop){
23405             /**
23406              * An empty function by default, but provided so that you can perform a custom action
23407              * after an invalid drop has occurred by providing an implementation.
23408              * @param {Event} e The event object
23409              * @param {String} id The id of the dropped element
23410              * @method afterInvalidDrop
23411              */
23412             this.afterInvalidDrop(e, id);
23413         }
23414     },
23415
23416     // private
23417     afterRepair : function(){
23418         if(Roo.enableFx){
23419             this.el.highlight(this.hlColor || "c3daf9");
23420         }
23421         this.dragging = false;
23422     },
23423
23424     /**
23425      * An empty function by default, but provided so that you can perform a custom action after an invalid
23426      * drop has occurred.
23427      * @param {Roo.dd.DragDrop} target The drop target
23428      * @param {Event} e The event object
23429      * @param {String} id The id of the dragged element
23430      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23431      */
23432     beforeInvalidDrop : function(target, e, id){
23433         return true;
23434     },
23435
23436     // private
23437     handleMouseDown : function(e){
23438         if(this.dragging) {
23439             return;
23440         }
23441         var data = this.getDragData(e);
23442         if(data && this.onBeforeDrag(data, e) !== false){
23443             this.dragData = data;
23444             this.proxy.stop();
23445             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23446         } 
23447     },
23448
23449     /**
23450      * An empty function by default, but provided so that you can perform a custom action before the initial
23451      * drag event begins and optionally cancel it.
23452      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23453      * @param {Event} e The event object
23454      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23455      */
23456     onBeforeDrag : function(data, e){
23457         return true;
23458     },
23459
23460     /**
23461      * An empty function by default, but provided so that you can perform a custom action once the initial
23462      * drag event has begun.  The drag cannot be canceled from this function.
23463      * @param {Number} x The x position of the click on the dragged object
23464      * @param {Number} y The y position of the click on the dragged object
23465      */
23466     onStartDrag : Roo.emptyFn,
23467
23468     // private - YUI override
23469     startDrag : function(x, y){
23470         this.proxy.reset();
23471         this.dragging = true;
23472         this.proxy.update("");
23473         this.onInitDrag(x, y);
23474         this.proxy.show();
23475     },
23476
23477     // private
23478     onInitDrag : function(x, y){
23479         var clone = this.el.dom.cloneNode(true);
23480         clone.id = Roo.id(); // prevent duplicate ids
23481         this.proxy.update(clone);
23482         this.onStartDrag(x, y);
23483         return true;
23484     },
23485
23486     /**
23487      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23488      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23489      */
23490     getProxy : function(){
23491         return this.proxy;  
23492     },
23493
23494     /**
23495      * Hides the drag source's {@link Roo.dd.StatusProxy}
23496      */
23497     hideProxy : function(){
23498         this.proxy.hide();  
23499         this.proxy.reset(true);
23500         this.dragging = false;
23501     },
23502
23503     // private
23504     triggerCacheRefresh : function(){
23505         Roo.dd.DDM.refreshCache(this.groups);
23506     },
23507
23508     // private - override to prevent hiding
23509     b4EndDrag: function(e) {
23510     },
23511
23512     // private - override to prevent moving
23513     endDrag : function(e){
23514         this.onEndDrag(this.dragData, e);
23515     },
23516
23517     // private
23518     onEndDrag : function(data, e){
23519     },
23520     
23521     // private - pin to cursor
23522     autoOffset : function(x, y) {
23523         this.setDelta(-12, -20);
23524     }    
23525 });/*
23526  * Based on:
23527  * Ext JS Library 1.1.1
23528  * Copyright(c) 2006-2007, Ext JS, LLC.
23529  *
23530  * Originally Released Under LGPL - original licence link has changed is not relivant.
23531  *
23532  * Fork - LGPL
23533  * <script type="text/javascript">
23534  */
23535
23536
23537 /**
23538  * @class Roo.dd.DropTarget
23539  * @extends Roo.dd.DDTarget
23540  * A simple class that provides the basic implementation needed to make any element a drop target that can have
23541  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
23542  * @constructor
23543  * @param {String/HTMLElement/Element} el The container element
23544  * @param {Object} config
23545  */
23546 Roo.dd.DropTarget = function(el, config){
23547     this.el = Roo.get(el);
23548     
23549     var listeners = false; ;
23550     if (config && config.listeners) {
23551         listeners= config.listeners;
23552         delete config.listeners;
23553     }
23554     Roo.apply(this, config);
23555     
23556     if(this.containerScroll){
23557         Roo.dd.ScrollManager.register(this.el);
23558     }
23559     this.addEvents( {
23560          /**
23561          * @scope Roo.dd.DropTarget
23562          */
23563          
23564          /**
23565          * @event enter
23566          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23567          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
23568          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
23569          * 
23570          * IMPORTANT : it should set  this.valid to true|false
23571          * 
23572          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23573          * @param {Event} e The event
23574          * @param {Object} data An object containing arbitrary data supplied by the drag source
23575          */
23576         "enter" : true,
23577         
23578          /**
23579          * @event over
23580          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23581          * This method will be called on every mouse movement while the drag source is over the drop target.
23582          * This default implementation simply returns the dropAllowed config value.
23583          * 
23584          * IMPORTANT : it should set  this.valid to true|false
23585          * 
23586          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23587          * @param {Event} e The event
23588          * @param {Object} data An object containing arbitrary data supplied by the drag source
23589          
23590          */
23591         "over" : true,
23592         /**
23593          * @event out
23594          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23595          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
23596          * overClass (if any) from the drop element.
23597          * 
23598          * 
23599          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23600          * @param {Event} e The event
23601          * @param {Object} data An object containing arbitrary data supplied by the drag source
23602          */
23603          "out" : true,
23604          
23605         /**
23606          * @event drop
23607          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23608          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
23609          * implementation that does something to process the drop event and returns true so that the drag source's
23610          * repair action does not run.
23611          * 
23612          * IMPORTANT : it should set this.success
23613          * 
23614          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23615          * @param {Event} e The event
23616          * @param {Object} data An object containing arbitrary data supplied by the drag source
23617         */
23618          "drop" : true
23619     });
23620             
23621      
23622     Roo.dd.DropTarget.superclass.constructor.call(  this, 
23623         this.el.dom, 
23624         this.ddGroup || this.group,
23625         {
23626             isTarget: true,
23627             listeners : listeners || {} 
23628            
23629         
23630         }
23631     );
23632
23633 };
23634
23635 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23636     /**
23637      * @cfg {String} overClass
23638      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23639      */
23640      /**
23641      * @cfg {String} ddGroup
23642      * The drag drop group to handle drop events for
23643      */
23644      
23645     /**
23646      * @cfg {String} dropAllowed
23647      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23648      */
23649     dropAllowed : "x-dd-drop-ok",
23650     /**
23651      * @cfg {String} dropNotAllowed
23652      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23653      */
23654     dropNotAllowed : "x-dd-drop-nodrop",
23655     /**
23656      * @cfg {boolean} success
23657      * set this after drop listener.. 
23658      */
23659     success : false,
23660     /**
23661      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23662      * if the drop point is valid for over/enter..
23663      */
23664     valid : false,
23665     // private
23666     isTarget : true,
23667
23668     // private
23669     isNotifyTarget : true,
23670     
23671     /**
23672      * @hide
23673      */
23674     notifyEnter : function(dd, e, data)
23675     {
23676         this.valid = true;
23677         this.fireEvent('enter', dd, e, data);
23678         if(this.overClass){
23679             this.el.addClass(this.overClass);
23680         }
23681         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23682             this.valid ? this.dropAllowed : this.dropNotAllowed
23683         );
23684     },
23685
23686     /**
23687      * @hide
23688      */
23689     notifyOver : function(dd, e, data)
23690     {
23691         this.valid = true;
23692         this.fireEvent('over', dd, e, data);
23693         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23694             this.valid ? this.dropAllowed : this.dropNotAllowed
23695         );
23696     },
23697
23698     /**
23699      * @hide
23700      */
23701     notifyOut : function(dd, e, data)
23702     {
23703         this.fireEvent('out', dd, e, data);
23704         if(this.overClass){
23705             this.el.removeClass(this.overClass);
23706         }
23707     },
23708
23709     /**
23710      * @hide
23711      */
23712     notifyDrop : function(dd, e, data)
23713     {
23714         this.success = false;
23715         this.fireEvent('drop', dd, e, data);
23716         return this.success;
23717     }
23718 });/*
23719  * Based on:
23720  * Ext JS Library 1.1.1
23721  * Copyright(c) 2006-2007, Ext JS, LLC.
23722  *
23723  * Originally Released Under LGPL - original licence link has changed is not relivant.
23724  *
23725  * Fork - LGPL
23726  * <script type="text/javascript">
23727  */
23728
23729
23730 /**
23731  * @class Roo.dd.DragZone
23732  * @extends Roo.dd.DragSource
23733  * This class provides a container DD instance that proxies for multiple child node sources.<br />
23734  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23735  * @constructor
23736  * @param {String/HTMLElement/Element} el The container element
23737  * @param {Object} config
23738  */
23739 Roo.dd.DragZone = function(el, config){
23740     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23741     if(this.containerScroll){
23742         Roo.dd.ScrollManager.register(this.el);
23743     }
23744 };
23745
23746 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23747     /**
23748      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23749      * for auto scrolling during drag operations.
23750      */
23751     /**
23752      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23753      * method after a failed drop (defaults to "c3daf9" - light blue)
23754      */
23755
23756     /**
23757      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23758      * for a valid target to drag based on the mouse down. Override this method
23759      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23760      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23761      * @param {EventObject} e The mouse down event
23762      * @return {Object} The dragData
23763      */
23764     getDragData : function(e){
23765         return Roo.dd.Registry.getHandleFromEvent(e);
23766     },
23767     
23768     /**
23769      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23770      * this.dragData.ddel
23771      * @param {Number} x The x position of the click on the dragged object
23772      * @param {Number} y The y position of the click on the dragged object
23773      * @return {Boolean} true to continue the drag, false to cancel
23774      */
23775     onInitDrag : function(x, y){
23776         this.proxy.update(this.dragData.ddel.cloneNode(true));
23777         this.onStartDrag(x, y);
23778         return true;
23779     },
23780     
23781     /**
23782      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
23783      */
23784     afterRepair : function(){
23785         if(Roo.enableFx){
23786             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23787         }
23788         this.dragging = false;
23789     },
23790
23791     /**
23792      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23793      * the XY of this.dragData.ddel
23794      * @param {EventObject} e The mouse up event
23795      * @return {Array} The xy location (e.g. [100, 200])
23796      */
23797     getRepairXY : function(e){
23798         return Roo.Element.fly(this.dragData.ddel).getXY();  
23799     }
23800 });/*
23801  * Based on:
23802  * Ext JS Library 1.1.1
23803  * Copyright(c) 2006-2007, Ext JS, LLC.
23804  *
23805  * Originally Released Under LGPL - original licence link has changed is not relivant.
23806  *
23807  * Fork - LGPL
23808  * <script type="text/javascript">
23809  */
23810 /**
23811  * @class Roo.dd.DropZone
23812  * @extends Roo.dd.DropTarget
23813  * This class provides a container DD instance that proxies for multiple child node targets.<br />
23814  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23815  * @constructor
23816  * @param {String/HTMLElement/Element} el The container element
23817  * @param {Object} config
23818  */
23819 Roo.dd.DropZone = function(el, config){
23820     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23821 };
23822
23823 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23824     /**
23825      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
23826      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23827      * provide your own custom lookup.
23828      * @param {Event} e The event
23829      * @return {Object} data The custom data
23830      */
23831     getTargetFromEvent : function(e){
23832         return Roo.dd.Registry.getTargetFromEvent(e);
23833     },
23834
23835     /**
23836      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
23837      * that it has registered.  This method has no default implementation and should be overridden to provide
23838      * node-specific processing if necessary.
23839      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
23840      * {@link #getTargetFromEvent} for this node)
23841      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23842      * @param {Event} e The event
23843      * @param {Object} data An object containing arbitrary data supplied by the drag source
23844      */
23845     onNodeEnter : function(n, dd, e, data){
23846         
23847     },
23848
23849     /**
23850      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23851      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
23852      * overridden to provide the proper feedback.
23853      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23854      * {@link #getTargetFromEvent} for this node)
23855      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23856      * @param {Event} e The event
23857      * @param {Object} data An object containing arbitrary data supplied by the drag source
23858      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23859      * underlying {@link Roo.dd.StatusProxy} can be updated
23860      */
23861     onNodeOver : function(n, dd, e, data){
23862         return this.dropAllowed;
23863     },
23864
23865     /**
23866      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23867      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
23868      * node-specific processing if necessary.
23869      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23870      * {@link #getTargetFromEvent} for this node)
23871      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23872      * @param {Event} e The event
23873      * @param {Object} data An object containing arbitrary data supplied by the drag source
23874      */
23875     onNodeOut : function(n, dd, e, data){
23876         
23877     },
23878
23879     /**
23880      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23881      * the drop node.  The default implementation returns false, so it should be overridden to provide the
23882      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23883      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23884      * {@link #getTargetFromEvent} for this node)
23885      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23886      * @param {Event} e The event
23887      * @param {Object} data An object containing arbitrary data supplied by the drag source
23888      * @return {Boolean} True if the drop was valid, else false
23889      */
23890     onNodeDrop : function(n, dd, e, data){
23891         return false;
23892     },
23893
23894     /**
23895      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23896      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
23897      * it should be overridden to provide the proper feedback if necessary.
23898      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23899      * @param {Event} e The event
23900      * @param {Object} data An object containing arbitrary data supplied by the drag source
23901      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23902      * underlying {@link Roo.dd.StatusProxy} can be updated
23903      */
23904     onContainerOver : function(dd, e, data){
23905         return this.dropNotAllowed;
23906     },
23907
23908     /**
23909      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23910      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
23911      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23912      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
23913      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23914      * @param {Event} e The event
23915      * @param {Object} data An object containing arbitrary data supplied by the drag source
23916      * @return {Boolean} True if the drop was valid, else false
23917      */
23918     onContainerDrop : function(dd, e, data){
23919         return false;
23920     },
23921
23922     /**
23923      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23924      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
23925      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23926      * you should override this method and provide a custom implementation.
23927      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23928      * @param {Event} e The event
23929      * @param {Object} data An object containing arbitrary data supplied by the drag source
23930      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23931      * underlying {@link Roo.dd.StatusProxy} can be updated
23932      */
23933     notifyEnter : function(dd, e, data){
23934         return this.dropNotAllowed;
23935     },
23936
23937     /**
23938      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23939      * This method will be called on every mouse movement while the drag source is over the drop zone.
23940      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23941      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23942      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23943      * registered node, it will call {@link #onContainerOver}.
23944      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23945      * @param {Event} e The event
23946      * @param {Object} data An object containing arbitrary data supplied by the drag source
23947      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23948      * underlying {@link Roo.dd.StatusProxy} can be updated
23949      */
23950     notifyOver : function(dd, e, data){
23951         var n = this.getTargetFromEvent(e);
23952         if(!n){ // not over valid drop target
23953             if(this.lastOverNode){
23954                 this.onNodeOut(this.lastOverNode, dd, e, data);
23955                 this.lastOverNode = null;
23956             }
23957             return this.onContainerOver(dd, e, data);
23958         }
23959         if(this.lastOverNode != n){
23960             if(this.lastOverNode){
23961                 this.onNodeOut(this.lastOverNode, dd, e, data);
23962             }
23963             this.onNodeEnter(n, dd, e, data);
23964             this.lastOverNode = n;
23965         }
23966         return this.onNodeOver(n, dd, e, data);
23967     },
23968
23969     /**
23970      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23971      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
23972      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23973      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23974      * @param {Event} e The event
23975      * @param {Object} data An object containing arbitrary data supplied by the drag zone
23976      */
23977     notifyOut : function(dd, e, data){
23978         if(this.lastOverNode){
23979             this.onNodeOut(this.lastOverNode, dd, e, data);
23980             this.lastOverNode = null;
23981         }
23982     },
23983
23984     /**
23985      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23986      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
23987      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23988      * otherwise it will call {@link #onContainerDrop}.
23989      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23990      * @param {Event} e The event
23991      * @param {Object} data An object containing arbitrary data supplied by the drag source
23992      * @return {Boolean} True if the drop was valid, else false
23993      */
23994     notifyDrop : function(dd, e, data){
23995         if(this.lastOverNode){
23996             this.onNodeOut(this.lastOverNode, dd, e, data);
23997             this.lastOverNode = null;
23998         }
23999         var n = this.getTargetFromEvent(e);
24000         return n ?
24001             this.onNodeDrop(n, dd, e, data) :
24002             this.onContainerDrop(dd, e, data);
24003     },
24004
24005     // private
24006     triggerCacheRefresh : function(){
24007         Roo.dd.DDM.refreshCache(this.groups);
24008     }  
24009 });