Fix #6913 - add more documentation to code
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @static
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 }
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux",
704                 "Roo.bootstrap",
705                 "Roo.bootstrap.dash");
706 /*
707  * Based on:
708  * Ext JS Library 1.1.1
709  * Copyright(c) 2006-2007, Ext JS, LLC.
710  *
711  * Originally Released Under LGPL - original licence link has changed is not relivant.
712  *
713  * Fork - LGPL
714  * <script type="text/javascript">
715  */
716
717 (function() {    
718     // wrappedn so fnCleanup is not in global scope...
719     if(Roo.isIE) {
720         function fnCleanUp() {
721             var p = Function.prototype;
722             delete p.createSequence;
723             delete p.defer;
724             delete p.createDelegate;
725             delete p.createCallback;
726             delete p.createInterceptor;
727
728             window.detachEvent("onunload", fnCleanUp);
729         }
730         window.attachEvent("onunload", fnCleanUp);
731     }
732 })();
733
734
735 /**
736  * @class Function
737  * These functions are available on every Function object (any JavaScript function).
738  */
739 Roo.apply(Function.prototype, {
740      /**
741      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
742      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
743      * Will create a function that is bound to those 2 args.
744      * @return {Function} The new function
745     */
746     createCallback : function(/*args...*/){
747         // make args available, in function below
748         var args = arguments;
749         var method = this;
750         return function() {
751             return method.apply(window, args);
752         };
753     },
754
755     /**
756      * Creates a delegate (callback) that sets the scope to obj.
757      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
758      * Will create a function that is automatically scoped to this.
759      * @param {Object} obj (optional) The object for which the scope is set
760      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762      *                                             if a number the args are inserted at the specified position
763      * @return {Function} The new function
764      */
765     createDelegate : function(obj, args, appendArgs){
766         var method = this;
767         return function() {
768             var callArgs = args || arguments;
769             if(appendArgs === true){
770                 callArgs = Array.prototype.slice.call(arguments, 0);
771                 callArgs = callArgs.concat(args);
772             }else if(typeof appendArgs == "number"){
773                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
774                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
775                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
776             }
777             return method.apply(obj || window, callArgs);
778         };
779     },
780
781     /**
782      * Calls this function after the number of millseconds specified.
783      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
784      * @param {Object} obj (optional) The object for which the scope is set
785      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
786      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
787      *                                             if a number the args are inserted at the specified position
788      * @return {Number} The timeout id that can be used with clearTimeout
789      */
790     defer : function(millis, obj, args, appendArgs){
791         var fn = this.createDelegate(obj, args, appendArgs);
792         if(millis){
793             return setTimeout(fn, millis);
794         }
795         fn();
796         return 0;
797     },
798     /**
799      * Create a combined function call sequence of the original function + the passed function.
800      * The resulting function returns the results of the original function.
801      * The passed fcn is called with the parameters of the original function
802      * @param {Function} fcn The function to sequence
803      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
804      * @return {Function} The new function
805      */
806     createSequence : function(fcn, scope){
807         if(typeof fcn != "function"){
808             return this;
809         }
810         var method = this;
811         return function() {
812             var retval = method.apply(this || window, arguments);
813             fcn.apply(scope || this || window, arguments);
814             return retval;
815         };
816     },
817
818     /**
819      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
820      * The resulting function returns the results of the original function.
821      * The passed fcn is called with the parameters of the original function.
822      * @addon
823      * @param {Function} fcn The function to call before the original
824      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
825      * @return {Function} The new function
826      */
827     createInterceptor : function(fcn, scope){
828         if(typeof fcn != "function"){
829             return this;
830         }
831         var method = this;
832         return function() {
833             fcn.target = this;
834             fcn.method = method;
835             if(fcn.apply(scope || this || window, arguments) === false){
836                 return;
837             }
838             return method.apply(this || window, arguments);
839         };
840     }
841 });
842 /*
843  * Based on:
844  * Ext JS Library 1.1.1
845  * Copyright(c) 2006-2007, Ext JS, LLC.
846  *
847  * Originally Released Under LGPL - original licence link has changed is not relivant.
848  *
849  * Fork - LGPL
850  * <script type="text/javascript">
851  */
852
853 Roo.applyIf(String, {
854     
855     /** @scope String */
856     
857     /**
858      * Escapes the passed string for ' and \
859      * @param {String} string The string to escape
860      * @return {String} The escaped string
861      * @static
862      */
863     escape : function(string) {
864         return string.replace(/('|\\)/g, "\\$1");
865     },
866
867     /**
868      * Pads the left side of a string with a specified character.  This is especially useful
869      * for normalizing number and date strings.  Example usage:
870      * <pre><code>
871 var s = String.leftPad('123', 5, '0');
872 // s now contains the string: '00123'
873 </code></pre>
874      * @param {String} string The original string
875      * @param {Number} size The total length of the output string
876      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
877      * @return {String} The padded string
878      * @static
879      */
880     leftPad : function (val, size, ch) {
881         var result = new String(val);
882         if(ch === null || ch === undefined || ch === '') {
883             ch = " ";
884         }
885         while (result.length < size) {
886             result = ch + result;
887         }
888         return result;
889     },
890
891     /**
892      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
893      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
894      * <pre><code>
895 var cls = 'my-class', text = 'Some text';
896 var s = String.format('<div class="{0}">{1}</div>', cls, text);
897 // s now contains the string: '<div class="my-class">Some text</div>'
898 </code></pre>
899      * @param {String} string The tokenized string to be formatted
900      * @param {String} value1 The value to replace token {0}
901      * @param {String} value2 Etc...
902      * @return {String} The formatted string
903      * @static
904      */
905     format : function(format){
906         var args = Array.prototype.slice.call(arguments, 1);
907         return format.replace(/\{(\d+)\}/g, function(m, i){
908             return Roo.util.Format.htmlEncode(args[i]);
909         });
910     }
911   
912     
913 });
914
915 /**
916  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
917  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
918  * they are already different, the first value passed in is returned.  Note that this method returns the new value
919  * but does not change the current string.
920  * <pre><code>
921 // alternate sort directions
922 sort = sort.toggle('ASC', 'DESC');
923
924 // instead of conditional logic:
925 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
926 </code></pre>
927  * @param {String} value The value to compare to the current string
928  * @param {String} other The new value to use if the string already equals the first value passed in
929  * @return {String} The new value
930  */
931  
932 String.prototype.toggle = function(value, other){
933     return this == value ? other : value;
934 };
935
936
937 /**
938   * Remove invalid unicode characters from a string 
939   *
940   * @return {String} The clean string
941   */
942 String.prototype.unicodeClean = function () {
943     return this.replace(/[\s\S]/g,
944         function(character) {
945             if (character.charCodeAt()< 256) {
946               return character;
947            }
948            try {
949                 encodeURIComponent(character);
950            } catch(e) { 
951               return '';
952            }
953            return character;
954         }
955     );
956 };
957   
958 /*
959  * Based on:
960  * Ext JS Library 1.1.1
961  * Copyright(c) 2006-2007, Ext JS, LLC.
962  *
963  * Originally Released Under LGPL - original licence link has changed is not relivant.
964  *
965  * Fork - LGPL
966  * <script type="text/javascript">
967  */
968
969  /**
970  * @class Number
971  */
972 Roo.applyIf(Number.prototype, {
973     /**
974      * Checks whether or not the current number is within a desired range.  If the number is already within the
975      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
976      * exceeded.  Note that this method returns the constrained value but does not change the current number.
977      * @param {Number} min The minimum number in the range
978      * @param {Number} max The maximum number in the range
979      * @return {Number} The constrained value if outside the range, otherwise the current value
980      */
981     constrain : function(min, max){
982         return Math.min(Math.max(this, min), max);
983     }
984 });/*
985  * Based on:
986  * Ext JS Library 1.1.1
987  * Copyright(c) 2006-2007, Ext JS, LLC.
988  *
989  * Originally Released Under LGPL - original licence link has changed is not relivant.
990  *
991  * Fork - LGPL
992  * <script type="text/javascript">
993  */
994  /**
995  * @class Array
996  */
997 Roo.applyIf(Array.prototype, {
998     /**
999      * 
1000      * Checks whether or not the specified object exists in the array.
1001      * @param {Object} o The object to check for
1002      * @return {Number} The index of o in the array (or -1 if it is not found)
1003      */
1004     indexOf : function(o){
1005        for (var i = 0, len = this.length; i < len; i++){
1006               if(this[i] == o) { return i; }
1007        }
1008            return -1;
1009     },
1010
1011     /**
1012      * Removes the specified object from the array.  If the object is not found nothing happens.
1013      * @param {Object} o The object to remove
1014      */
1015     remove : function(o){
1016        var index = this.indexOf(o);
1017        if(index != -1){
1018            this.splice(index, 1);
1019        }
1020     },
1021     /**
1022      * Map (JS 1.6 compatibility)
1023      * @param {Function} function  to call
1024      */
1025     map : function(fun )
1026     {
1027         var len = this.length >>> 0;
1028         if (typeof fun != "function") {
1029             throw new TypeError();
1030         }
1031         var res = new Array(len);
1032         var thisp = arguments[1];
1033         for (var i = 0; i < len; i++)
1034         {
1035             if (i in this) {
1036                 res[i] = fun.call(thisp, this[i], i, this);
1037             }
1038         }
1039
1040         return res;
1041     },
1042     /**
1043      * equals
1044      * @param {Array} o The array to compare to
1045      * @returns {Boolean} true if the same
1046      */
1047     equals : function(b)
1048     {
1049         // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1050         if (this === b) {
1051             return true;
1052          }
1053         if (b == null) {
1054             return false;
1055         }
1056         if (this.length !== b.length) {
1057             return false;
1058         }
1059       
1060         // sort?? a.sort().equals(b.sort());
1061       
1062         for (var i = 0; i < this.length; ++i) {
1063             if (this[i] !== b[i]) {
1064                 return false;
1065             }
1066         }
1067         return true;
1068     }
1069 });
1070
1071
1072  
1073 /*
1074  * Based on:
1075  * Ext JS Library 1.1.1
1076  * Copyright(c) 2006-2007, Ext JS, LLC.
1077  *
1078  * Originally Released Under LGPL - original licence link has changed is not relivant.
1079  *
1080  * Fork - LGPL
1081  * <script type="text/javascript">
1082  */
1083
1084 /**
1085  * @class Date
1086  *
1087  * The date parsing and format syntax is a subset of
1088  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1089  * supported will provide results equivalent to their PHP versions.
1090  *
1091  * Following is the list of all currently supported formats:
1092  *<pre>
1093 Sample date:
1094 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1095
1096 Format  Output      Description
1097 ------  ----------  --------------------------------------------------------------
1098   d      10         Day of the month, 2 digits with leading zeros
1099   D      Wed        A textual representation of a day, three letters
1100   j      10         Day of the month without leading zeros
1101   l      Wednesday  A full textual representation of the day of the week
1102   S      th         English ordinal day of month suffix, 2 chars (use with j)
1103   w      3          Numeric representation of the day of the week
1104   z      9          The julian date, or day of the year (0-365)
1105   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1106   F      January    A full textual representation of the month
1107   m      01         Numeric representation of a month, with leading zeros
1108   M      Jan        Month name abbreviation, three letters
1109   n      1          Numeric representation of a month, without leading zeros
1110   t      31         Number of days in the given month
1111   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1112   Y      2007       A full numeric representation of a year, 4 digits
1113   y      07         A two digit representation of a year
1114   a      pm         Lowercase Ante meridiem and Post meridiem
1115   A      PM         Uppercase Ante meridiem and Post meridiem
1116   g      3          12-hour format of an hour without leading zeros
1117   G      15         24-hour format of an hour without leading zeros
1118   h      03         12-hour format of an hour with leading zeros
1119   H      15         24-hour format of an hour with leading zeros
1120   i      05         Minutes with leading zeros
1121   s      01         Seconds, with leading zeros
1122   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1123   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1124   T      CST        Timezone setting of the machine running the code
1125   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1126 </pre>
1127  *
1128  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1129  * <pre><code>
1130 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1131 document.write(dt.format('Y-m-d'));                         //2007-01-10
1132 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1133 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1134  </code></pre>
1135  *
1136  * Here are some standard date/time patterns that you might find helpful.  They
1137  * are not part of the source of Date.js, but to use them you can simply copy this
1138  * block of code into any script that is included after Date.js and they will also become
1139  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1140  * <pre><code>
1141 Date.patterns = {
1142     ISO8601Long:"Y-m-d H:i:s",
1143     ISO8601Short:"Y-m-d",
1144     ShortDate: "n/j/Y",
1145     LongDate: "l, F d, Y",
1146     FullDateTime: "l, F d, Y g:i:s A",
1147     MonthDay: "F d",
1148     ShortTime: "g:i A",
1149     LongTime: "g:i:s A",
1150     SortableDateTime: "Y-m-d\\TH:i:s",
1151     UniversalSortableDateTime: "Y-m-d H:i:sO",
1152     YearMonth: "F, Y"
1153 };
1154 </code></pre>
1155  *
1156  * Example usage:
1157  * <pre><code>
1158 var dt = new Date();
1159 document.write(dt.format(Date.patterns.ShortDate));
1160  </code></pre>
1161  */
1162
1163 /*
1164  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1165  * They generate precompiled functions from date formats instead of parsing and
1166  * processing the pattern every time you format a date.  These functions are available
1167  * on every Date object (any javascript function).
1168  *
1169  * The original article and download are here:
1170  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1171  *
1172  */
1173  
1174  
1175  // was in core
1176 /**
1177  Returns the number of milliseconds between this date and date
1178  @param {Date} date (optional) Defaults to now
1179  @return {Number} The diff in milliseconds
1180  @member Date getElapsed
1181  */
1182 Date.prototype.getElapsed = function(date) {
1183         return Math.abs((date || new Date()).getTime()-this.getTime());
1184 };
1185 // was in date file..
1186
1187
1188 // private
1189 Date.parseFunctions = {count:0};
1190 // private
1191 Date.parseRegexes = [];
1192 // private
1193 Date.formatFunctions = {count:0};
1194
1195 // private
1196 Date.prototype.dateFormat = function(format) {
1197     if (Date.formatFunctions[format] == null) {
1198         Date.createNewFormat(format);
1199     }
1200     var func = Date.formatFunctions[format];
1201     return this[func]();
1202 };
1203
1204
1205 /**
1206  * Formats a date given the supplied format string
1207  * @param {String} format The format string
1208  * @return {String} The formatted date
1209  * @method
1210  */
1211 Date.prototype.format = Date.prototype.dateFormat;
1212
1213 // private
1214 Date.createNewFormat = function(format) {
1215     var funcName = "format" + Date.formatFunctions.count++;
1216     Date.formatFunctions[format] = funcName;
1217     var code = "Date.prototype." + funcName + " = function(){return ";
1218     var special = false;
1219     var ch = '';
1220     for (var i = 0; i < format.length; ++i) {
1221         ch = format.charAt(i);
1222         if (!special && ch == "\\") {
1223             special = true;
1224         }
1225         else if (special) {
1226             special = false;
1227             code += "'" + String.escape(ch) + "' + ";
1228         }
1229         else {
1230             code += Date.getFormatCode(ch);
1231         }
1232     }
1233     /** eval:var:zzzzzzzzzzzzz */
1234     eval(code.substring(0, code.length - 3) + ";}");
1235 };
1236
1237 // private
1238 Date.getFormatCode = function(character) {
1239     switch (character) {
1240     case "d":
1241         return "String.leftPad(this.getDate(), 2, '0') + ";
1242     case "D":
1243         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1244     case "j":
1245         return "this.getDate() + ";
1246     case "l":
1247         return "Date.dayNames[this.getDay()] + ";
1248     case "S":
1249         return "this.getSuffix() + ";
1250     case "w":
1251         return "this.getDay() + ";
1252     case "z":
1253         return "this.getDayOfYear() + ";
1254     case "W":
1255         return "this.getWeekOfYear() + ";
1256     case "F":
1257         return "Date.monthNames[this.getMonth()] + ";
1258     case "m":
1259         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1260     case "M":
1261         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1262     case "n":
1263         return "(this.getMonth() + 1) + ";
1264     case "t":
1265         return "this.getDaysInMonth() + ";
1266     case "L":
1267         return "(this.isLeapYear() ? 1 : 0) + ";
1268     case "Y":
1269         return "this.getFullYear() + ";
1270     case "y":
1271         return "('' + this.getFullYear()).substring(2, 4) + ";
1272     case "a":
1273         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1274     case "A":
1275         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1276     case "g":
1277         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1278     case "G":
1279         return "this.getHours() + ";
1280     case "h":
1281         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1282     case "H":
1283         return "String.leftPad(this.getHours(), 2, '0') + ";
1284     case "i":
1285         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1286     case "s":
1287         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1288     case "O":
1289         return "this.getGMTOffset() + ";
1290     case "P":
1291         return "this.getGMTColonOffset() + ";
1292     case "T":
1293         return "this.getTimezone() + ";
1294     case "Z":
1295         return "(this.getTimezoneOffset() * -60) + ";
1296     default:
1297         return "'" + String.escape(character) + "' + ";
1298     }
1299 };
1300
1301 /**
1302  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1303  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1304  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1305  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1306  * string or the parse operation will fail.
1307  * Example Usage:
1308 <pre><code>
1309 //dt = Fri May 25 2007 (current date)
1310 var dt = new Date();
1311
1312 //dt = Thu May 25 2006 (today's month/day in 2006)
1313 dt = Date.parseDate("2006", "Y");
1314
1315 //dt = Sun Jan 15 2006 (all date parts specified)
1316 dt = Date.parseDate("2006-1-15", "Y-m-d");
1317
1318 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1319 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1320 </code></pre>
1321  * @param {String} input The unparsed date as a string
1322  * @param {String} format The format the date is in
1323  * @return {Date} The parsed date
1324  * @static
1325  */
1326 Date.parseDate = function(input, format) {
1327     if (Date.parseFunctions[format] == null) {
1328         Date.createParser(format);
1329     }
1330     var func = Date.parseFunctions[format];
1331     return Date[func](input);
1332 };
1333 /**
1334  * @private
1335  */
1336
1337 Date.createParser = function(format) {
1338     var funcName = "parse" + Date.parseFunctions.count++;
1339     var regexNum = Date.parseRegexes.length;
1340     var currentGroup = 1;
1341     Date.parseFunctions[format] = funcName;
1342
1343     var code = "Date." + funcName + " = function(input){\n"
1344         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1345         + "var d = new Date();\n"
1346         + "y = d.getFullYear();\n"
1347         + "m = d.getMonth();\n"
1348         + "d = d.getDate();\n"
1349         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1350         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1351         + "if (results && results.length > 0) {";
1352     var regex = "";
1353
1354     var special = false;
1355     var ch = '';
1356     for (var i = 0; i < format.length; ++i) {
1357         ch = format.charAt(i);
1358         if (!special && ch == "\\") {
1359             special = true;
1360         }
1361         else if (special) {
1362             special = false;
1363             regex += String.escape(ch);
1364         }
1365         else {
1366             var obj = Date.formatCodeToRegex(ch, currentGroup);
1367             currentGroup += obj.g;
1368             regex += obj.s;
1369             if (obj.g && obj.c) {
1370                 code += obj.c;
1371             }
1372         }
1373     }
1374
1375     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1376         + "{v = new Date(y, m, d, h, i, s);}\n"
1377         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1378         + "{v = new Date(y, m, d, h, i);}\n"
1379         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1380         + "{v = new Date(y, m, d, h);}\n"
1381         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1382         + "{v = new Date(y, m, d);}\n"
1383         + "else if (y >= 0 && m >= 0)\n"
1384         + "{v = new Date(y, m);}\n"
1385         + "else if (y >= 0)\n"
1386         + "{v = new Date(y);}\n"
1387         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1388         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1389         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1390         + ";}";
1391
1392     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1393     /** eval:var:zzzzzzzzzzzzz */
1394     eval(code);
1395 };
1396
1397 // private
1398 Date.formatCodeToRegex = function(character, currentGroup) {
1399     switch (character) {
1400     case "D":
1401         return {g:0,
1402         c:null,
1403         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1404     case "j":
1405         return {g:1,
1406             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1407             s:"(\\d{1,2})"}; // day of month without leading zeroes
1408     case "d":
1409         return {g:1,
1410             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1411             s:"(\\d{2})"}; // day of month with leading zeroes
1412     case "l":
1413         return {g:0,
1414             c:null,
1415             s:"(?:" + Date.dayNames.join("|") + ")"};
1416     case "S":
1417         return {g:0,
1418             c:null,
1419             s:"(?:st|nd|rd|th)"};
1420     case "w":
1421         return {g:0,
1422             c:null,
1423             s:"\\d"};
1424     case "z":
1425         return {g:0,
1426             c:null,
1427             s:"(?:\\d{1,3})"};
1428     case "W":
1429         return {g:0,
1430             c:null,
1431             s:"(?:\\d{2})"};
1432     case "F":
1433         return {g:1,
1434             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1435             s:"(" + Date.monthNames.join("|") + ")"};
1436     case "M":
1437         return {g:1,
1438             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1439             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1440     case "n":
1441         return {g:1,
1442             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1443             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1444     case "m":
1445         return {g:1,
1446             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1447             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1448     case "t":
1449         return {g:0,
1450             c:null,
1451             s:"\\d{1,2}"};
1452     case "L":
1453         return {g:0,
1454             c:null,
1455             s:"(?:1|0)"};
1456     case "Y":
1457         return {g:1,
1458             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1459             s:"(\\d{4})"};
1460     case "y":
1461         return {g:1,
1462             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1463                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1464             s:"(\\d{1,2})"};
1465     case "a":
1466         return {g:1,
1467             c:"if (results[" + currentGroup + "] == 'am') {\n"
1468                 + "if (h == 12) { h = 0; }\n"
1469                 + "} else { if (h < 12) { h += 12; }}",
1470             s:"(am|pm)"};
1471     case "A":
1472         return {g:1,
1473             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1474                 + "if (h == 12) { h = 0; }\n"
1475                 + "} else { if (h < 12) { h += 12; }}",
1476             s:"(AM|PM)"};
1477     case "g":
1478     case "G":
1479         return {g:1,
1480             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1481             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1482     case "h":
1483     case "H":
1484         return {g:1,
1485             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1486             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1487     case "i":
1488         return {g:1,
1489             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1490             s:"(\\d{2})"};
1491     case "s":
1492         return {g:1,
1493             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1494             s:"(\\d{2})"};
1495     case "O":
1496         return {g:1,
1497             c:[
1498                 "o = results[", currentGroup, "];\n",
1499                 "var sn = o.substring(0,1);\n", // get + / - sign
1500                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1501                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1502                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1503                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1504             ].join(""),
1505             s:"([+\-]\\d{2,4})"};
1506     
1507     
1508     case "P":
1509         return {g:1,
1510                 c:[
1511                    "o = results[", currentGroup, "];\n",
1512                    "var sn = o.substring(0,1);\n",
1513                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1514                    "var mn = o.substring(4,6) % 60;\n",
1515                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1516                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1517             ].join(""),
1518             s:"([+\-]\\d{4})"};
1519     case "T":
1520         return {g:0,
1521             c:null,
1522             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1523     case "Z":
1524         return {g:1,
1525             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1526                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1527             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1528     default:
1529         return {g:0,
1530             c:null,
1531             s:String.escape(character)};
1532     }
1533 };
1534
1535 /**
1536  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1537  * @return {String} The abbreviated timezone name (e.g. 'CST')
1538  */
1539 Date.prototype.getTimezone = function() {
1540     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1541 };
1542
1543 /**
1544  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1545  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1546  */
1547 Date.prototype.getGMTOffset = function() {
1548     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1549         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1550         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1551 };
1552
1553 /**
1554  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1555  * @return {String} 2-characters representing hours and 2-characters representing minutes
1556  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1557  */
1558 Date.prototype.getGMTColonOffset = function() {
1559         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1560                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1561                 + ":"
1562                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1563 }
1564
1565 /**
1566  * Get the numeric day number of the year, adjusted for leap year.
1567  * @return {Number} 0 through 364 (365 in leap years)
1568  */
1569 Date.prototype.getDayOfYear = function() {
1570     var num = 0;
1571     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1572     for (var i = 0; i < this.getMonth(); ++i) {
1573         num += Date.daysInMonth[i];
1574     }
1575     return num + this.getDate() - 1;
1576 };
1577
1578 /**
1579  * Get the string representation of the numeric week number of the year
1580  * (equivalent to the format specifier 'W').
1581  * @return {String} '00' through '52'
1582  */
1583 Date.prototype.getWeekOfYear = function() {
1584     // Skip to Thursday of this week
1585     var now = this.getDayOfYear() + (4 - this.getDay());
1586     // Find the first Thursday of the year
1587     var jan1 = new Date(this.getFullYear(), 0, 1);
1588     var then = (7 - jan1.getDay() + 4);
1589     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1590 };
1591
1592 /**
1593  * Whether or not the current date is in a leap year.
1594  * @return {Boolean} True if the current date is in a leap year, else false
1595  */
1596 Date.prototype.isLeapYear = function() {
1597     var year = this.getFullYear();
1598     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1599 };
1600
1601 /**
1602  * Get the first day of the current month, adjusted for leap year.  The returned value
1603  * is the numeric day index within the week (0-6) which can be used in conjunction with
1604  * the {@link #monthNames} array to retrieve the textual day name.
1605  * Example:
1606  *<pre><code>
1607 var dt = new Date('1/10/2007');
1608 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1609 </code></pre>
1610  * @return {Number} The day number (0-6)
1611  */
1612 Date.prototype.getFirstDayOfMonth = function() {
1613     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1614     return (day < 0) ? (day + 7) : day;
1615 };
1616
1617 /**
1618  * Get the last day of the current month, adjusted for leap year.  The returned value
1619  * is the numeric day index within the week (0-6) which can be used in conjunction with
1620  * the {@link #monthNames} array to retrieve the textual day name.
1621  * Example:
1622  *<pre><code>
1623 var dt = new Date('1/10/2007');
1624 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1625 </code></pre>
1626  * @return {Number} The day number (0-6)
1627  */
1628 Date.prototype.getLastDayOfMonth = function() {
1629     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1630     return (day < 0) ? (day + 7) : day;
1631 };
1632
1633
1634 /**
1635  * Get the first date of this date's month
1636  * @return {Date}
1637  */
1638 Date.prototype.getFirstDateOfMonth = function() {
1639     return new Date(this.getFullYear(), this.getMonth(), 1);
1640 };
1641
1642 /**
1643  * Get the last date of this date's month
1644  * @return {Date}
1645  */
1646 Date.prototype.getLastDateOfMonth = function() {
1647     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1648 };
1649 /**
1650  * Get the number of days in the current month, adjusted for leap year.
1651  * @return {Number} The number of days in the month
1652  */
1653 Date.prototype.getDaysInMonth = function() {
1654     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1655     return Date.daysInMonth[this.getMonth()];
1656 };
1657
1658 /**
1659  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1660  * @return {String} 'st, 'nd', 'rd' or 'th'
1661  */
1662 Date.prototype.getSuffix = function() {
1663     switch (this.getDate()) {
1664         case 1:
1665         case 21:
1666         case 31:
1667             return "st";
1668         case 2:
1669         case 22:
1670             return "nd";
1671         case 3:
1672         case 23:
1673             return "rd";
1674         default:
1675             return "th";
1676     }
1677 };
1678
1679 // private
1680 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1681
1682 /**
1683  * An array of textual month names.
1684  * Override these values for international dates, for example...
1685  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1686  * @type Array
1687  * @static
1688  */
1689 Date.monthNames =
1690    ["January",
1691     "February",
1692     "March",
1693     "April",
1694     "May",
1695     "June",
1696     "July",
1697     "August",
1698     "September",
1699     "October",
1700     "November",
1701     "December"];
1702
1703 /**
1704  * An array of textual day names.
1705  * Override these values for international dates, for example...
1706  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1707  * @type Array
1708  * @static
1709  */
1710 Date.dayNames =
1711    ["Sunday",
1712     "Monday",
1713     "Tuesday",
1714     "Wednesday",
1715     "Thursday",
1716     "Friday",
1717     "Saturday"];
1718
1719 // private
1720 Date.y2kYear = 50;
1721 // private
1722 Date.monthNumbers = {
1723     Jan:0,
1724     Feb:1,
1725     Mar:2,
1726     Apr:3,
1727     May:4,
1728     Jun:5,
1729     Jul:6,
1730     Aug:7,
1731     Sep:8,
1732     Oct:9,
1733     Nov:10,
1734     Dec:11};
1735
1736 /**
1737  * Creates and returns a new Date instance with the exact same date value as the called instance.
1738  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1739  * variable will also be changed.  When the intention is to create a new variable that will not
1740  * modify the original instance, you should create a clone.
1741  *
1742  * Example of correctly cloning a date:
1743  * <pre><code>
1744 //wrong way:
1745 var orig = new Date('10/1/2006');
1746 var copy = orig;
1747 copy.setDate(5);
1748 document.write(orig);  //returns 'Thu Oct 05 2006'!
1749
1750 //correct way:
1751 var orig = new Date('10/1/2006');
1752 var copy = orig.clone();
1753 copy.setDate(5);
1754 document.write(orig);  //returns 'Thu Oct 01 2006'
1755 </code></pre>
1756  * @return {Date} The new Date instance
1757  */
1758 Date.prototype.clone = function() {
1759         return new Date(this.getTime());
1760 };
1761
1762 /**
1763  * Clears any time information from this date
1764  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1765  @return {Date} this or the clone
1766  */
1767 Date.prototype.clearTime = function(clone){
1768     if(clone){
1769         return this.clone().clearTime();
1770     }
1771     this.setHours(0);
1772     this.setMinutes(0);
1773     this.setSeconds(0);
1774     this.setMilliseconds(0);
1775     return this;
1776 };
1777
1778 // private
1779 // safari setMonth is broken -- check that this is only donw once...
1780 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1781     Date.brokenSetMonth = Date.prototype.setMonth;
1782         Date.prototype.setMonth = function(num){
1783                 if(num <= -1){
1784                         var n = Math.ceil(-num);
1785                         var back_year = Math.ceil(n/12);
1786                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1787                         this.setFullYear(this.getFullYear() - back_year);
1788                         return Date.brokenSetMonth.call(this, month);
1789                 } else {
1790                         return Date.brokenSetMonth.apply(this, arguments);
1791                 }
1792         };
1793 }
1794
1795 /** Date interval constant 
1796 * @static 
1797 * @type String */
1798 Date.MILLI = "ms";
1799 /** Date interval constant 
1800 * @static 
1801 * @type String */
1802 Date.SECOND = "s";
1803 /** Date interval constant 
1804 * @static 
1805 * @type String */
1806 Date.MINUTE = "mi";
1807 /** Date interval constant 
1808 * @static 
1809 * @type String */
1810 Date.HOUR = "h";
1811 /** Date interval constant 
1812 * @static 
1813 * @type String */
1814 Date.DAY = "d";
1815 /** Date interval constant 
1816 * @static 
1817 * @type String */
1818 Date.MONTH = "mo";
1819 /** Date interval constant 
1820 * @static 
1821 * @type String */
1822 Date.YEAR = "y";
1823
1824 /**
1825  * Provides a convenient method of performing basic date arithmetic.  This method
1826  * does not modify the Date instance being called - it creates and returns
1827  * a new Date instance containing the resulting date value.
1828  *
1829  * Examples:
1830  * <pre><code>
1831 //Basic usage:
1832 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1833 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1834
1835 //Negative values will subtract correctly:
1836 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1837 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1838
1839 //You can even chain several calls together in one line!
1840 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1841 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1842  </code></pre>
1843  *
1844  * @param {String} interval   A valid date interval enum value
1845  * @param {Number} value      The amount to add to the current date
1846  * @return {Date} The new Date instance
1847  */
1848 Date.prototype.add = function(interval, value){
1849   var d = this.clone();
1850   if (!interval || value === 0) { return d; }
1851   switch(interval.toLowerCase()){
1852     case Date.MILLI:
1853       d.setMilliseconds(this.getMilliseconds() + value);
1854       break;
1855     case Date.SECOND:
1856       d.setSeconds(this.getSeconds() + value);
1857       break;
1858     case Date.MINUTE:
1859       d.setMinutes(this.getMinutes() + value);
1860       break;
1861     case Date.HOUR:
1862       d.setHours(this.getHours() + value);
1863       break;
1864     case Date.DAY:
1865       d.setDate(this.getDate() + value);
1866       break;
1867     case Date.MONTH:
1868       var day = this.getDate();
1869       if(day > 28){
1870           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1871       }
1872       d.setDate(day);
1873       d.setMonth(this.getMonth() + value);
1874       break;
1875     case Date.YEAR:
1876       d.setFullYear(this.getFullYear() + value);
1877       break;
1878   }
1879   return d;
1880 };
1881 /**
1882  * @class Roo.lib.Dom
1883  * @licence LGPL
1884  * @static
1885  * 
1886  * Dom utils (from YIU afaik)
1887  *
1888  * 
1889  **/
1890 Roo.lib.Dom = {
1891     /**
1892      * Get the view width
1893      * @param {Boolean} full True will get the full document, otherwise it's the view width
1894      * @return {Number} The width
1895      */
1896      
1897     getViewWidth : function(full) {
1898         return full ? this.getDocumentWidth() : this.getViewportWidth();
1899     },
1900     /**
1901      * Get the view height
1902      * @param {Boolean} full True will get the full document, otherwise it's the view height
1903      * @return {Number} The height
1904      */
1905     getViewHeight : function(full) {
1906         return full ? this.getDocumentHeight() : this.getViewportHeight();
1907     },
1908     /**
1909      * Get the Full Document height 
1910      * @return {Number} The height
1911      */
1912     getDocumentHeight: function() {
1913         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1914         return Math.max(scrollHeight, this.getViewportHeight());
1915     },
1916     /**
1917      * Get the Full Document width
1918      * @return {Number} The width
1919      */
1920     getDocumentWidth: function() {
1921         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1922         return Math.max(scrollWidth, this.getViewportWidth());
1923     },
1924     /**
1925      * Get the Window Viewport height
1926      * @return {Number} The height
1927      */
1928     getViewportHeight: function() {
1929         var height = self.innerHeight;
1930         var mode = document.compatMode;
1931
1932         if ((mode || Roo.isIE) && !Roo.isOpera) {
1933             height = (mode == "CSS1Compat") ?
1934                      document.documentElement.clientHeight :
1935                      document.body.clientHeight;
1936         }
1937
1938         return height;
1939     },
1940     /**
1941      * Get the Window Viewport width
1942      * @return {Number} The width
1943      */
1944     getViewportWidth: function() {
1945         var width = self.innerWidth;
1946         var mode = document.compatMode;
1947
1948         if (mode || Roo.isIE) {
1949             width = (mode == "CSS1Compat") ?
1950                     document.documentElement.clientWidth :
1951                     document.body.clientWidth;
1952         }
1953         return width;
1954     },
1955
1956     isAncestor : function(p, c) {
1957         p = Roo.getDom(p);
1958         c = Roo.getDom(c);
1959         if (!p || !c) {
1960             return false;
1961         }
1962
1963         if (p.contains && !Roo.isSafari) {
1964             return p.contains(c);
1965         } else if (p.compareDocumentPosition) {
1966             return !!(p.compareDocumentPosition(c) & 16);
1967         } else {
1968             var parent = c.parentNode;
1969             while (parent) {
1970                 if (parent == p) {
1971                     return true;
1972                 }
1973                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1974                     return false;
1975                 }
1976                 parent = parent.parentNode;
1977             }
1978             return false;
1979         }
1980     },
1981
1982     getRegion : function(el) {
1983         return Roo.lib.Region.getRegion(el);
1984     },
1985
1986     getY : function(el) {
1987         return this.getXY(el)[1];
1988     },
1989
1990     getX : function(el) {
1991         return this.getXY(el)[0];
1992     },
1993
1994     getXY : function(el) {
1995         var p, pe, b, scroll, bd = document.body;
1996         el = Roo.getDom(el);
1997         var fly = Roo.lib.AnimBase.fly;
1998         if (el.getBoundingClientRect) {
1999             b = el.getBoundingClientRect();
2000             scroll = fly(document).getScroll();
2001             return [b.left + scroll.left, b.top + scroll.top];
2002         }
2003         var x = 0, y = 0;
2004
2005         p = el;
2006
2007         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2008
2009         while (p) {
2010
2011             x += p.offsetLeft;
2012             y += p.offsetTop;
2013
2014             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2015                 hasAbsolute = true;
2016             }
2017
2018             if (Roo.isGecko) {
2019                 pe = fly(p);
2020
2021                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2022                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2023
2024
2025                 x += bl;
2026                 y += bt;
2027
2028
2029                 if (p != el && pe.getStyle('overflow') != 'visible') {
2030                     x += bl;
2031                     y += bt;
2032                 }
2033             }
2034             p = p.offsetParent;
2035         }
2036
2037         if (Roo.isSafari && hasAbsolute) {
2038             x -= bd.offsetLeft;
2039             y -= bd.offsetTop;
2040         }
2041
2042         if (Roo.isGecko && !hasAbsolute) {
2043             var dbd = fly(bd);
2044             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2045             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2046         }
2047
2048         p = el.parentNode;
2049         while (p && p != bd) {
2050             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2051                 x -= p.scrollLeft;
2052                 y -= p.scrollTop;
2053             }
2054             p = p.parentNode;
2055         }
2056         return [x, y];
2057     },
2058  
2059   
2060
2061
2062     setXY : function(el, xy) {
2063         el = Roo.fly(el, '_setXY');
2064         el.position();
2065         var pts = el.translatePoints(xy);
2066         if (xy[0] !== false) {
2067             el.dom.style.left = pts.left + "px";
2068         }
2069         if (xy[1] !== false) {
2070             el.dom.style.top = pts.top + "px";
2071         }
2072     },
2073
2074     setX : function(el, x) {
2075         this.setXY(el, [x, false]);
2076     },
2077
2078     setY : function(el, y) {
2079         this.setXY(el, [false, y]);
2080     }
2081 };
2082 /*
2083  * Portions of this file are based on pieces of Yahoo User Interface Library
2084  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2085  * YUI licensed under the BSD License:
2086  * http://developer.yahoo.net/yui/license.txt
2087  * <script type="text/javascript">
2088  *
2089  */
2090
2091 Roo.lib.Event = function() {
2092     var loadComplete = false;
2093     var listeners = [];
2094     var unloadListeners = [];
2095     var retryCount = 0;
2096     var onAvailStack = [];
2097     var counter = 0;
2098     var lastError = null;
2099
2100     return {
2101         POLL_RETRYS: 200,
2102         POLL_INTERVAL: 20,
2103         EL: 0,
2104         TYPE: 1,
2105         FN: 2,
2106         WFN: 3,
2107         OBJ: 3,
2108         ADJ_SCOPE: 4,
2109         _interval: null,
2110
2111         startInterval: function() {
2112             if (!this._interval) {
2113                 var self = this;
2114                 var callback = function() {
2115                     self._tryPreloadAttach();
2116                 };
2117                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2118
2119             }
2120         },
2121
2122         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2123             onAvailStack.push({ id:         p_id,
2124                 fn:         p_fn,
2125                 obj:        p_obj,
2126                 override:   p_override,
2127                 checkReady: false    });
2128
2129             retryCount = this.POLL_RETRYS;
2130             this.startInterval();
2131         },
2132
2133
2134         addListener: function(el, eventName, fn) {
2135             el = Roo.getDom(el);
2136             if (!el || !fn) {
2137                 return false;
2138             }
2139
2140             if ("unload" == eventName) {
2141                 unloadListeners[unloadListeners.length] =
2142                 [el, eventName, fn];
2143                 return true;
2144             }
2145
2146             var wrappedFn = function(e) {
2147                 return fn(Roo.lib.Event.getEvent(e));
2148             };
2149
2150             var li = [el, eventName, fn, wrappedFn];
2151
2152             var index = listeners.length;
2153             listeners[index] = li;
2154
2155             this.doAdd(el, eventName, wrappedFn, false);
2156             return true;
2157
2158         },
2159
2160
2161         removeListener: function(el, eventName, fn) {
2162             var i, len;
2163
2164             el = Roo.getDom(el);
2165
2166             if(!fn) {
2167                 return this.purgeElement(el, false, eventName);
2168             }
2169
2170
2171             if ("unload" == eventName) {
2172
2173                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2174                     var li = unloadListeners[i];
2175                     if (li &&
2176                         li[0] == el &&
2177                         li[1] == eventName &&
2178                         li[2] == fn) {
2179                         unloadListeners.splice(i, 1);
2180                         return true;
2181                     }
2182                 }
2183
2184                 return false;
2185             }
2186
2187             var cacheItem = null;
2188
2189
2190             var index = arguments[3];
2191
2192             if ("undefined" == typeof index) {
2193                 index = this._getCacheIndex(el, eventName, fn);
2194             }
2195
2196             if (index >= 0) {
2197                 cacheItem = listeners[index];
2198             }
2199
2200             if (!el || !cacheItem) {
2201                 return false;
2202             }
2203
2204             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2205
2206             delete listeners[index][this.WFN];
2207             delete listeners[index][this.FN];
2208             listeners.splice(index, 1);
2209
2210             return true;
2211
2212         },
2213
2214
2215         getTarget: function(ev, resolveTextNode) {
2216             ev = ev.browserEvent || ev;
2217             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2218             var t = ev.target || ev.srcElement;
2219             return this.resolveTextNode(t);
2220         },
2221
2222
2223         resolveTextNode: function(node) {
2224             if (Roo.isSafari && node && 3 == node.nodeType) {
2225                 return node.parentNode;
2226             } else {
2227                 return node;
2228             }
2229         },
2230
2231
2232         getPageX: function(ev) {
2233             ev = ev.browserEvent || ev;
2234             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2235             var x = ev.pageX;
2236             if (!x && 0 !== x) {
2237                 x = ev.clientX || 0;
2238
2239                 if (Roo.isIE) {
2240                     x += this.getScroll()[1];
2241                 }
2242             }
2243
2244             return x;
2245         },
2246
2247
2248         getPageY: function(ev) {
2249             ev = ev.browserEvent || ev;
2250             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2251             var y = ev.pageY;
2252             if (!y && 0 !== y) {
2253                 y = ev.clientY || 0;
2254
2255                 if (Roo.isIE) {
2256                     y += this.getScroll()[0];
2257                 }
2258             }
2259
2260
2261             return y;
2262         },
2263
2264
2265         getXY: function(ev) {
2266             ev = ev.browserEvent || ev;
2267             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2268             return [this.getPageX(ev), this.getPageY(ev)];
2269         },
2270
2271
2272         getRelatedTarget: function(ev) {
2273             ev = ev.browserEvent || ev;
2274             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2275             var t = ev.relatedTarget;
2276             if (!t) {
2277                 if (ev.type == "mouseout") {
2278                     t = ev.toElement;
2279                 } else if (ev.type == "mouseover") {
2280                     t = ev.fromElement;
2281                 }
2282             }
2283
2284             return this.resolveTextNode(t);
2285         },
2286
2287
2288         getTime: function(ev) {
2289             ev = ev.browserEvent || ev;
2290             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2291             if (!ev.time) {
2292                 var t = new Date().getTime();
2293                 try {
2294                     ev.time = t;
2295                 } catch(ex) {
2296                     this.lastError = ex;
2297                     return t;
2298                 }
2299             }
2300
2301             return ev.time;
2302         },
2303
2304
2305         stopEvent: function(ev) {
2306             this.stopPropagation(ev);
2307             this.preventDefault(ev);
2308         },
2309
2310
2311         stopPropagation: function(ev) {
2312             ev = ev.browserEvent || ev;
2313             if (ev.stopPropagation) {
2314                 ev.stopPropagation();
2315             } else {
2316                 ev.cancelBubble = true;
2317             }
2318         },
2319
2320
2321         preventDefault: function(ev) {
2322             ev = ev.browserEvent || ev;
2323             if(ev.preventDefault) {
2324                 ev.preventDefault();
2325             } else {
2326                 ev.returnValue = false;
2327             }
2328         },
2329
2330
2331         getEvent: function(e) {
2332             var ev = e || window.event;
2333             if (!ev) {
2334                 var c = this.getEvent.caller;
2335                 while (c) {
2336                     ev = c.arguments[0];
2337                     if (ev && Event == ev.constructor) {
2338                         break;
2339                     }
2340                     c = c.caller;
2341                 }
2342             }
2343             return ev;
2344         },
2345
2346
2347         getCharCode: function(ev) {
2348             ev = ev.browserEvent || ev;
2349             return ev.charCode || ev.keyCode || 0;
2350         },
2351
2352
2353         _getCacheIndex: function(el, eventName, fn) {
2354             for (var i = 0,len = listeners.length; i < len; ++i) {
2355                 var li = listeners[i];
2356                 if (li &&
2357                     li[this.FN] == fn &&
2358                     li[this.EL] == el &&
2359                     li[this.TYPE] == eventName) {
2360                     return i;
2361                 }
2362             }
2363
2364             return -1;
2365         },
2366
2367
2368         elCache: {},
2369
2370
2371         getEl: function(id) {
2372             return document.getElementById(id);
2373         },
2374
2375
2376         clearCache: function() {
2377         },
2378
2379
2380         _load: function(e) {
2381             loadComplete = true;
2382             var EU = Roo.lib.Event;
2383
2384
2385             if (Roo.isIE) {
2386                 EU.doRemove(window, "load", EU._load);
2387             }
2388         },
2389
2390
2391         _tryPreloadAttach: function() {
2392
2393             if (this.locked) {
2394                 return false;
2395             }
2396
2397             this.locked = true;
2398
2399
2400             var tryAgain = !loadComplete;
2401             if (!tryAgain) {
2402                 tryAgain = (retryCount > 0);
2403             }
2404
2405
2406             var notAvail = [];
2407             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2408                 var item = onAvailStack[i];
2409                 if (item) {
2410                     var el = this.getEl(item.id);
2411
2412                     if (el) {
2413                         if (!item.checkReady ||
2414                             loadComplete ||
2415                             el.nextSibling ||
2416                             (document && document.body)) {
2417
2418                             var scope = el;
2419                             if (item.override) {
2420                                 if (item.override === true) {
2421                                     scope = item.obj;
2422                                 } else {
2423                                     scope = item.override;
2424                                 }
2425                             }
2426                             item.fn.call(scope, item.obj);
2427                             onAvailStack[i] = null;
2428                         }
2429                     } else {
2430                         notAvail.push(item);
2431                     }
2432                 }
2433             }
2434
2435             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2436
2437             if (tryAgain) {
2438
2439                 this.startInterval();
2440             } else {
2441                 clearInterval(this._interval);
2442                 this._interval = null;
2443             }
2444
2445             this.locked = false;
2446
2447             return true;
2448
2449         },
2450
2451
2452         purgeElement: function(el, recurse, eventName) {
2453             var elListeners = this.getListeners(el, eventName);
2454             if (elListeners) {
2455                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2456                     var l = elListeners[i];
2457                     this.removeListener(el, l.type, l.fn);
2458                 }
2459             }
2460
2461             if (recurse && el && el.childNodes) {
2462                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2463                     this.purgeElement(el.childNodes[i], recurse, eventName);
2464                 }
2465             }
2466         },
2467
2468
2469         getListeners: function(el, eventName) {
2470             var results = [], searchLists;
2471             if (!eventName) {
2472                 searchLists = [listeners, unloadListeners];
2473             } else if (eventName == "unload") {
2474                 searchLists = [unloadListeners];
2475             } else {
2476                 searchLists = [listeners];
2477             }
2478
2479             for (var j = 0; j < searchLists.length; ++j) {
2480                 var searchList = searchLists[j];
2481                 if (searchList && searchList.length > 0) {
2482                     for (var i = 0,len = searchList.length; i < len; ++i) {
2483                         var l = searchList[i];
2484                         if (l && l[this.EL] === el &&
2485                             (!eventName || eventName === l[this.TYPE])) {
2486                             results.push({
2487                                 type:   l[this.TYPE],
2488                                 fn:     l[this.FN],
2489                                 obj:    l[this.OBJ],
2490                                 adjust: l[this.ADJ_SCOPE],
2491                                 index:  i
2492                             });
2493                         }
2494                     }
2495                 }
2496             }
2497
2498             return (results.length) ? results : null;
2499         },
2500
2501
2502         _unload: function(e) {
2503
2504             var EU = Roo.lib.Event, i, j, l, len, index;
2505
2506             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2507                 l = unloadListeners[i];
2508                 if (l) {
2509                     var scope = window;
2510                     if (l[EU.ADJ_SCOPE]) {
2511                         if (l[EU.ADJ_SCOPE] === true) {
2512                             scope = l[EU.OBJ];
2513                         } else {
2514                             scope = l[EU.ADJ_SCOPE];
2515                         }
2516                     }
2517                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2518                     unloadListeners[i] = null;
2519                     l = null;
2520                     scope = null;
2521                 }
2522             }
2523
2524             unloadListeners = null;
2525
2526             if (listeners && listeners.length > 0) {
2527                 j = listeners.length;
2528                 while (j) {
2529                     index = j - 1;
2530                     l = listeners[index];
2531                     if (l) {
2532                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2533                                 l[EU.FN], index);
2534                     }
2535                     j = j - 1;
2536                 }
2537                 l = null;
2538
2539                 EU.clearCache();
2540             }
2541
2542             EU.doRemove(window, "unload", EU._unload);
2543
2544         },
2545
2546
2547         getScroll: function() {
2548             var dd = document.documentElement, db = document.body;
2549             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2550                 return [dd.scrollTop, dd.scrollLeft];
2551             } else if (db) {
2552                 return [db.scrollTop, db.scrollLeft];
2553             } else {
2554                 return [0, 0];
2555             }
2556         },
2557
2558
2559         doAdd: function () {
2560             if (window.addEventListener) {
2561                 return function(el, eventName, fn, capture) {
2562                     el.addEventListener(eventName, fn, (capture));
2563                 };
2564             } else if (window.attachEvent) {
2565                 return function(el, eventName, fn, capture) {
2566                     el.attachEvent("on" + eventName, fn);
2567                 };
2568             } else {
2569                 return function() {
2570                 };
2571             }
2572         }(),
2573
2574
2575         doRemove: function() {
2576             if (window.removeEventListener) {
2577                 return function (el, eventName, fn, capture) {
2578                     el.removeEventListener(eventName, fn, (capture));
2579                 };
2580             } else if (window.detachEvent) {
2581                 return function (el, eventName, fn) {
2582                     el.detachEvent("on" + eventName, fn);
2583                 };
2584             } else {
2585                 return function() {
2586                 };
2587             }
2588         }()
2589     };
2590     
2591 }();
2592 (function() {     
2593    
2594     var E = Roo.lib.Event;
2595     E.on = E.addListener;
2596     E.un = E.removeListener;
2597
2598     if (document && document.body) {
2599         E._load();
2600     } else {
2601         E.doAdd(window, "load", E._load);
2602     }
2603     E.doAdd(window, "unload", E._unload);
2604     E._tryPreloadAttach();
2605 })();
2606
2607 /*
2608  * Portions of this file are based on pieces of Yahoo User Interface Library
2609  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2610  * YUI licensed under the BSD License:
2611  * http://developer.yahoo.net/yui/license.txt
2612  * <script type="text/javascript">
2613  *
2614  */
2615
2616 (function() {
2617     /**
2618      * @class Roo.lib.Ajax
2619      *
2620      */
2621     Roo.lib.Ajax = {
2622         /**
2623          * @static 
2624          */
2625         request : function(method, uri, cb, data, options) {
2626             if(options){
2627                 var hs = options.headers;
2628                 if(hs){
2629                     for(var h in hs){
2630                         if(hs.hasOwnProperty(h)){
2631                             this.initHeader(h, hs[h], false);
2632                         }
2633                     }
2634                 }
2635                 if(options.xmlData){
2636                     this.initHeader('Content-Type', 'text/xml', false);
2637                     method = 'POST';
2638                     data = options.xmlData;
2639                 }
2640             }
2641
2642             return this.asyncRequest(method, uri, cb, data);
2643         },
2644
2645         serializeForm : function(form) {
2646             if(typeof form == 'string') {
2647                 form = (document.getElementById(form) || document.forms[form]);
2648             }
2649
2650             var el, name, val, disabled, data = '', hasSubmit = false;
2651             for (var i = 0; i < form.elements.length; i++) {
2652                 el = form.elements[i];
2653                 disabled = form.elements[i].disabled;
2654                 name = form.elements[i].name;
2655                 val = form.elements[i].value;
2656
2657                 if (!disabled && name){
2658                     switch (el.type)
2659                             {
2660                         case 'select-one':
2661                         case 'select-multiple':
2662                             for (var j = 0; j < el.options.length; j++) {
2663                                 if (el.options[j].selected) {
2664                                     if (Roo.isIE) {
2665                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2666                                     }
2667                                     else {
2668                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2669                                     }
2670                                 }
2671                             }
2672                             break;
2673                         case 'radio':
2674                         case 'checkbox':
2675                             if (el.checked) {
2676                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2677                             }
2678                             break;
2679                         case 'file':
2680
2681                         case undefined:
2682
2683                         case 'reset':
2684
2685                         case 'button':
2686
2687                             break;
2688                         case 'submit':
2689                             if(hasSubmit == false) {
2690                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2691                                 hasSubmit = true;
2692                             }
2693                             break;
2694                         default:
2695                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2696                             break;
2697                     }
2698                 }
2699             }
2700             data = data.substr(0, data.length - 1);
2701             return data;
2702         },
2703
2704         headers:{},
2705
2706         hasHeaders:false,
2707
2708         useDefaultHeader:true,
2709
2710         defaultPostHeader:'application/x-www-form-urlencoded',
2711
2712         useDefaultXhrHeader:true,
2713
2714         defaultXhrHeader:'XMLHttpRequest',
2715
2716         hasDefaultHeaders:true,
2717
2718         defaultHeaders:{},
2719
2720         poll:{},
2721
2722         timeout:{},
2723
2724         pollInterval:50,
2725
2726         transactionId:0,
2727
2728         setProgId:function(id)
2729         {
2730             this.activeX.unshift(id);
2731         },
2732
2733         setDefaultPostHeader:function(b)
2734         {
2735             this.useDefaultHeader = b;
2736         },
2737
2738         setDefaultXhrHeader:function(b)
2739         {
2740             this.useDefaultXhrHeader = b;
2741         },
2742
2743         setPollingInterval:function(i)
2744         {
2745             if (typeof i == 'number' && isFinite(i)) {
2746                 this.pollInterval = i;
2747             }
2748         },
2749
2750         createXhrObject:function(transactionId)
2751         {
2752             var obj,http;
2753             try
2754             {
2755
2756                 http = new XMLHttpRequest();
2757
2758                 obj = { conn:http, tId:transactionId };
2759             }
2760             catch(e)
2761             {
2762                 for (var i = 0; i < this.activeX.length; ++i) {
2763                     try
2764                     {
2765
2766                         http = new ActiveXObject(this.activeX[i]);
2767
2768                         obj = { conn:http, tId:transactionId };
2769                         break;
2770                     }
2771                     catch(e) {
2772                     }
2773                 }
2774             }
2775             finally
2776             {
2777                 return obj;
2778             }
2779         },
2780
2781         getConnectionObject:function()
2782         {
2783             var o;
2784             var tId = this.transactionId;
2785
2786             try
2787             {
2788                 o = this.createXhrObject(tId);
2789                 if (o) {
2790                     this.transactionId++;
2791                 }
2792             }
2793             catch(e) {
2794             }
2795             finally
2796             {
2797                 return o;
2798             }
2799         },
2800
2801         asyncRequest:function(method, uri, callback, postData)
2802         {
2803             var o = this.getConnectionObject();
2804
2805             if (!o) {
2806                 return null;
2807             }
2808             else {
2809                 o.conn.open(method, uri, true);
2810
2811                 if (this.useDefaultXhrHeader) {
2812                     if (!this.defaultHeaders['X-Requested-With']) {
2813                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2814                     }
2815                 }
2816
2817                 if(postData && this.useDefaultHeader){
2818                     this.initHeader('Content-Type', this.defaultPostHeader);
2819                 }
2820
2821                  if (this.hasDefaultHeaders || this.hasHeaders) {
2822                     this.setHeader(o);
2823                 }
2824
2825                 this.handleReadyState(o, callback);
2826                 o.conn.send(postData || null);
2827
2828                 return o;
2829             }
2830         },
2831
2832         handleReadyState:function(o, callback)
2833         {
2834             var oConn = this;
2835
2836             if (callback && callback.timeout) {
2837                 
2838                 this.timeout[o.tId] = window.setTimeout(function() {
2839                     oConn.abort(o, callback, true);
2840                 }, callback.timeout);
2841             }
2842
2843             this.poll[o.tId] = window.setInterval(
2844                     function() {
2845                         if (o.conn && o.conn.readyState == 4) {
2846                             window.clearInterval(oConn.poll[o.tId]);
2847                             delete oConn.poll[o.tId];
2848
2849                             if(callback && callback.timeout) {
2850                                 window.clearTimeout(oConn.timeout[o.tId]);
2851                                 delete oConn.timeout[o.tId];
2852                             }
2853
2854                             oConn.handleTransactionResponse(o, callback);
2855                         }
2856                     }
2857                     , this.pollInterval);
2858         },
2859
2860         handleTransactionResponse:function(o, callback, isAbort)
2861         {
2862
2863             if (!callback) {
2864                 this.releaseObject(o);
2865                 return;
2866             }
2867
2868             var httpStatus, responseObject;
2869
2870             try
2871             {
2872                 if (o.conn.status !== undefined && o.conn.status != 0) {
2873                     httpStatus = o.conn.status;
2874                 }
2875                 else {
2876                     httpStatus = 13030;
2877                 }
2878             }
2879             catch(e) {
2880
2881
2882                 httpStatus = 13030;
2883             }
2884
2885             if (httpStatus >= 200 && httpStatus < 300) {
2886                 responseObject = this.createResponseObject(o, callback.argument);
2887                 if (callback.success) {
2888                     if (!callback.scope) {
2889                         callback.success(responseObject);
2890                     }
2891                     else {
2892
2893
2894                         callback.success.apply(callback.scope, [responseObject]);
2895                     }
2896                 }
2897             }
2898             else {
2899                 switch (httpStatus) {
2900
2901                     case 12002:
2902                     case 12029:
2903                     case 12030:
2904                     case 12031:
2905                     case 12152:
2906                     case 13030:
2907                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2908                         if (callback.failure) {
2909                             if (!callback.scope) {
2910                                 callback.failure(responseObject);
2911                             }
2912                             else {
2913                                 callback.failure.apply(callback.scope, [responseObject]);
2914                             }
2915                         }
2916                         break;
2917                     default:
2918                         responseObject = this.createResponseObject(o, callback.argument);
2919                         if (callback.failure) {
2920                             if (!callback.scope) {
2921                                 callback.failure(responseObject);
2922                             }
2923                             else {
2924                                 callback.failure.apply(callback.scope, [responseObject]);
2925                             }
2926                         }
2927                 }
2928             }
2929
2930             this.releaseObject(o);
2931             responseObject = null;
2932         },
2933
2934         createResponseObject:function(o, callbackArg)
2935         {
2936             var obj = {};
2937             var headerObj = {};
2938
2939             try
2940             {
2941                 var headerStr = o.conn.getAllResponseHeaders();
2942                 var header = headerStr.split('\n');
2943                 for (var i = 0; i < header.length; i++) {
2944                     var delimitPos = header[i].indexOf(':');
2945                     if (delimitPos != -1) {
2946                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2947                     }
2948                 }
2949             }
2950             catch(e) {
2951             }
2952
2953             obj.tId = o.tId;
2954             obj.status = o.conn.status;
2955             obj.statusText = o.conn.statusText;
2956             obj.getResponseHeader = headerObj;
2957             obj.getAllResponseHeaders = headerStr;
2958             obj.responseText = o.conn.responseText;
2959             obj.responseXML = o.conn.responseXML;
2960
2961             if (typeof callbackArg !== undefined) {
2962                 obj.argument = callbackArg;
2963             }
2964
2965             return obj;
2966         },
2967
2968         createExceptionObject:function(tId, callbackArg, isAbort)
2969         {
2970             var COMM_CODE = 0;
2971             var COMM_ERROR = 'communication failure';
2972             var ABORT_CODE = -1;
2973             var ABORT_ERROR = 'transaction aborted';
2974
2975             var obj = {};
2976
2977             obj.tId = tId;
2978             if (isAbort) {
2979                 obj.status = ABORT_CODE;
2980                 obj.statusText = ABORT_ERROR;
2981             }
2982             else {
2983                 obj.status = COMM_CODE;
2984                 obj.statusText = COMM_ERROR;
2985             }
2986
2987             if (callbackArg) {
2988                 obj.argument = callbackArg;
2989             }
2990
2991             return obj;
2992         },
2993
2994         initHeader:function(label, value, isDefault)
2995         {
2996             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2997
2998             if (headerObj[label] === undefined) {
2999                 headerObj[label] = value;
3000             }
3001             else {
3002
3003
3004                 headerObj[label] = value + "," + headerObj[label];
3005             }
3006
3007             if (isDefault) {
3008                 this.hasDefaultHeaders = true;
3009             }
3010             else {
3011                 this.hasHeaders = true;
3012             }
3013         },
3014
3015
3016         setHeader:function(o)
3017         {
3018             if (this.hasDefaultHeaders) {
3019                 for (var prop in this.defaultHeaders) {
3020                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3021                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3022                     }
3023                 }
3024             }
3025
3026             if (this.hasHeaders) {
3027                 for (var prop in this.headers) {
3028                     if (this.headers.hasOwnProperty(prop)) {
3029                         o.conn.setRequestHeader(prop, this.headers[prop]);
3030                     }
3031                 }
3032                 this.headers = {};
3033                 this.hasHeaders = false;
3034             }
3035         },
3036
3037         resetDefaultHeaders:function() {
3038             delete this.defaultHeaders;
3039             this.defaultHeaders = {};
3040             this.hasDefaultHeaders = false;
3041         },
3042
3043         abort:function(o, callback, isTimeout)
3044         {
3045             if(this.isCallInProgress(o)) {
3046                 o.conn.abort();
3047                 window.clearInterval(this.poll[o.tId]);
3048                 delete this.poll[o.tId];
3049                 if (isTimeout) {
3050                     delete this.timeout[o.tId];
3051                 }
3052
3053                 this.handleTransactionResponse(o, callback, true);
3054
3055                 return true;
3056             }
3057             else {
3058                 return false;
3059             }
3060         },
3061
3062
3063         isCallInProgress:function(o)
3064         {
3065             if (o && o.conn) {
3066                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3067             }
3068             else {
3069
3070                 return false;
3071             }
3072         },
3073
3074
3075         releaseObject:function(o)
3076         {
3077
3078             o.conn = null;
3079
3080             o = null;
3081         },
3082
3083         activeX:[
3084         'MSXML2.XMLHTTP.3.0',
3085         'MSXML2.XMLHTTP',
3086         'Microsoft.XMLHTTP'
3087         ]
3088
3089
3090     };
3091 })();/*
3092  * Portions of this file are based on pieces of Yahoo User Interface Library
3093  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3094  * YUI licensed under the BSD License:
3095  * http://developer.yahoo.net/yui/license.txt
3096  * <script type="text/javascript">
3097  *
3098  */
3099
3100 Roo.lib.Region = function(t, r, b, l) {
3101     this.top = t;
3102     this[1] = t;
3103     this.right = r;
3104     this.bottom = b;
3105     this.left = l;
3106     this[0] = l;
3107 };
3108
3109
3110 Roo.lib.Region.prototype = {
3111     contains : function(region) {
3112         return ( region.left >= this.left &&
3113                  region.right <= this.right &&
3114                  region.top >= this.top &&
3115                  region.bottom <= this.bottom    );
3116
3117     },
3118
3119     getArea : function() {
3120         return ( (this.bottom - this.top) * (this.right - this.left) );
3121     },
3122
3123     intersect : function(region) {
3124         var t = Math.max(this.top, region.top);
3125         var r = Math.min(this.right, region.right);
3126         var b = Math.min(this.bottom, region.bottom);
3127         var l = Math.max(this.left, region.left);
3128
3129         if (b >= t && r >= l) {
3130             return new Roo.lib.Region(t, r, b, l);
3131         } else {
3132             return null;
3133         }
3134     },
3135     union : function(region) {
3136         var t = Math.min(this.top, region.top);
3137         var r = Math.max(this.right, region.right);
3138         var b = Math.max(this.bottom, region.bottom);
3139         var l = Math.min(this.left, region.left);
3140
3141         return new Roo.lib.Region(t, r, b, l);
3142     },
3143
3144     adjust : function(t, l, b, r) {
3145         this.top += t;
3146         this.left += l;
3147         this.right += r;
3148         this.bottom += b;
3149         return this;
3150     }
3151 };
3152
3153 Roo.lib.Region.getRegion = function(el) {
3154     var p = Roo.lib.Dom.getXY(el);
3155
3156     var t = p[1];
3157     var r = p[0] + el.offsetWidth;
3158     var b = p[1] + el.offsetHeight;
3159     var l = p[0];
3160
3161     return new Roo.lib.Region(t, r, b, l);
3162 };
3163 /*
3164  * Portions of this file are based on pieces of Yahoo User Interface Library
3165  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3166  * YUI licensed under the BSD License:
3167  * http://developer.yahoo.net/yui/license.txt
3168  * <script type="text/javascript">
3169  *
3170  */
3171 //@@dep Roo.lib.Region
3172
3173
3174 Roo.lib.Point = function(x, y) {
3175     if (x instanceof Array) {
3176         y = x[1];
3177         x = x[0];
3178     }
3179     this.x = this.right = this.left = this[0] = x;
3180     this.y = this.top = this.bottom = this[1] = y;
3181 };
3182
3183 Roo.lib.Point.prototype = new Roo.lib.Region();
3184 /*
3185  * Portions of this file are based on pieces of Yahoo User Interface Library
3186  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3187  * YUI licensed under the BSD License:
3188  * http://developer.yahoo.net/yui/license.txt
3189  * <script type="text/javascript">
3190  *
3191  */
3192  
3193 (function() {   
3194
3195     Roo.lib.Anim = {
3196         scroll : function(el, args, duration, easing, cb, scope) {
3197             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3198         },
3199
3200         motion : function(el, args, duration, easing, cb, scope) {
3201             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3202         },
3203
3204         color : function(el, args, duration, easing, cb, scope) {
3205             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3206         },
3207
3208         run : function(el, args, duration, easing, cb, scope, type) {
3209             type = type || Roo.lib.AnimBase;
3210             if (typeof easing == "string") {
3211                 easing = Roo.lib.Easing[easing];
3212             }
3213             var anim = new type(el, args, duration, easing);
3214             anim.animateX(function() {
3215                 Roo.callback(cb, scope);
3216             });
3217             return anim;
3218         }
3219     };
3220 })();/*
3221  * Portions of this file are based on pieces of Yahoo User Interface Library
3222  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3223  * YUI licensed under the BSD License:
3224  * http://developer.yahoo.net/yui/license.txt
3225  * <script type="text/javascript">
3226  *
3227  */
3228
3229 (function() {    
3230     var libFlyweight;
3231     
3232     function fly(el) {
3233         if (!libFlyweight) {
3234             libFlyweight = new Roo.Element.Flyweight();
3235         }
3236         libFlyweight.dom = el;
3237         return libFlyweight;
3238     }
3239
3240     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3241     
3242    
3243     
3244     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3245         if (el) {
3246             this.init(el, attributes, duration, method);
3247         }
3248     };
3249
3250     Roo.lib.AnimBase.fly = fly;
3251     
3252     
3253     
3254     Roo.lib.AnimBase.prototype = {
3255
3256         toString: function() {
3257             var el = this.getEl();
3258             var id = el.id || el.tagName;
3259             return ("Anim " + id);
3260         },
3261
3262         patterns: {
3263             noNegatives:        /width|height|opacity|padding/i,
3264             offsetAttribute:  /^((width|height)|(top|left))$/,
3265             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3266             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3267         },
3268
3269
3270         doMethod: function(attr, start, end) {
3271             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3272         },
3273
3274
3275         setAttribute: function(attr, val, unit) {
3276             if (this.patterns.noNegatives.test(attr)) {
3277                 val = (val > 0) ? val : 0;
3278             }
3279
3280             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3281         },
3282
3283
3284         getAttribute: function(attr) {
3285             var el = this.getEl();
3286             var val = fly(el).getStyle(attr);
3287
3288             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3289                 return parseFloat(val);
3290             }
3291
3292             var a = this.patterns.offsetAttribute.exec(attr) || [];
3293             var pos = !!( a[3] );
3294             var box = !!( a[2] );
3295
3296
3297             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3298                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3299             } else {
3300                 val = 0;
3301             }
3302
3303             return val;
3304         },
3305
3306
3307         getDefaultUnit: function(attr) {
3308             if (this.patterns.defaultUnit.test(attr)) {
3309                 return 'px';
3310             }
3311
3312             return '';
3313         },
3314
3315         animateX : function(callback, scope) {
3316             var f = function() {
3317                 this.onComplete.removeListener(f);
3318                 if (typeof callback == "function") {
3319                     callback.call(scope || this, this);
3320                 }
3321             };
3322             this.onComplete.addListener(f, this);
3323             this.animate();
3324         },
3325
3326
3327         setRuntimeAttribute: function(attr) {
3328             var start;
3329             var end;
3330             var attributes = this.attributes;
3331
3332             this.runtimeAttributes[attr] = {};
3333
3334             var isset = function(prop) {
3335                 return (typeof prop !== 'undefined');
3336             };
3337
3338             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3339                 return false;
3340             }
3341
3342             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3343
3344
3345             if (isset(attributes[attr]['to'])) {
3346                 end = attributes[attr]['to'];
3347             } else if (isset(attributes[attr]['by'])) {
3348                 if (start.constructor == Array) {
3349                     end = [];
3350                     for (var i = 0, len = start.length; i < len; ++i) {
3351                         end[i] = start[i] + attributes[attr]['by'][i];
3352                     }
3353                 } else {
3354                     end = start + attributes[attr]['by'];
3355                 }
3356             }
3357
3358             this.runtimeAttributes[attr].start = start;
3359             this.runtimeAttributes[attr].end = end;
3360
3361
3362             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3363         },
3364
3365
3366         init: function(el, attributes, duration, method) {
3367
3368             var isAnimated = false;
3369
3370
3371             var startTime = null;
3372
3373
3374             var actualFrames = 0;
3375
3376
3377             el = Roo.getDom(el);
3378
3379
3380             this.attributes = attributes || {};
3381
3382
3383             this.duration = duration || 1;
3384
3385
3386             this.method = method || Roo.lib.Easing.easeNone;
3387
3388
3389             this.useSeconds = true;
3390
3391
3392             this.currentFrame = 0;
3393
3394
3395             this.totalFrames = Roo.lib.AnimMgr.fps;
3396
3397
3398             this.getEl = function() {
3399                 return el;
3400             };
3401
3402
3403             this.isAnimated = function() {
3404                 return isAnimated;
3405             };
3406
3407
3408             this.getStartTime = function() {
3409                 return startTime;
3410             };
3411
3412             this.runtimeAttributes = {};
3413
3414
3415             this.animate = function() {
3416                 if (this.isAnimated()) {
3417                     return false;
3418                 }
3419
3420                 this.currentFrame = 0;
3421
3422                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3423
3424                 Roo.lib.AnimMgr.registerElement(this);
3425             };
3426
3427
3428             this.stop = function(finish) {
3429                 if (finish) {
3430                     this.currentFrame = this.totalFrames;
3431                     this._onTween.fire();
3432                 }
3433                 Roo.lib.AnimMgr.stop(this);
3434             };
3435
3436             var onStart = function() {
3437                 this.onStart.fire();
3438
3439                 this.runtimeAttributes = {};
3440                 for (var attr in this.attributes) {
3441                     this.setRuntimeAttribute(attr);
3442                 }
3443
3444                 isAnimated = true;
3445                 actualFrames = 0;
3446                 startTime = new Date();
3447             };
3448
3449
3450             var onTween = function() {
3451                 var data = {
3452                     duration: new Date() - this.getStartTime(),
3453                     currentFrame: this.currentFrame
3454                 };
3455
3456                 data.toString = function() {
3457                     return (
3458                             'duration: ' + data.duration +
3459                             ', currentFrame: ' + data.currentFrame
3460                             );
3461                 };
3462
3463                 this.onTween.fire(data);
3464
3465                 var runtimeAttributes = this.runtimeAttributes;
3466
3467                 for (var attr in runtimeAttributes) {
3468                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3469                 }
3470
3471                 actualFrames += 1;
3472             };
3473
3474             var onComplete = function() {
3475                 var actual_duration = (new Date() - startTime) / 1000 ;
3476
3477                 var data = {
3478                     duration: actual_duration,
3479                     frames: actualFrames,
3480                     fps: actualFrames / actual_duration
3481                 };
3482
3483                 data.toString = function() {
3484                     return (
3485                             'duration: ' + data.duration +
3486                             ', frames: ' + data.frames +
3487                             ', fps: ' + data.fps
3488                             );
3489                 };
3490
3491                 isAnimated = false;
3492                 actualFrames = 0;
3493                 this.onComplete.fire(data);
3494             };
3495
3496
3497             this._onStart = new Roo.util.Event(this);
3498             this.onStart = new Roo.util.Event(this);
3499             this.onTween = new Roo.util.Event(this);
3500             this._onTween = new Roo.util.Event(this);
3501             this.onComplete = new Roo.util.Event(this);
3502             this._onComplete = new Roo.util.Event(this);
3503             this._onStart.addListener(onStart);
3504             this._onTween.addListener(onTween);
3505             this._onComplete.addListener(onComplete);
3506         }
3507     };
3508 })();
3509 /*
3510  * Portions of this file are based on pieces of Yahoo User Interface Library
3511  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3512  * YUI licensed under the BSD License:
3513  * http://developer.yahoo.net/yui/license.txt
3514  * <script type="text/javascript">
3515  *
3516  */
3517
3518 Roo.lib.AnimMgr = new function() {
3519
3520     var thread = null;
3521
3522
3523     var queue = [];
3524
3525
3526     var tweenCount = 0;
3527
3528
3529     this.fps = 1000;
3530
3531
3532     this.delay = 1;
3533
3534
3535     this.registerElement = function(tween) {
3536         queue[queue.length] = tween;
3537         tweenCount += 1;
3538         tween._onStart.fire();
3539         this.start();
3540     };
3541
3542
3543     this.unRegister = function(tween, index) {
3544         tween._onComplete.fire();
3545         index = index || getIndex(tween);
3546         if (index != -1) {
3547             queue.splice(index, 1);
3548         }
3549
3550         tweenCount -= 1;
3551         if (tweenCount <= 0) {
3552             this.stop();
3553         }
3554     };
3555
3556
3557     this.start = function() {
3558         if (thread === null) {
3559             thread = setInterval(this.run, this.delay);
3560         }
3561     };
3562
3563
3564     this.stop = function(tween) {
3565         if (!tween) {
3566             clearInterval(thread);
3567
3568             for (var i = 0, len = queue.length; i < len; ++i) {
3569                 if (queue[0].isAnimated()) {
3570                     this.unRegister(queue[0], 0);
3571                 }
3572             }
3573
3574             queue = [];
3575             thread = null;
3576             tweenCount = 0;
3577         }
3578         else {
3579             this.unRegister(tween);
3580         }
3581     };
3582
3583
3584     this.run = function() {
3585         for (var i = 0, len = queue.length; i < len; ++i) {
3586             var tween = queue[i];
3587             if (!tween || !tween.isAnimated()) {
3588                 continue;
3589             }
3590
3591             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3592             {
3593                 tween.currentFrame += 1;
3594
3595                 if (tween.useSeconds) {
3596                     correctFrame(tween);
3597                 }
3598                 tween._onTween.fire();
3599             }
3600             else {
3601                 Roo.lib.AnimMgr.stop(tween, i);
3602             }
3603         }
3604     };
3605
3606     var getIndex = function(anim) {
3607         for (var i = 0, len = queue.length; i < len; ++i) {
3608             if (queue[i] == anim) {
3609                 return i;
3610             }
3611         }
3612         return -1;
3613     };
3614
3615
3616     var correctFrame = function(tween) {
3617         var frames = tween.totalFrames;
3618         var frame = tween.currentFrame;
3619         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3620         var elapsed = (new Date() - tween.getStartTime());
3621         var tweak = 0;
3622
3623         if (elapsed < tween.duration * 1000) {
3624             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3625         } else {
3626             tweak = frames - (frame + 1);
3627         }
3628         if (tweak > 0 && isFinite(tweak)) {
3629             if (tween.currentFrame + tweak >= frames) {
3630                 tweak = frames - (frame + 1);
3631             }
3632
3633             tween.currentFrame += tweak;
3634         }
3635     };
3636 };
3637
3638     /*
3639  * Portions of this file are based on pieces of Yahoo User Interface Library
3640  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3641  * YUI licensed under the BSD License:
3642  * http://developer.yahoo.net/yui/license.txt
3643  * <script type="text/javascript">
3644  *
3645  */
3646 Roo.lib.Bezier = new function() {
3647
3648         this.getPosition = function(points, t) {
3649             var n = points.length;
3650             var tmp = [];
3651
3652             for (var i = 0; i < n; ++i) {
3653                 tmp[i] = [points[i][0], points[i][1]];
3654             }
3655
3656             for (var j = 1; j < n; ++j) {
3657                 for (i = 0; i < n - j; ++i) {
3658                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3659                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3660                 }
3661             }
3662
3663             return [ tmp[0][0], tmp[0][1] ];
3664
3665         };
3666     };/*
3667  * Portions of this file are based on pieces of Yahoo User Interface Library
3668  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669  * YUI licensed under the BSD License:
3670  * http://developer.yahoo.net/yui/license.txt
3671  * <script type="text/javascript">
3672  *
3673  */
3674 (function() {
3675
3676     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3677         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3678     };
3679
3680     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3681
3682     var fly = Roo.lib.AnimBase.fly;
3683     var Y = Roo.lib;
3684     var superclass = Y.ColorAnim.superclass;
3685     var proto = Y.ColorAnim.prototype;
3686
3687     proto.toString = function() {
3688         var el = this.getEl();
3689         var id = el.id || el.tagName;
3690         return ("ColorAnim " + id);
3691     };
3692
3693     proto.patterns.color = /color$/i;
3694     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3695     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3696     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3697     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3698
3699
3700     proto.parseColor = function(s) {
3701         if (s.length == 3) {
3702             return s;
3703         }
3704
3705         var c = this.patterns.hex.exec(s);
3706         if (c && c.length == 4) {
3707             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3708         }
3709
3710         c = this.patterns.rgb.exec(s);
3711         if (c && c.length == 4) {
3712             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3713         }
3714
3715         c = this.patterns.hex3.exec(s);
3716         if (c && c.length == 4) {
3717             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3718         }
3719
3720         return null;
3721     };
3722     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3723     proto.getAttribute = function(attr) {
3724         var el = this.getEl();
3725         if (this.patterns.color.test(attr)) {
3726             var val = fly(el).getStyle(attr);
3727
3728             if (this.patterns.transparent.test(val)) {
3729                 var parent = el.parentNode;
3730                 val = fly(parent).getStyle(attr);
3731
3732                 while (parent && this.patterns.transparent.test(val)) {
3733                     parent = parent.parentNode;
3734                     val = fly(parent).getStyle(attr);
3735                     if (parent.tagName.toUpperCase() == 'HTML') {
3736                         val = '#fff';
3737                     }
3738                 }
3739             }
3740         } else {
3741             val = superclass.getAttribute.call(this, attr);
3742         }
3743
3744         return val;
3745     };
3746     proto.getAttribute = function(attr) {
3747         var el = this.getEl();
3748         if (this.patterns.color.test(attr)) {
3749             var val = fly(el).getStyle(attr);
3750
3751             if (this.patterns.transparent.test(val)) {
3752                 var parent = el.parentNode;
3753                 val = fly(parent).getStyle(attr);
3754
3755                 while (parent && this.patterns.transparent.test(val)) {
3756                     parent = parent.parentNode;
3757                     val = fly(parent).getStyle(attr);
3758                     if (parent.tagName.toUpperCase() == 'HTML') {
3759                         val = '#fff';
3760                     }
3761                 }
3762             }
3763         } else {
3764             val = superclass.getAttribute.call(this, attr);
3765         }
3766
3767         return val;
3768     };
3769
3770     proto.doMethod = function(attr, start, end) {
3771         var val;
3772
3773         if (this.patterns.color.test(attr)) {
3774             val = [];
3775             for (var i = 0, len = start.length; i < len; ++i) {
3776                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3777             }
3778
3779             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3780         }
3781         else {
3782             val = superclass.doMethod.call(this, attr, start, end);
3783         }
3784
3785         return val;
3786     };
3787
3788     proto.setRuntimeAttribute = function(attr) {
3789         superclass.setRuntimeAttribute.call(this, attr);
3790
3791         if (this.patterns.color.test(attr)) {
3792             var attributes = this.attributes;
3793             var start = this.parseColor(this.runtimeAttributes[attr].start);
3794             var end = this.parseColor(this.runtimeAttributes[attr].end);
3795
3796             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3797                 end = this.parseColor(attributes[attr].by);
3798
3799                 for (var i = 0, len = start.length; i < len; ++i) {
3800                     end[i] = start[i] + end[i];
3801                 }
3802             }
3803
3804             this.runtimeAttributes[attr].start = start;
3805             this.runtimeAttributes[attr].end = end;
3806         }
3807     };
3808 })();
3809
3810 /*
3811  * Portions of this file are based on pieces of Yahoo User Interface Library
3812  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3813  * YUI licensed under the BSD License:
3814  * http://developer.yahoo.net/yui/license.txt
3815  * <script type="text/javascript">
3816  *
3817  */
3818 Roo.lib.Easing = {
3819
3820
3821     easeNone: function (t, b, c, d) {
3822         return c * t / d + b;
3823     },
3824
3825
3826     easeIn: function (t, b, c, d) {
3827         return c * (t /= d) * t + b;
3828     },
3829
3830
3831     easeOut: function (t, b, c, d) {
3832         return -c * (t /= d) * (t - 2) + b;
3833     },
3834
3835
3836     easeBoth: function (t, b, c, d) {
3837         if ((t /= d / 2) < 1) {
3838             return c / 2 * t * t + b;
3839         }
3840
3841         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3842     },
3843
3844
3845     easeInStrong: function (t, b, c, d) {
3846         return c * (t /= d) * t * t * t + b;
3847     },
3848
3849
3850     easeOutStrong: function (t, b, c, d) {
3851         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3852     },
3853
3854
3855     easeBothStrong: function (t, b, c, d) {
3856         if ((t /= d / 2) < 1) {
3857             return c / 2 * t * t * t * t + b;
3858         }
3859
3860         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3861     },
3862
3863
3864
3865     elasticIn: function (t, b, c, d, a, p) {
3866         if (t == 0) {
3867             return b;
3868         }
3869         if ((t /= d) == 1) {
3870             return b + c;
3871         }
3872         if (!p) {
3873             p = d * .3;
3874         }
3875
3876         if (!a || a < Math.abs(c)) {
3877             a = c;
3878             var s = p / 4;
3879         }
3880         else {
3881             var s = p / (2 * Math.PI) * Math.asin(c / a);
3882         }
3883
3884         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3885     },
3886
3887
3888     elasticOut: function (t, b, c, d, a, p) {
3889         if (t == 0) {
3890             return b;
3891         }
3892         if ((t /= d) == 1) {
3893             return b + c;
3894         }
3895         if (!p) {
3896             p = d * .3;
3897         }
3898
3899         if (!a || a < Math.abs(c)) {
3900             a = c;
3901             var s = p / 4;
3902         }
3903         else {
3904             var s = p / (2 * Math.PI) * Math.asin(c / a);
3905         }
3906
3907         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3908     },
3909
3910
3911     elasticBoth: function (t, b, c, d, a, p) {
3912         if (t == 0) {
3913             return b;
3914         }
3915
3916         if ((t /= d / 2) == 2) {
3917             return b + c;
3918         }
3919
3920         if (!p) {
3921             p = d * (.3 * 1.5);
3922         }
3923
3924         if (!a || a < Math.abs(c)) {
3925             a = c;
3926             var s = p / 4;
3927         }
3928         else {
3929             var s = p / (2 * Math.PI) * Math.asin(c / a);
3930         }
3931
3932         if (t < 1) {
3933             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3934                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3935         }
3936         return a * Math.pow(2, -10 * (t -= 1)) *
3937                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3938     },
3939
3940
3941
3942     backIn: function (t, b, c, d, s) {
3943         if (typeof s == 'undefined') {
3944             s = 1.70158;
3945         }
3946         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3947     },
3948
3949
3950     backOut: function (t, b, c, d, s) {
3951         if (typeof s == 'undefined') {
3952             s = 1.70158;
3953         }
3954         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3955     },
3956
3957
3958     backBoth: function (t, b, c, d, s) {
3959         if (typeof s == 'undefined') {
3960             s = 1.70158;
3961         }
3962
3963         if ((t /= d / 2 ) < 1) {
3964             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3965         }
3966         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3967     },
3968
3969
3970     bounceIn: function (t, b, c, d) {
3971         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3972     },
3973
3974
3975     bounceOut: function (t, b, c, d) {
3976         if ((t /= d) < (1 / 2.75)) {
3977             return c * (7.5625 * t * t) + b;
3978         } else if (t < (2 / 2.75)) {
3979             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3980         } else if (t < (2.5 / 2.75)) {
3981             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3982         }
3983         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3984     },
3985
3986
3987     bounceBoth: function (t, b, c, d) {
3988         if (t < d / 2) {
3989             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3990         }
3991         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3992     }
3993 };/*
3994  * Portions of this file are based on pieces of Yahoo User Interface Library
3995  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3996  * YUI licensed under the BSD License:
3997  * http://developer.yahoo.net/yui/license.txt
3998  * <script type="text/javascript">
3999  *
4000  */
4001     (function() {
4002         Roo.lib.Motion = function(el, attributes, duration, method) {
4003             if (el) {
4004                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4005             }
4006         };
4007
4008         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4009
4010
4011         var Y = Roo.lib;
4012         var superclass = Y.Motion.superclass;
4013         var proto = Y.Motion.prototype;
4014
4015         proto.toString = function() {
4016             var el = this.getEl();
4017             var id = el.id || el.tagName;
4018             return ("Motion " + id);
4019         };
4020
4021         proto.patterns.points = /^points$/i;
4022
4023         proto.setAttribute = function(attr, val, unit) {
4024             if (this.patterns.points.test(attr)) {
4025                 unit = unit || 'px';
4026                 superclass.setAttribute.call(this, 'left', val[0], unit);
4027                 superclass.setAttribute.call(this, 'top', val[1], unit);
4028             } else {
4029                 superclass.setAttribute.call(this, attr, val, unit);
4030             }
4031         };
4032
4033         proto.getAttribute = function(attr) {
4034             if (this.patterns.points.test(attr)) {
4035                 var val = [
4036                         superclass.getAttribute.call(this, 'left'),
4037                         superclass.getAttribute.call(this, 'top')
4038                         ];
4039             } else {
4040                 val = superclass.getAttribute.call(this, attr);
4041             }
4042
4043             return val;
4044         };
4045
4046         proto.doMethod = function(attr, start, end) {
4047             var val = null;
4048
4049             if (this.patterns.points.test(attr)) {
4050                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4051                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4052             } else {
4053                 val = superclass.doMethod.call(this, attr, start, end);
4054             }
4055             return val;
4056         };
4057
4058         proto.setRuntimeAttribute = function(attr) {
4059             if (this.patterns.points.test(attr)) {
4060                 var el = this.getEl();
4061                 var attributes = this.attributes;
4062                 var start;
4063                 var control = attributes['points']['control'] || [];
4064                 var end;
4065                 var i, len;
4066
4067                 if (control.length > 0 && !(control[0] instanceof Array)) {
4068                     control = [control];
4069                 } else {
4070                     var tmp = [];
4071                     for (i = 0,len = control.length; i < len; ++i) {
4072                         tmp[i] = control[i];
4073                     }
4074                     control = tmp;
4075                 }
4076
4077                 Roo.fly(el).position();
4078
4079                 if (isset(attributes['points']['from'])) {
4080                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4081                 }
4082                 else {
4083                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4084                 }
4085
4086                 start = this.getAttribute('points');
4087
4088
4089                 if (isset(attributes['points']['to'])) {
4090                     end = translateValues.call(this, attributes['points']['to'], start);
4091
4092                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4093                     for (i = 0,len = control.length; i < len; ++i) {
4094                         control[i] = translateValues.call(this, control[i], start);
4095                     }
4096
4097
4098                 } else if (isset(attributes['points']['by'])) {
4099                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4100
4101                     for (i = 0,len = control.length; i < len; ++i) {
4102                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4103                     }
4104                 }
4105
4106                 this.runtimeAttributes[attr] = [start];
4107
4108                 if (control.length > 0) {
4109                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4110                 }
4111
4112                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4113             }
4114             else {
4115                 superclass.setRuntimeAttribute.call(this, attr);
4116             }
4117         };
4118
4119         var translateValues = function(val, start) {
4120             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4121             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4122
4123             return val;
4124         };
4125
4126         var isset = function(prop) {
4127             return (typeof prop !== 'undefined');
4128         };
4129     })();
4130 /*
4131  * Portions of this file are based on pieces of Yahoo User Interface Library
4132  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4133  * YUI licensed under the BSD License:
4134  * http://developer.yahoo.net/yui/license.txt
4135  * <script type="text/javascript">
4136  *
4137  */
4138     (function() {
4139         Roo.lib.Scroll = function(el, attributes, duration, method) {
4140             if (el) {
4141                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4142             }
4143         };
4144
4145         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4146
4147
4148         var Y = Roo.lib;
4149         var superclass = Y.Scroll.superclass;
4150         var proto = Y.Scroll.prototype;
4151
4152         proto.toString = function() {
4153             var el = this.getEl();
4154             var id = el.id || el.tagName;
4155             return ("Scroll " + id);
4156         };
4157
4158         proto.doMethod = function(attr, start, end) {
4159             var val = null;
4160
4161             if (attr == 'scroll') {
4162                 val = [
4163                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4164                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4165                         ];
4166
4167             } else {
4168                 val = superclass.doMethod.call(this, attr, start, end);
4169             }
4170             return val;
4171         };
4172
4173         proto.getAttribute = function(attr) {
4174             var val = null;
4175             var el = this.getEl();
4176
4177             if (attr == 'scroll') {
4178                 val = [ el.scrollLeft, el.scrollTop ];
4179             } else {
4180                 val = superclass.getAttribute.call(this, attr);
4181             }
4182
4183             return val;
4184         };
4185
4186         proto.setAttribute = function(attr, val, unit) {
4187             var el = this.getEl();
4188
4189             if (attr == 'scroll') {
4190                 el.scrollLeft = val[0];
4191                 el.scrollTop = val[1];
4192             } else {
4193                 superclass.setAttribute.call(this, attr, val, unit);
4194             }
4195         };
4196     })();
4197 /*
4198  * Based on:
4199  * Ext JS Library 1.1.1
4200  * Copyright(c) 2006-2007, Ext JS, LLC.
4201  *
4202  * Originally Released Under LGPL - original licence link has changed is not relivant.
4203  *
4204  * Fork - LGPL
4205  * <script type="text/javascript">
4206  */
4207
4208
4209 // nasty IE9 hack - what a pile of crap that is..
4210
4211  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4212     Range.prototype.createContextualFragment = function (html) {
4213         var doc = window.document;
4214         var container = doc.createElement("div");
4215         container.innerHTML = html;
4216         var frag = doc.createDocumentFragment(), n;
4217         while ((n = container.firstChild)) {
4218             frag.appendChild(n);
4219         }
4220         return frag;
4221     };
4222 }
4223
4224 /**
4225  * @class Roo.DomHelper
4226  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4227  * 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>.
4228  * @singleton
4229  */
4230 Roo.DomHelper = function(){
4231     var tempTableEl = null;
4232     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4233     var tableRe = /^table|tbody|tr|td$/i;
4234     var xmlns = {};
4235     // build as innerHTML where available
4236     /** @ignore */
4237     var createHtml = function(o){
4238         if(typeof o == 'string'){
4239             return o;
4240         }
4241         var b = "";
4242         if(!o.tag){
4243             o.tag = "div";
4244         }
4245         b += "<" + o.tag;
4246         for(var attr in o){
4247             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4248             if(attr == "style"){
4249                 var s = o["style"];
4250                 if(typeof s == "function"){
4251                     s = s.call();
4252                 }
4253                 if(typeof s == "string"){
4254                     b += ' style="' + s + '"';
4255                 }else if(typeof s == "object"){
4256                     b += ' style="';
4257                     for(var key in s){
4258                         if(typeof s[key] != "function"){
4259                             b += key + ":" + s[key] + ";";
4260                         }
4261                     }
4262                     b += '"';
4263                 }
4264             }else{
4265                 if(attr == "cls"){
4266                     b += ' class="' + o["cls"] + '"';
4267                 }else if(attr == "htmlFor"){
4268                     b += ' for="' + o["htmlFor"] + '"';
4269                 }else{
4270                     b += " " + attr + '="' + o[attr] + '"';
4271                 }
4272             }
4273         }
4274         if(emptyTags.test(o.tag)){
4275             b += "/>";
4276         }else{
4277             b += ">";
4278             var cn = o.children || o.cn;
4279             if(cn){
4280                 //http://bugs.kde.org/show_bug.cgi?id=71506
4281                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4282                     for(var i = 0, len = cn.length; i < len; i++) {
4283                         b += createHtml(cn[i], b);
4284                     }
4285                 }else{
4286                     b += createHtml(cn, b);
4287                 }
4288             }
4289             if(o.html){
4290                 b += o.html;
4291             }
4292             b += "</" + o.tag + ">";
4293         }
4294         return b;
4295     };
4296
4297     // build as dom
4298     /** @ignore */
4299     var createDom = function(o, parentNode){
4300          
4301         // defininition craeted..
4302         var ns = false;
4303         if (o.ns && o.ns != 'html') {
4304                
4305             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4306                 xmlns[o.ns] = o.xmlns;
4307                 ns = o.xmlns;
4308             }
4309             if (typeof(xmlns[o.ns]) == 'undefined') {
4310                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4311             }
4312             ns = xmlns[o.ns];
4313         }
4314         
4315         
4316         if (typeof(o) == 'string') {
4317             return parentNode.appendChild(document.createTextNode(o));
4318         }
4319         o.tag = o.tag || div;
4320         if (o.ns && Roo.isIE) {
4321             ns = false;
4322             o.tag = o.ns + ':' + o.tag;
4323             
4324         }
4325         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4326         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4327         for(var attr in o){
4328             
4329             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4330                     attr == "style" || typeof o[attr] == "function") { continue; }
4331                     
4332             if(attr=="cls" && Roo.isIE){
4333                 el.className = o["cls"];
4334             }else{
4335                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4336                 else { 
4337                     el[attr] = o[attr];
4338                 }
4339             }
4340         }
4341         Roo.DomHelper.applyStyles(el, o.style);
4342         var cn = o.children || o.cn;
4343         if(cn){
4344             //http://bugs.kde.org/show_bug.cgi?id=71506
4345              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4346                 for(var i = 0, len = cn.length; i < len; i++) {
4347                     createDom(cn[i], el);
4348                 }
4349             }else{
4350                 createDom(cn, el);
4351             }
4352         }
4353         if(o.html){
4354             el.innerHTML = o.html;
4355         }
4356         if(parentNode){
4357            parentNode.appendChild(el);
4358         }
4359         return el;
4360     };
4361
4362     var ieTable = function(depth, s, h, e){
4363         tempTableEl.innerHTML = [s, h, e].join('');
4364         var i = -1, el = tempTableEl;
4365         while(++i < depth && el.firstChild){
4366             el = el.firstChild;
4367         }
4368         return el;
4369     };
4370
4371     // kill repeat to save bytes
4372     var ts = '<table>',
4373         te = '</table>',
4374         tbs = ts+'<tbody>',
4375         tbe = '</tbody>'+te,
4376         trs = tbs + '<tr>',
4377         tre = '</tr>'+tbe;
4378
4379     /**
4380      * @ignore
4381      * Nasty code for IE's broken table implementation
4382      */
4383     var insertIntoTable = function(tag, where, el, html){
4384         if(!tempTableEl){
4385             tempTableEl = document.createElement('div');
4386         }
4387         var node;
4388         var before = null;
4389         if(tag == 'td'){
4390             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4391                 return;
4392             }
4393             if(where == 'beforebegin'){
4394                 before = el;
4395                 el = el.parentNode;
4396             } else{
4397                 before = el.nextSibling;
4398                 el = el.parentNode;
4399             }
4400             node = ieTable(4, trs, html, tre);
4401         }
4402         else if(tag == 'tr'){
4403             if(where == 'beforebegin'){
4404                 before = el;
4405                 el = el.parentNode;
4406                 node = ieTable(3, tbs, html, tbe);
4407             } else if(where == 'afterend'){
4408                 before = el.nextSibling;
4409                 el = el.parentNode;
4410                 node = ieTable(3, tbs, html, tbe);
4411             } else{ // INTO a TR
4412                 if(where == 'afterbegin'){
4413                     before = el.firstChild;
4414                 }
4415                 node = ieTable(4, trs, html, tre);
4416             }
4417         } else if(tag == 'tbody'){
4418             if(where == 'beforebegin'){
4419                 before = el;
4420                 el = el.parentNode;
4421                 node = ieTable(2, ts, html, te);
4422             } else if(where == 'afterend'){
4423                 before = el.nextSibling;
4424                 el = el.parentNode;
4425                 node = ieTable(2, ts, html, te);
4426             } else{
4427                 if(where == 'afterbegin'){
4428                     before = el.firstChild;
4429                 }
4430                 node = ieTable(3, tbs, html, tbe);
4431             }
4432         } else{ // TABLE
4433             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4434                 return;
4435             }
4436             if(where == 'afterbegin'){
4437                 before = el.firstChild;
4438             }
4439             node = ieTable(2, ts, html, te);
4440         }
4441         el.insertBefore(node, before);
4442         return node;
4443     };
4444
4445     return {
4446     /** True to force the use of DOM instead of html fragments @type Boolean */
4447     useDom : false,
4448
4449     /**
4450      * Returns the markup for the passed Element(s) config
4451      * @param {Object} o The Dom object spec (and children)
4452      * @return {String}
4453      */
4454     markup : function(o){
4455         return createHtml(o);
4456     },
4457
4458     /**
4459      * Applies a style specification to an element
4460      * @param {String/HTMLElement} el The element to apply styles to
4461      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4462      * a function which returns such a specification.
4463      */
4464     applyStyles : function(el, styles){
4465         if(styles){
4466            el = Roo.fly(el);
4467            if(typeof styles == "string"){
4468                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4469                var matches;
4470                while ((matches = re.exec(styles)) != null){
4471                    el.setStyle(matches[1], matches[2]);
4472                }
4473            }else if (typeof styles == "object"){
4474                for (var style in styles){
4475                   el.setStyle(style, styles[style]);
4476                }
4477            }else if (typeof styles == "function"){
4478                 Roo.DomHelper.applyStyles(el, styles.call());
4479            }
4480         }
4481     },
4482
4483     /**
4484      * Inserts an HTML fragment into the Dom
4485      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4486      * @param {HTMLElement} el The context element
4487      * @param {String} html The HTML fragmenet
4488      * @return {HTMLElement} The new node
4489      */
4490     insertHtml : function(where, el, html){
4491         where = where.toLowerCase();
4492         if(el.insertAdjacentHTML){
4493             if(tableRe.test(el.tagName)){
4494                 var rs;
4495                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4496                     return rs;
4497                 }
4498             }
4499             switch(where){
4500                 case "beforebegin":
4501                     el.insertAdjacentHTML('BeforeBegin', html);
4502                     return el.previousSibling;
4503                 case "afterbegin":
4504                     el.insertAdjacentHTML('AfterBegin', html);
4505                     return el.firstChild;
4506                 case "beforeend":
4507                     el.insertAdjacentHTML('BeforeEnd', html);
4508                     return el.lastChild;
4509                 case "afterend":
4510                     el.insertAdjacentHTML('AfterEnd', html);
4511                     return el.nextSibling;
4512             }
4513             throw 'Illegal insertion point -> "' + where + '"';
4514         }
4515         var range = el.ownerDocument.createRange();
4516         var frag;
4517         switch(where){
4518              case "beforebegin":
4519                 range.setStartBefore(el);
4520                 frag = range.createContextualFragment(html);
4521                 el.parentNode.insertBefore(frag, el);
4522                 return el.previousSibling;
4523              case "afterbegin":
4524                 if(el.firstChild){
4525                     range.setStartBefore(el.firstChild);
4526                     frag = range.createContextualFragment(html);
4527                     el.insertBefore(frag, el.firstChild);
4528                     return el.firstChild;
4529                 }else{
4530                     el.innerHTML = html;
4531                     return el.firstChild;
4532                 }
4533             case "beforeend":
4534                 if(el.lastChild){
4535                     range.setStartAfter(el.lastChild);
4536                     frag = range.createContextualFragment(html);
4537                     el.appendChild(frag);
4538                     return el.lastChild;
4539                 }else{
4540                     el.innerHTML = html;
4541                     return el.lastChild;
4542                 }
4543             case "afterend":
4544                 range.setStartAfter(el);
4545                 frag = range.createContextualFragment(html);
4546                 el.parentNode.insertBefore(frag, el.nextSibling);
4547                 return el.nextSibling;
4548             }
4549             throw 'Illegal insertion point -> "' + where + '"';
4550     },
4551
4552     /**
4553      * Creates new Dom element(s) and inserts them before el
4554      * @param {String/HTMLElement/Element} el The context element
4555      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4556      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4557      * @return {HTMLElement/Roo.Element} The new node
4558      */
4559     insertBefore : function(el, o, returnElement){
4560         return this.doInsert(el, o, returnElement, "beforeBegin");
4561     },
4562
4563     /**
4564      * Creates new Dom element(s) and inserts them after el
4565      * @param {String/HTMLElement/Element} el The context element
4566      * @param {Object} o The Dom object spec (and children)
4567      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4568      * @return {HTMLElement/Roo.Element} The new node
4569      */
4570     insertAfter : function(el, o, returnElement){
4571         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4572     },
4573
4574     /**
4575      * Creates new Dom element(s) and inserts them as the first child of el
4576      * @param {String/HTMLElement/Element} el The context element
4577      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4578      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4579      * @return {HTMLElement/Roo.Element} The new node
4580      */
4581     insertFirst : function(el, o, returnElement){
4582         return this.doInsert(el, o, returnElement, "afterBegin");
4583     },
4584
4585     // private
4586     doInsert : function(el, o, returnElement, pos, sibling){
4587         el = Roo.getDom(el);
4588         var newNode;
4589         if(this.useDom || o.ns){
4590             newNode = createDom(o, null);
4591             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4592         }else{
4593             var html = createHtml(o);
4594             newNode = this.insertHtml(pos, el, html);
4595         }
4596         return returnElement ? Roo.get(newNode, true) : newNode;
4597     },
4598
4599     /**
4600      * Creates new Dom element(s) and appends them to el
4601      * @param {String/HTMLElement/Element} el The context element
4602      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4603      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4604      * @return {HTMLElement/Roo.Element} The new node
4605      */
4606     append : function(el, o, returnElement){
4607         el = Roo.getDom(el);
4608         var newNode;
4609         if(this.useDom || o.ns){
4610             newNode = createDom(o, null);
4611             el.appendChild(newNode);
4612         }else{
4613             var html = createHtml(o);
4614             newNode = this.insertHtml("beforeEnd", el, html);
4615         }
4616         return returnElement ? Roo.get(newNode, true) : newNode;
4617     },
4618
4619     /**
4620      * Creates new Dom element(s) and overwrites the contents of el with them
4621      * @param {String/HTMLElement/Element} el The context element
4622      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4623      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4624      * @return {HTMLElement/Roo.Element} The new node
4625      */
4626     overwrite : function(el, o, returnElement){
4627         el = Roo.getDom(el);
4628         if (o.ns) {
4629           
4630             while (el.childNodes.length) {
4631                 el.removeChild(el.firstChild);
4632             }
4633             createDom(o, el);
4634         } else {
4635             el.innerHTML = createHtml(o);   
4636         }
4637         
4638         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4639     },
4640
4641     /**
4642      * Creates a new Roo.DomHelper.Template from the Dom object spec
4643      * @param {Object} o The Dom object spec (and children)
4644      * @return {Roo.DomHelper.Template} The new template
4645      */
4646     createTemplate : function(o){
4647         var html = createHtml(o);
4648         return new Roo.Template(html);
4649     }
4650     };
4651 }();
4652 /*
4653  * Based on:
4654  * Ext JS Library 1.1.1
4655  * Copyright(c) 2006-2007, Ext JS, LLC.
4656  *
4657  * Originally Released Under LGPL - original licence link has changed is not relivant.
4658  *
4659  * Fork - LGPL
4660  * <script type="text/javascript">
4661  */
4662  
4663 /**
4664 * @class Roo.Template
4665 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4666 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4667 * Usage:
4668 <pre><code>
4669 var t = new Roo.Template({
4670     html :  '&lt;div name="{id}"&gt;' + 
4671         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4672         '&lt;/div&gt;',
4673     myformat: function (value, allValues) {
4674         return 'XX' + value;
4675     }
4676 });
4677 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4678 </code></pre>
4679 * For more information see this blog post with examples:
4680 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4681      - Create Elements using DOM, HTML fragments and Templates</a>. 
4682 * @constructor
4683 * @param {Object} cfg - Configuration object.
4684 */
4685 Roo.Template = function(cfg){
4686     // BC!
4687     if(cfg instanceof Array){
4688         cfg = cfg.join("");
4689     }else if(arguments.length > 1){
4690         cfg = Array.prototype.join.call(arguments, "");
4691     }
4692     
4693     
4694     if (typeof(cfg) == 'object') {
4695         Roo.apply(this,cfg)
4696     } else {
4697         // bc
4698         this.html = cfg;
4699     }
4700     if (this.url) {
4701         this.load();
4702     }
4703     
4704 };
4705 Roo.Template.prototype = {
4706     
4707     /**
4708      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
4709      */
4710     onLoad : false,
4711     
4712     
4713     /**
4714      * @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..
4715      *                    it should be fixed so that template is observable...
4716      */
4717     url : false,
4718     /**
4719      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4720      */
4721     html : '',
4722     
4723     
4724     compiled : false,
4725     loaded : false,
4726     /**
4727      * Returns an HTML fragment of this template with the specified values applied.
4728      * @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'})
4729      * @return {String} The HTML fragment
4730      */
4731     
4732    
4733     
4734     applyTemplate : function(values){
4735         //Roo.log(["applyTemplate", values]);
4736         try {
4737            
4738             if(this.compiled){
4739                 return this.compiled(values);
4740             }
4741             var useF = this.disableFormats !== true;
4742             var fm = Roo.util.Format, tpl = this;
4743             var fn = function(m, name, format, args){
4744                 if(format && useF){
4745                     if(format.substr(0, 5) == "this."){
4746                         return tpl.call(format.substr(5), values[name], values);
4747                     }else{
4748                         if(args){
4749                             // quoted values are required for strings in compiled templates, 
4750                             // but for non compiled we need to strip them
4751                             // quoted reversed for jsmin
4752                             var re = /^\s*['"](.*)["']\s*$/;
4753                             args = args.split(',');
4754                             for(var i = 0, len = args.length; i < len; i++){
4755                                 args[i] = args[i].replace(re, "$1");
4756                             }
4757                             args = [values[name]].concat(args);
4758                         }else{
4759                             args = [values[name]];
4760                         }
4761                         return fm[format].apply(fm, args);
4762                     }
4763                 }else{
4764                     return values[name] !== undefined ? values[name] : "";
4765                 }
4766             };
4767             return this.html.replace(this.re, fn);
4768         } catch (e) {
4769             Roo.log(e);
4770             throw e;
4771         }
4772          
4773     },
4774     
4775     loading : false,
4776       
4777     load : function ()
4778     {
4779          
4780         if (this.loading) {
4781             return;
4782         }
4783         var _t = this;
4784         
4785         this.loading = true;
4786         this.compiled = false;
4787         
4788         var cx = new Roo.data.Connection();
4789         cx.request({
4790             url : this.url,
4791             method : 'GET',
4792             success : function (response) {
4793                 _t.loading = false;
4794                 _t.url = false;
4795                 
4796                 _t.set(response.responseText,true);
4797                 _t.loaded = true;
4798                 if (_t.onLoad) {
4799                     _t.onLoad();
4800                 }
4801              },
4802             failure : function(response) {
4803                 Roo.log("Template failed to load from " + _t.url);
4804                 _t.loading = false;
4805             }
4806         });
4807     },
4808
4809     /**
4810      * Sets the HTML used as the template and optionally compiles it.
4811      * @param {String} html
4812      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4813      * @return {Roo.Template} this
4814      */
4815     set : function(html, compile){
4816         this.html = html;
4817         this.compiled = false;
4818         if(compile){
4819             this.compile();
4820         }
4821         return this;
4822     },
4823     
4824     /**
4825      * True to disable format functions (defaults to false)
4826      * @type Boolean
4827      */
4828     disableFormats : false,
4829     
4830     /**
4831     * The regular expression used to match template variables 
4832     * @type RegExp
4833     * @property 
4834     */
4835     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4836     
4837     /**
4838      * Compiles the template into an internal function, eliminating the RegEx overhead.
4839      * @return {Roo.Template} this
4840      */
4841     compile : function(){
4842         var fm = Roo.util.Format;
4843         var useF = this.disableFormats !== true;
4844         var sep = Roo.isGecko ? "+" : ",";
4845         var fn = function(m, name, format, args){
4846             if(format && useF){
4847                 args = args ? ',' + args : "";
4848                 if(format.substr(0, 5) != "this."){
4849                     format = "fm." + format + '(';
4850                 }else{
4851                     format = 'this.call("'+ format.substr(5) + '", ';
4852                     args = ", values";
4853                 }
4854             }else{
4855                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4856             }
4857             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4858         };
4859         var body;
4860         // branched to use + in gecko and [].join() in others
4861         if(Roo.isGecko){
4862             body = "this.compiled = function(values){ return '" +
4863                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4864                     "';};";
4865         }else{
4866             body = ["this.compiled = function(values){ return ['"];
4867             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4868             body.push("'].join('');};");
4869             body = body.join('');
4870         }
4871         /**
4872          * eval:var:values
4873          * eval:var:fm
4874          */
4875         eval(body);
4876         return this;
4877     },
4878     
4879     // private function used to call members
4880     call : function(fnName, value, allValues){
4881         return this[fnName](value, allValues);
4882     },
4883     
4884     /**
4885      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4886      * @param {String/HTMLElement/Roo.Element} el The context element
4887      * @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'})
4888      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4889      * @return {HTMLElement/Roo.Element} The new node or Element
4890      */
4891     insertFirst: function(el, values, returnElement){
4892         return this.doInsert('afterBegin', el, values, returnElement);
4893     },
4894
4895     /**
4896      * Applies the supplied values to the template and inserts the new node(s) before el.
4897      * @param {String/HTMLElement/Roo.Element} el The context element
4898      * @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'})
4899      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4900      * @return {HTMLElement/Roo.Element} The new node or Element
4901      */
4902     insertBefore: function(el, values, returnElement){
4903         return this.doInsert('beforeBegin', el, values, returnElement);
4904     },
4905
4906     /**
4907      * Applies the supplied values to the template and inserts the new node(s) after el.
4908      * @param {String/HTMLElement/Roo.Element} el The context element
4909      * @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'})
4910      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4911      * @return {HTMLElement/Roo.Element} The new node or Element
4912      */
4913     insertAfter : function(el, values, returnElement){
4914         return this.doInsert('afterEnd', el, values, returnElement);
4915     },
4916     
4917     /**
4918      * Applies the supplied values to the template and appends the new node(s) to el.
4919      * @param {String/HTMLElement/Roo.Element} el The context element
4920      * @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'})
4921      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4922      * @return {HTMLElement/Roo.Element} The new node or Element
4923      */
4924     append : function(el, values, returnElement){
4925         return this.doInsert('beforeEnd', el, values, returnElement);
4926     },
4927
4928     doInsert : function(where, el, values, returnEl){
4929         el = Roo.getDom(el);
4930         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4931         return returnEl ? Roo.get(newNode, true) : newNode;
4932     },
4933
4934     /**
4935      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4936      * @param {String/HTMLElement/Roo.Element} el The context element
4937      * @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'})
4938      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4939      * @return {HTMLElement/Roo.Element} The new node or Element
4940      */
4941     overwrite : function(el, values, returnElement){
4942         el = Roo.getDom(el);
4943         el.innerHTML = this.applyTemplate(values);
4944         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4945     }
4946 };
4947 /**
4948  * Alias for {@link #applyTemplate}
4949  * @method
4950  */
4951 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4952
4953 // backwards compat
4954 Roo.DomHelper.Template = Roo.Template;
4955
4956 /**
4957  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4958  * @param {String/HTMLElement} el A DOM element or its id
4959  * @returns {Roo.Template} The created template
4960  * @static
4961  */
4962 Roo.Template.from = function(el){
4963     el = Roo.getDom(el);
4964     return new Roo.Template(el.value || el.innerHTML);
4965 };/*
4966  * Based on:
4967  * Ext JS Library 1.1.1
4968  * Copyright(c) 2006-2007, Ext JS, LLC.
4969  *
4970  * Originally Released Under LGPL - original licence link has changed is not relivant.
4971  *
4972  * Fork - LGPL
4973  * <script type="text/javascript">
4974  */
4975  
4976
4977 /*
4978  * This is code is also distributed under MIT license for use
4979  * with jQuery and prototype JavaScript libraries.
4980  */
4981 /**
4982  * @class Roo.DomQuery
4983 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).
4984 <p>
4985 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>
4986
4987 <p>
4988 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.
4989 </p>
4990 <h4>Element Selectors:</h4>
4991 <ul class="list">
4992     <li> <b>*</b> any element</li>
4993     <li> <b>E</b> an element with the tag E</li>
4994     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4995     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4996     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4997     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4998 </ul>
4999 <h4>Attribute Selectors:</h4>
5000 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5001 <ul class="list">
5002     <li> <b>E[foo]</b> has an attribute "foo"</li>
5003     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5004     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5005     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5006     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5007     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5008     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5009 </ul>
5010 <h4>Pseudo Classes:</h4>
5011 <ul class="list">
5012     <li> <b>E:first-child</b> E is the first child of its parent</li>
5013     <li> <b>E:last-child</b> E is the last child of its parent</li>
5014     <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>
5015     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5016     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5017     <li> <b>E:only-child</b> E is the only child of its parent</li>
5018     <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>
5019     <li> <b>E:first</b> the first E in the resultset</li>
5020     <li> <b>E:last</b> the last E in the resultset</li>
5021     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5022     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5023     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5024     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5025     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5026     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5027     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5028     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5029     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5030 </ul>
5031 <h4>CSS Value Selectors:</h4>
5032 <ul class="list">
5033     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5034     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5035     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5036     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5037     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5038     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5039 </ul>
5040  * @singleton
5041  */
5042 Roo.DomQuery = function(){
5043     var cache = {}, simpleCache = {}, valueCache = {};
5044     var nonSpace = /\S/;
5045     var trimRe = /^\s+|\s+$/g;
5046     var tplRe = /\{(\d+)\}/g;
5047     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5048     var tagTokenRe = /^(#)?([\w-\*]+)/;
5049     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5050
5051     function child(p, index){
5052         var i = 0;
5053         var n = p.firstChild;
5054         while(n){
5055             if(n.nodeType == 1){
5056                if(++i == index){
5057                    return n;
5058                }
5059             }
5060             n = n.nextSibling;
5061         }
5062         return null;
5063     };
5064
5065     function next(n){
5066         while((n = n.nextSibling) && n.nodeType != 1);
5067         return n;
5068     };
5069
5070     function prev(n){
5071         while((n = n.previousSibling) && n.nodeType != 1);
5072         return n;
5073     };
5074
5075     function children(d){
5076         var n = d.firstChild, ni = -1;
5077             while(n){
5078                 var nx = n.nextSibling;
5079                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5080                     d.removeChild(n);
5081                 }else{
5082                     n.nodeIndex = ++ni;
5083                 }
5084                 n = nx;
5085             }
5086             return this;
5087         };
5088
5089     function byClassName(c, a, v){
5090         if(!v){
5091             return c;
5092         }
5093         var r = [], ri = -1, cn;
5094         for(var i = 0, ci; ci = c[i]; i++){
5095             
5096             
5097             if((' '+
5098                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5099                  +' ').indexOf(v) != -1){
5100                 r[++ri] = ci;
5101             }
5102         }
5103         return r;
5104     };
5105
5106     function attrValue(n, attr){
5107         if(!n.tagName && typeof n.length != "undefined"){
5108             n = n[0];
5109         }
5110         if(!n){
5111             return null;
5112         }
5113         if(attr == "for"){
5114             return n.htmlFor;
5115         }
5116         if(attr == "class" || attr == "className"){
5117             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5118         }
5119         return n.getAttribute(attr) || n[attr];
5120
5121     };
5122
5123     function getNodes(ns, mode, tagName){
5124         var result = [], ri = -1, cs;
5125         if(!ns){
5126             return result;
5127         }
5128         tagName = tagName || "*";
5129         if(typeof ns.getElementsByTagName != "undefined"){
5130             ns = [ns];
5131         }
5132         if(!mode){
5133             for(var i = 0, ni; ni = ns[i]; i++){
5134                 cs = ni.getElementsByTagName(tagName);
5135                 for(var j = 0, ci; ci = cs[j]; j++){
5136                     result[++ri] = ci;
5137                 }
5138             }
5139         }else if(mode == "/" || mode == ">"){
5140             var utag = tagName.toUpperCase();
5141             for(var i = 0, ni, cn; ni = ns[i]; i++){
5142                 cn = ni.children || ni.childNodes;
5143                 for(var j = 0, cj; cj = cn[j]; j++){
5144                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5145                         result[++ri] = cj;
5146                     }
5147                 }
5148             }
5149         }else if(mode == "+"){
5150             var utag = tagName.toUpperCase();
5151             for(var i = 0, n; n = ns[i]; i++){
5152                 while((n = n.nextSibling) && n.nodeType != 1);
5153                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5154                     result[++ri] = n;
5155                 }
5156             }
5157         }else if(mode == "~"){
5158             for(var i = 0, n; n = ns[i]; i++){
5159                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5160                 if(n){
5161                     result[++ri] = n;
5162                 }
5163             }
5164         }
5165         return result;
5166     };
5167
5168     function concat(a, b){
5169         if(b.slice){
5170             return a.concat(b);
5171         }
5172         for(var i = 0, l = b.length; i < l; i++){
5173             a[a.length] = b[i];
5174         }
5175         return a;
5176     }
5177
5178     function byTag(cs, tagName){
5179         if(cs.tagName || cs == document){
5180             cs = [cs];
5181         }
5182         if(!tagName){
5183             return cs;
5184         }
5185         var r = [], ri = -1;
5186         tagName = tagName.toLowerCase();
5187         for(var i = 0, ci; ci = cs[i]; i++){
5188             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5189                 r[++ri] = ci;
5190             }
5191         }
5192         return r;
5193     };
5194
5195     function byId(cs, attr, id){
5196         if(cs.tagName || cs == document){
5197             cs = [cs];
5198         }
5199         if(!id){
5200             return cs;
5201         }
5202         var r = [], ri = -1;
5203         for(var i = 0,ci; ci = cs[i]; i++){
5204             if(ci && ci.id == id){
5205                 r[++ri] = ci;
5206                 return r;
5207             }
5208         }
5209         return r;
5210     };
5211
5212     function byAttribute(cs, attr, value, op, custom){
5213         var r = [], ri = -1, st = custom=="{";
5214         var f = Roo.DomQuery.operators[op];
5215         for(var i = 0, ci; ci = cs[i]; i++){
5216             var a;
5217             if(st){
5218                 a = Roo.DomQuery.getStyle(ci, attr);
5219             }
5220             else if(attr == "class" || attr == "className"){
5221                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
5222             }else if(attr == "for"){
5223                 a = ci.htmlFor;
5224             }else if(attr == "href"){
5225                 a = ci.getAttribute("href", 2);
5226             }else{
5227                 a = ci.getAttribute(attr);
5228             }
5229             if((f && f(a, value)) || (!f && a)){
5230                 r[++ri] = ci;
5231             }
5232         }
5233         return r;
5234     };
5235
5236     function byPseudo(cs, name, value){
5237         return Roo.DomQuery.pseudos[name](cs, value);
5238     };
5239
5240     // This is for IE MSXML which does not support expandos.
5241     // IE runs the same speed using setAttribute, however FF slows way down
5242     // and Safari completely fails so they need to continue to use expandos.
5243     var isIE = window.ActiveXObject ? true : false;
5244
5245     // this eval is stop the compressor from
5246     // renaming the variable to something shorter
5247     
5248     /** eval:var:batch */
5249     var batch = 30803; 
5250
5251     var key = 30803;
5252
5253     function nodupIEXml(cs){
5254         var d = ++key;
5255         cs[0].setAttribute("_nodup", d);
5256         var r = [cs[0]];
5257         for(var i = 1, len = cs.length; i < len; i++){
5258             var c = cs[i];
5259             if(!c.getAttribute("_nodup") != d){
5260                 c.setAttribute("_nodup", d);
5261                 r[r.length] = c;
5262             }
5263         }
5264         for(var i = 0, len = cs.length; i < len; i++){
5265             cs[i].removeAttribute("_nodup");
5266         }
5267         return r;
5268     }
5269
5270     function nodup(cs){
5271         if(!cs){
5272             return [];
5273         }
5274         var len = cs.length, c, i, r = cs, cj, ri = -1;
5275         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5276             return cs;
5277         }
5278         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5279             return nodupIEXml(cs);
5280         }
5281         var d = ++key;
5282         cs[0]._nodup = d;
5283         for(i = 1; c = cs[i]; i++){
5284             if(c._nodup != d){
5285                 c._nodup = d;
5286             }else{
5287                 r = [];
5288                 for(var j = 0; j < i; j++){
5289                     r[++ri] = cs[j];
5290                 }
5291                 for(j = i+1; cj = cs[j]; j++){
5292                     if(cj._nodup != d){
5293                         cj._nodup = d;
5294                         r[++ri] = cj;
5295                     }
5296                 }
5297                 return r;
5298             }
5299         }
5300         return r;
5301     }
5302
5303     function quickDiffIEXml(c1, c2){
5304         var d = ++key;
5305         for(var i = 0, len = c1.length; i < len; i++){
5306             c1[i].setAttribute("_qdiff", d);
5307         }
5308         var r = [];
5309         for(var i = 0, len = c2.length; i < len; i++){
5310             if(c2[i].getAttribute("_qdiff") != d){
5311                 r[r.length] = c2[i];
5312             }
5313         }
5314         for(var i = 0, len = c1.length; i < len; i++){
5315            c1[i].removeAttribute("_qdiff");
5316         }
5317         return r;
5318     }
5319
5320     function quickDiff(c1, c2){
5321         var len1 = c1.length;
5322         if(!len1){
5323             return c2;
5324         }
5325         if(isIE && c1[0].selectSingleNode){
5326             return quickDiffIEXml(c1, c2);
5327         }
5328         var d = ++key;
5329         for(var i = 0; i < len1; i++){
5330             c1[i]._qdiff = d;
5331         }
5332         var r = [];
5333         for(var i = 0, len = c2.length; i < len; i++){
5334             if(c2[i]._qdiff != d){
5335                 r[r.length] = c2[i];
5336             }
5337         }
5338         return r;
5339     }
5340
5341     function quickId(ns, mode, root, id){
5342         if(ns == root){
5343            var d = root.ownerDocument || root;
5344            return d.getElementById(id);
5345         }
5346         ns = getNodes(ns, mode, "*");
5347         return byId(ns, null, id);
5348     }
5349
5350     return {
5351         getStyle : function(el, name){
5352             return Roo.fly(el).getStyle(name);
5353         },
5354         /**
5355          * Compiles a selector/xpath query into a reusable function. The returned function
5356          * takes one parameter "root" (optional), which is the context node from where the query should start.
5357          * @param {String} selector The selector/xpath query
5358          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5359          * @return {Function}
5360          */
5361         compile : function(path, type){
5362             type = type || "select";
5363             
5364             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5365             var q = path, mode, lq;
5366             var tk = Roo.DomQuery.matchers;
5367             var tklen = tk.length;
5368             var mm;
5369
5370             // accept leading mode switch
5371             var lmode = q.match(modeRe);
5372             if(lmode && lmode[1]){
5373                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5374                 q = q.replace(lmode[1], "");
5375             }
5376             // strip leading slashes
5377             while(path.substr(0, 1)=="/"){
5378                 path = path.substr(1);
5379             }
5380
5381             while(q && lq != q){
5382                 lq = q;
5383                 var tm = q.match(tagTokenRe);
5384                 if(type == "select"){
5385                     if(tm){
5386                         if(tm[1] == "#"){
5387                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5388                         }else{
5389                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5390                         }
5391                         q = q.replace(tm[0], "");
5392                     }else if(q.substr(0, 1) != '@'){
5393                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5394                     }
5395                 }else{
5396                     if(tm){
5397                         if(tm[1] == "#"){
5398                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5399                         }else{
5400                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5401                         }
5402                         q = q.replace(tm[0], "");
5403                     }
5404                 }
5405                 while(!(mm = q.match(modeRe))){
5406                     var matched = false;
5407                     for(var j = 0; j < tklen; j++){
5408                         var t = tk[j];
5409                         var m = q.match(t.re);
5410                         if(m){
5411                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5412                                                     return m[i];
5413                                                 });
5414                             q = q.replace(m[0], "");
5415                             matched = true;
5416                             break;
5417                         }
5418                     }
5419                     // prevent infinite loop on bad selector
5420                     if(!matched){
5421                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5422                     }
5423                 }
5424                 if(mm[1]){
5425                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5426                     q = q.replace(mm[1], "");
5427                 }
5428             }
5429             fn[fn.length] = "return nodup(n);\n}";
5430             
5431              /** 
5432               * list of variables that need from compression as they are used by eval.
5433              *  eval:var:batch 
5434              *  eval:var:nodup
5435              *  eval:var:byTag
5436              *  eval:var:ById
5437              *  eval:var:getNodes
5438              *  eval:var:quickId
5439              *  eval:var:mode
5440              *  eval:var:root
5441              *  eval:var:n
5442              *  eval:var:byClassName
5443              *  eval:var:byPseudo
5444              *  eval:var:byAttribute
5445              *  eval:var:attrValue
5446              * 
5447              **/ 
5448             eval(fn.join(""));
5449             return f;
5450         },
5451
5452         /**
5453          * Selects a group of elements.
5454          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5455          * @param {Node} root (optional) The start of the query (defaults to document).
5456          * @return {Array}
5457          */
5458         select : function(path, root, type){
5459             if(!root || root == document){
5460                 root = document;
5461             }
5462             if(typeof root == "string"){
5463                 root = document.getElementById(root);
5464             }
5465             var paths = path.split(",");
5466             var results = [];
5467             for(var i = 0, len = paths.length; i < len; i++){
5468                 var p = paths[i].replace(trimRe, "");
5469                 if(!cache[p]){
5470                     cache[p] = Roo.DomQuery.compile(p);
5471                     if(!cache[p]){
5472                         throw p + " is not a valid selector";
5473                     }
5474                 }
5475                 var result = cache[p](root);
5476                 if(result && result != document){
5477                     results = results.concat(result);
5478                 }
5479             }
5480             if(paths.length > 1){
5481                 return nodup(results);
5482             }
5483             return results;
5484         },
5485
5486         /**
5487          * Selects a single element.
5488          * @param {String} selector The selector/xpath query
5489          * @param {Node} root (optional) The start of the query (defaults to document).
5490          * @return {Element}
5491          */
5492         selectNode : function(path, root){
5493             return Roo.DomQuery.select(path, root)[0];
5494         },
5495
5496         /**
5497          * Selects the value of a node, optionally replacing null with the defaultValue.
5498          * @param {String} selector The selector/xpath query
5499          * @param {Node} root (optional) The start of the query (defaults to document).
5500          * @param {String} defaultValue
5501          */
5502         selectValue : function(path, root, defaultValue){
5503             path = path.replace(trimRe, "");
5504             if(!valueCache[path]){
5505                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5506             }
5507             var n = valueCache[path](root);
5508             n = n[0] ? n[0] : n;
5509             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5510             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5511         },
5512
5513         /**
5514          * Selects the value of a node, parsing integers and floats.
5515          * @param {String} selector The selector/xpath query
5516          * @param {Node} root (optional) The start of the query (defaults to document).
5517          * @param {Number} defaultValue
5518          * @return {Number}
5519          */
5520         selectNumber : function(path, root, defaultValue){
5521             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5522             return parseFloat(v);
5523         },
5524
5525         /**
5526          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5527          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5528          * @param {String} selector The simple selector to test
5529          * @return {Boolean}
5530          */
5531         is : function(el, ss){
5532             if(typeof el == "string"){
5533                 el = document.getElementById(el);
5534             }
5535             var isArray = (el instanceof Array);
5536             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5537             return isArray ? (result.length == el.length) : (result.length > 0);
5538         },
5539
5540         /**
5541          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5542          * @param {Array} el An array of elements to filter
5543          * @param {String} selector The simple selector to test
5544          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5545          * the selector instead of the ones that match
5546          * @return {Array}
5547          */
5548         filter : function(els, ss, nonMatches){
5549             ss = ss.replace(trimRe, "");
5550             if(!simpleCache[ss]){
5551                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5552             }
5553             var result = simpleCache[ss](els);
5554             return nonMatches ? quickDiff(result, els) : result;
5555         },
5556
5557         /**
5558          * Collection of matching regular expressions and code snippets.
5559          */
5560         matchers : [{
5561                 re: /^\.([\w-]+)/,
5562                 select: 'n = byClassName(n, null, " {1} ");'
5563             }, {
5564                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5565                 select: 'n = byPseudo(n, "{1}", "{2}");'
5566             },{
5567                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5568                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5569             }, {
5570                 re: /^#([\w-]+)/,
5571                 select: 'n = byId(n, null, "{1}");'
5572             },{
5573                 re: /^@([\w-]+)/,
5574                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5575             }
5576         ],
5577
5578         /**
5579          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5580          * 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;.
5581          */
5582         operators : {
5583             "=" : function(a, v){
5584                 return a == v;
5585             },
5586             "!=" : function(a, v){
5587                 return a != v;
5588             },
5589             "^=" : function(a, v){
5590                 return a && a.substr(0, v.length) == v;
5591             },
5592             "$=" : function(a, v){
5593                 return a && a.substr(a.length-v.length) == v;
5594             },
5595             "*=" : function(a, v){
5596                 return a && a.indexOf(v) !== -1;
5597             },
5598             "%=" : function(a, v){
5599                 return (a % v) == 0;
5600             },
5601             "|=" : function(a, v){
5602                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5603             },
5604             "~=" : function(a, v){
5605                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5606             }
5607         },
5608
5609         /**
5610          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5611          * and the argument (if any) supplied in the selector.
5612          */
5613         pseudos : {
5614             "first-child" : function(c){
5615                 var r = [], ri = -1, n;
5616                 for(var i = 0, ci; ci = n = c[i]; i++){
5617                     while((n = n.previousSibling) && n.nodeType != 1);
5618                     if(!n){
5619                         r[++ri] = ci;
5620                     }
5621                 }
5622                 return r;
5623             },
5624
5625             "last-child" : function(c){
5626                 var r = [], ri = -1, n;
5627                 for(var i = 0, ci; ci = n = c[i]; i++){
5628                     while((n = n.nextSibling) && n.nodeType != 1);
5629                     if(!n){
5630                         r[++ri] = ci;
5631                     }
5632                 }
5633                 return r;
5634             },
5635
5636             "nth-child" : function(c, a) {
5637                 var r = [], ri = -1;
5638                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5639                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5640                 for(var i = 0, n; n = c[i]; i++){
5641                     var pn = n.parentNode;
5642                     if (batch != pn._batch) {
5643                         var j = 0;
5644                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5645                             if(cn.nodeType == 1){
5646                                cn.nodeIndex = ++j;
5647                             }
5648                         }
5649                         pn._batch = batch;
5650                     }
5651                     if (f == 1) {
5652                         if (l == 0 || n.nodeIndex == l){
5653                             r[++ri] = n;
5654                         }
5655                     } else if ((n.nodeIndex + l) % f == 0){
5656                         r[++ri] = n;
5657                     }
5658                 }
5659
5660                 return r;
5661             },
5662
5663             "only-child" : function(c){
5664                 var r = [], ri = -1;;
5665                 for(var i = 0, ci; ci = c[i]; i++){
5666                     if(!prev(ci) && !next(ci)){
5667                         r[++ri] = ci;
5668                     }
5669                 }
5670                 return r;
5671             },
5672
5673             "empty" : function(c){
5674                 var r = [], ri = -1;
5675                 for(var i = 0, ci; ci = c[i]; i++){
5676                     var cns = ci.childNodes, j = 0, cn, empty = true;
5677                     while(cn = cns[j]){
5678                         ++j;
5679                         if(cn.nodeType == 1 || cn.nodeType == 3){
5680                             empty = false;
5681                             break;
5682                         }
5683                     }
5684                     if(empty){
5685                         r[++ri] = ci;
5686                     }
5687                 }
5688                 return r;
5689             },
5690
5691             "contains" : function(c, v){
5692                 var r = [], ri = -1;
5693                 for(var i = 0, ci; ci = c[i]; i++){
5694                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5695                         r[++ri] = ci;
5696                     }
5697                 }
5698                 return r;
5699             },
5700
5701             "nodeValue" : function(c, v){
5702                 var r = [], ri = -1;
5703                 for(var i = 0, ci; ci = c[i]; i++){
5704                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5705                         r[++ri] = ci;
5706                     }
5707                 }
5708                 return r;
5709             },
5710
5711             "checked" : function(c){
5712                 var r = [], ri = -1;
5713                 for(var i = 0, ci; ci = c[i]; i++){
5714                     if(ci.checked == true){
5715                         r[++ri] = ci;
5716                     }
5717                 }
5718                 return r;
5719             },
5720
5721             "not" : function(c, ss){
5722                 return Roo.DomQuery.filter(c, ss, true);
5723             },
5724
5725             "odd" : function(c){
5726                 return this["nth-child"](c, "odd");
5727             },
5728
5729             "even" : function(c){
5730                 return this["nth-child"](c, "even");
5731             },
5732
5733             "nth" : function(c, a){
5734                 return c[a-1] || [];
5735             },
5736
5737             "first" : function(c){
5738                 return c[0] || [];
5739             },
5740
5741             "last" : function(c){
5742                 return c[c.length-1] || [];
5743             },
5744
5745             "has" : function(c, ss){
5746                 var s = Roo.DomQuery.select;
5747                 var r = [], ri = -1;
5748                 for(var i = 0, ci; ci = c[i]; i++){
5749                     if(s(ss, ci).length > 0){
5750                         r[++ri] = ci;
5751                     }
5752                 }
5753                 return r;
5754             },
5755
5756             "next" : function(c, ss){
5757                 var is = Roo.DomQuery.is;
5758                 var r = [], ri = -1;
5759                 for(var i = 0, ci; ci = c[i]; i++){
5760                     var n = next(ci);
5761                     if(n && is(n, ss)){
5762                         r[++ri] = ci;
5763                     }
5764                 }
5765                 return r;
5766             },
5767
5768             "prev" : function(c, ss){
5769                 var is = Roo.DomQuery.is;
5770                 var r = [], ri = -1;
5771                 for(var i = 0, ci; ci = c[i]; i++){
5772                     var n = prev(ci);
5773                     if(n && is(n, ss)){
5774                         r[++ri] = ci;
5775                     }
5776                 }
5777                 return r;
5778             }
5779         }
5780     };
5781 }();
5782
5783 /**
5784  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5785  * @param {String} path The selector/xpath query
5786  * @param {Node} root (optional) The start of the query (defaults to document).
5787  * @return {Array}
5788  * @member Roo
5789  * @method query
5790  */
5791 Roo.query = Roo.DomQuery.select;
5792 /*
5793  * Based on:
5794  * Ext JS Library 1.1.1
5795  * Copyright(c) 2006-2007, Ext JS, LLC.
5796  *
5797  * Originally Released Under LGPL - original licence link has changed is not relivant.
5798  *
5799  * Fork - LGPL
5800  * <script type="text/javascript">
5801  */
5802
5803 /**
5804  * @class Roo.util.Observable
5805  * Base class that provides a common interface for publishing events. Subclasses are expected to
5806  * to have a property "events" with all the events defined.<br>
5807  * For example:
5808  * <pre><code>
5809  Employee = function(name){
5810     this.name = name;
5811     this.addEvents({
5812         "fired" : true,
5813         "quit" : true
5814     });
5815  }
5816  Roo.extend(Employee, Roo.util.Observable);
5817 </code></pre>
5818  * @param {Object} config properties to use (incuding events / listeners)
5819  */
5820
5821 Roo.util.Observable = function(cfg){
5822     
5823     cfg = cfg|| {};
5824     this.addEvents(cfg.events || {});
5825     if (cfg.events) {
5826         delete cfg.events; // make sure
5827     }
5828      
5829     Roo.apply(this, cfg);
5830     
5831     if(this.listeners){
5832         this.on(this.listeners);
5833         delete this.listeners;
5834     }
5835 };
5836 Roo.util.Observable.prototype = {
5837     /** 
5838  * @cfg {Object} listeners  list of events and functions to call for this object, 
5839  * For example :
5840  * <pre><code>
5841     listeners :  { 
5842        'click' : function(e) {
5843            ..... 
5844         } ,
5845         .... 
5846     } 
5847   </code></pre>
5848  */
5849     
5850     
5851     /**
5852      * Fires the specified event with the passed parameters (minus the event name).
5853      * @param {String} eventName
5854      * @param {Object...} args Variable number of parameters are passed to handlers
5855      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5856      */
5857     fireEvent : function(){
5858         var ce = this.events[arguments[0].toLowerCase()];
5859         if(typeof ce == "object"){
5860             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5861         }else{
5862             return true;
5863         }
5864     },
5865
5866     // private
5867     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5868
5869     /**
5870      * Appends an event handler to this component
5871      * @param {String}   eventName The type of event to listen for
5872      * @param {Function} handler The method the event invokes
5873      * @param {Object}   scope (optional) The scope in which to execute the handler
5874      * function. The handler function's "this" context.
5875      * @param {Object}   options (optional) An object containing handler configuration
5876      * properties. This may contain any of the following properties:<ul>
5877      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5878      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5879      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5880      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5881      * by the specified number of milliseconds. If the event fires again within that time, the original
5882      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5883      * </ul><br>
5884      * <p>
5885      * <b>Combining Options</b><br>
5886      * Using the options argument, it is possible to combine different types of listeners:<br>
5887      * <br>
5888      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5889                 <pre><code>
5890                 el.on('click', this.onClick, this, {
5891                         single: true,
5892                 delay: 100,
5893                 forumId: 4
5894                 });
5895                 </code></pre>
5896      * <p>
5897      * <b>Attaching multiple handlers in 1 call</b><br>
5898      * The method also allows for a single argument to be passed which is a config object containing properties
5899      * which specify multiple handlers.
5900      * <pre><code>
5901                 el.on({
5902                         'click': {
5903                         fn: this.onClick,
5904                         scope: this,
5905                         delay: 100
5906                 }, 
5907                 'mouseover': {
5908                         fn: this.onMouseOver,
5909                         scope: this
5910                 },
5911                 'mouseout': {
5912                         fn: this.onMouseOut,
5913                         scope: this
5914                 }
5915                 });
5916                 </code></pre>
5917      * <p>
5918      * Or a shorthand syntax which passes the same scope object to all handlers:
5919         <pre><code>
5920                 el.on({
5921                         'click': this.onClick,
5922                 'mouseover': this.onMouseOver,
5923                 'mouseout': this.onMouseOut,
5924                 scope: this
5925                 });
5926                 </code></pre>
5927      */
5928     addListener : function(eventName, fn, scope, o){
5929         if(typeof eventName == "object"){
5930             o = eventName;
5931             for(var e in o){
5932                 if(this.filterOptRe.test(e)){
5933                     continue;
5934                 }
5935                 if(typeof o[e] == "function"){
5936                     // shared options
5937                     this.addListener(e, o[e], o.scope,  o);
5938                 }else{
5939                     // individual options
5940                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5941                 }
5942             }
5943             return;
5944         }
5945         o = (!o || typeof o == "boolean") ? {} : o;
5946         eventName = eventName.toLowerCase();
5947         var ce = this.events[eventName] || true;
5948         if(typeof ce == "boolean"){
5949             ce = new Roo.util.Event(this, eventName);
5950             this.events[eventName] = ce;
5951         }
5952         ce.addListener(fn, scope, o);
5953     },
5954
5955     /**
5956      * Removes a listener
5957      * @param {String}   eventName     The type of event to listen for
5958      * @param {Function} handler        The handler to remove
5959      * @param {Object}   scope  (optional) The scope (this object) for the handler
5960      */
5961     removeListener : function(eventName, fn, scope){
5962         var ce = this.events[eventName.toLowerCase()];
5963         if(typeof ce == "object"){
5964             ce.removeListener(fn, scope);
5965         }
5966     },
5967
5968     /**
5969      * Removes all listeners for this object
5970      */
5971     purgeListeners : function(){
5972         for(var evt in this.events){
5973             if(typeof this.events[evt] == "object"){
5974                  this.events[evt].clearListeners();
5975             }
5976         }
5977     },
5978
5979     relayEvents : function(o, events){
5980         var createHandler = function(ename){
5981             return function(){
5982                  
5983                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5984             };
5985         };
5986         for(var i = 0, len = events.length; i < len; i++){
5987             var ename = events[i];
5988             if(!this.events[ename]){
5989                 this.events[ename] = true;
5990             };
5991             o.on(ename, createHandler(ename), this);
5992         }
5993     },
5994
5995     /**
5996      * Used to define events on this Observable
5997      * @param {Object} object The object with the events defined
5998      */
5999     addEvents : function(o){
6000         if(!this.events){
6001             this.events = {};
6002         }
6003         Roo.applyIf(this.events, o);
6004     },
6005
6006     /**
6007      * Checks to see if this object has any listeners for a specified event
6008      * @param {String} eventName The name of the event to check for
6009      * @return {Boolean} True if the event is being listened for, else false
6010      */
6011     hasListener : function(eventName){
6012         var e = this.events[eventName];
6013         return typeof e == "object" && e.listeners.length > 0;
6014     }
6015 };
6016 /**
6017  * Appends an event handler to this element (shorthand for addListener)
6018  * @param {String}   eventName     The type of event to listen for
6019  * @param {Function} handler        The method the event invokes
6020  * @param {Object}   scope (optional) The scope in which to execute the handler
6021  * function. The handler function's "this" context.
6022  * @param {Object}   options  (optional)
6023  * @method
6024  */
6025 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6026 /**
6027  * Removes a listener (shorthand for removeListener)
6028  * @param {String}   eventName     The type of event to listen for
6029  * @param {Function} handler        The handler to remove
6030  * @param {Object}   scope  (optional) The scope (this object) for the handler
6031  * @method
6032  */
6033 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6034
6035 /**
6036  * Starts capture on the specified Observable. All events will be passed
6037  * to the supplied function with the event name + standard signature of the event
6038  * <b>before</b> the event is fired. If the supplied function returns false,
6039  * the event will not fire.
6040  * @param {Observable} o The Observable to capture
6041  * @param {Function} fn The function to call
6042  * @param {Object} scope (optional) The scope (this object) for the fn
6043  * @static
6044  */
6045 Roo.util.Observable.capture = function(o, fn, scope){
6046     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6047 };
6048
6049 /**
6050  * Removes <b>all</b> added captures from the Observable.
6051  * @param {Observable} o The Observable to release
6052  * @static
6053  */
6054 Roo.util.Observable.releaseCapture = function(o){
6055     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6056 };
6057
6058 (function(){
6059
6060     var createBuffered = function(h, o, scope){
6061         var task = new Roo.util.DelayedTask();
6062         return function(){
6063             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6064         };
6065     };
6066
6067     var createSingle = function(h, e, fn, scope){
6068         return function(){
6069             e.removeListener(fn, scope);
6070             return h.apply(scope, arguments);
6071         };
6072     };
6073
6074     var createDelayed = function(h, o, scope){
6075         return function(){
6076             var args = Array.prototype.slice.call(arguments, 0);
6077             setTimeout(function(){
6078                 h.apply(scope, args);
6079             }, o.delay || 10);
6080         };
6081     };
6082
6083     Roo.util.Event = function(obj, name){
6084         this.name = name;
6085         this.obj = obj;
6086         this.listeners = [];
6087     };
6088
6089     Roo.util.Event.prototype = {
6090         addListener : function(fn, scope, options){
6091             var o = options || {};
6092             scope = scope || this.obj;
6093             if(!this.isListening(fn, scope)){
6094                 var l = {fn: fn, scope: scope, options: o};
6095                 var h = fn;
6096                 if(o.delay){
6097                     h = createDelayed(h, o, scope);
6098                 }
6099                 if(o.single){
6100                     h = createSingle(h, this, fn, scope);
6101                 }
6102                 if(o.buffer){
6103                     h = createBuffered(h, o, scope);
6104                 }
6105                 l.fireFn = h;
6106                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6107                     this.listeners.push(l);
6108                 }else{
6109                     this.listeners = this.listeners.slice(0);
6110                     this.listeners.push(l);
6111                 }
6112             }
6113         },
6114
6115         findListener : function(fn, scope){
6116             scope = scope || this.obj;
6117             var ls = this.listeners;
6118             for(var i = 0, len = ls.length; i < len; i++){
6119                 var l = ls[i];
6120                 if(l.fn == fn && l.scope == scope){
6121                     return i;
6122                 }
6123             }
6124             return -1;
6125         },
6126
6127         isListening : function(fn, scope){
6128             return this.findListener(fn, scope) != -1;
6129         },
6130
6131         removeListener : function(fn, scope){
6132             var index;
6133             if((index = this.findListener(fn, scope)) != -1){
6134                 if(!this.firing){
6135                     this.listeners.splice(index, 1);
6136                 }else{
6137                     this.listeners = this.listeners.slice(0);
6138                     this.listeners.splice(index, 1);
6139                 }
6140                 return true;
6141             }
6142             return false;
6143         },
6144
6145         clearListeners : function(){
6146             this.listeners = [];
6147         },
6148
6149         fire : function(){
6150             var ls = this.listeners, scope, len = ls.length;
6151             if(len > 0){
6152                 this.firing = true;
6153                 var args = Array.prototype.slice.call(arguments, 0);                
6154                 for(var i = 0; i < len; i++){
6155                     var l = ls[i];
6156                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6157                         this.firing = false;
6158                         return false;
6159                     }
6160                 }
6161                 this.firing = false;
6162             }
6163             return true;
6164         }
6165     };
6166 })();/*
6167  * RooJS Library 
6168  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6169  *
6170  * Licence LGPL 
6171  *
6172  */
6173  
6174 /**
6175  * @class Roo.Document
6176  * @extends Roo.util.Observable
6177  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6178  * 
6179  * @param {Object} config the methods and properties of the 'base' class for the application.
6180  * 
6181  *  Generic Page handler - implement this to start your app..
6182  * 
6183  * eg.
6184  *  MyProject = new Roo.Document({
6185         events : {
6186             'load' : true // your events..
6187         },
6188         listeners : {
6189             'ready' : function() {
6190                 // fired on Roo.onReady()
6191             }
6192         }
6193  * 
6194  */
6195 Roo.Document = function(cfg) {
6196      
6197     this.addEvents({ 
6198         'ready' : true
6199     });
6200     Roo.util.Observable.call(this,cfg);
6201     
6202     var _this = this;
6203     
6204     Roo.onReady(function() {
6205         _this.fireEvent('ready');
6206     },null,false);
6207     
6208     
6209 }
6210
6211 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6212  * Based on:
6213  * Ext JS Library 1.1.1
6214  * Copyright(c) 2006-2007, Ext JS, LLC.
6215  *
6216  * Originally Released Under LGPL - original licence link has changed is not relivant.
6217  *
6218  * Fork - LGPL
6219  * <script type="text/javascript">
6220  */
6221
6222 /**
6223  * @class Roo.EventManager
6224  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6225  * several useful events directly.
6226  * See {@link Roo.EventObject} for more details on normalized event objects.
6227  * @singleton
6228  */
6229 Roo.EventManager = function(){
6230     var docReadyEvent, docReadyProcId, docReadyState = false;
6231     var resizeEvent, resizeTask, textEvent, textSize;
6232     var E = Roo.lib.Event;
6233     var D = Roo.lib.Dom;
6234
6235     
6236     
6237
6238     var fireDocReady = function(){
6239         if(!docReadyState){
6240             docReadyState = true;
6241             Roo.isReady = true;
6242             if(docReadyProcId){
6243                 clearInterval(docReadyProcId);
6244             }
6245             if(Roo.isGecko || Roo.isOpera) {
6246                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6247             }
6248             if(Roo.isIE){
6249                 var defer = document.getElementById("ie-deferred-loader");
6250                 if(defer){
6251                     defer.onreadystatechange = null;
6252                     defer.parentNode.removeChild(defer);
6253                 }
6254             }
6255             if(docReadyEvent){
6256                 docReadyEvent.fire();
6257                 docReadyEvent.clearListeners();
6258             }
6259         }
6260     };
6261     
6262     var initDocReady = function(){
6263         docReadyEvent = new Roo.util.Event();
6264         if(Roo.isGecko || Roo.isOpera) {
6265             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6266         }else if(Roo.isIE){
6267             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6268             var defer = document.getElementById("ie-deferred-loader");
6269             defer.onreadystatechange = function(){
6270                 if(this.readyState == "complete"){
6271                     fireDocReady();
6272                 }
6273             };
6274         }else if(Roo.isSafari){ 
6275             docReadyProcId = setInterval(function(){
6276                 var rs = document.readyState;
6277                 if(rs == "complete") {
6278                     fireDocReady();     
6279                  }
6280             }, 10);
6281         }
6282         // no matter what, make sure it fires on load
6283         E.on(window, "load", fireDocReady);
6284     };
6285
6286     var createBuffered = function(h, o){
6287         var task = new Roo.util.DelayedTask(h);
6288         return function(e){
6289             // create new event object impl so new events don't wipe out properties
6290             e = new Roo.EventObjectImpl(e);
6291             task.delay(o.buffer, h, null, [e]);
6292         };
6293     };
6294
6295     var createSingle = function(h, el, ename, fn){
6296         return function(e){
6297             Roo.EventManager.removeListener(el, ename, fn);
6298             h(e);
6299         };
6300     };
6301
6302     var createDelayed = function(h, o){
6303         return function(e){
6304             // create new event object impl so new events don't wipe out properties
6305             e = new Roo.EventObjectImpl(e);
6306             setTimeout(function(){
6307                 h(e);
6308             }, o.delay || 10);
6309         };
6310     };
6311     var transitionEndVal = false;
6312     
6313     var transitionEnd = function()
6314     {
6315         if (transitionEndVal) {
6316             return transitionEndVal;
6317         }
6318         var el = document.createElement('div');
6319
6320         var transEndEventNames = {
6321             WebkitTransition : 'webkitTransitionEnd',
6322             MozTransition    : 'transitionend',
6323             OTransition      : 'oTransitionEnd otransitionend',
6324             transition       : 'transitionend'
6325         };
6326     
6327         for (var name in transEndEventNames) {
6328             if (el.style[name] !== undefined) {
6329                 transitionEndVal = transEndEventNames[name];
6330                 return  transitionEndVal ;
6331             }
6332         }
6333     }
6334     
6335   
6336
6337     var listen = function(element, ename, opt, fn, scope)
6338     {
6339         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6340         fn = fn || o.fn; scope = scope || o.scope;
6341         var el = Roo.getDom(element);
6342         
6343         
6344         if(!el){
6345             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6346         }
6347         
6348         if (ename == 'transitionend') {
6349             ename = transitionEnd();
6350         }
6351         var h = function(e){
6352             e = Roo.EventObject.setEvent(e);
6353             var t;
6354             if(o.delegate){
6355                 t = e.getTarget(o.delegate, el);
6356                 if(!t){
6357                     return;
6358                 }
6359             }else{
6360                 t = e.target;
6361             }
6362             if(o.stopEvent === true){
6363                 e.stopEvent();
6364             }
6365             if(o.preventDefault === true){
6366                e.preventDefault();
6367             }
6368             if(o.stopPropagation === true){
6369                 e.stopPropagation();
6370             }
6371
6372             if(o.normalized === false){
6373                 e = e.browserEvent;
6374             }
6375
6376             fn.call(scope || el, e, t, o);
6377         };
6378         if(o.delay){
6379             h = createDelayed(h, o);
6380         }
6381         if(o.single){
6382             h = createSingle(h, el, ename, fn);
6383         }
6384         if(o.buffer){
6385             h = createBuffered(h, o);
6386         }
6387         
6388         fn._handlers = fn._handlers || [];
6389         
6390         
6391         fn._handlers.push([Roo.id(el), ename, h]);
6392         
6393         
6394          
6395         E.on(el, ename, h); // this adds the actuall listener to the object..
6396         
6397         
6398         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6399             el.addEventListener("DOMMouseScroll", h, false);
6400             E.on(window, 'unload', function(){
6401                 el.removeEventListener("DOMMouseScroll", h, false);
6402             });
6403         }
6404         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6405             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6406         }
6407         return h;
6408     };
6409
6410     var stopListening = function(el, ename, fn){
6411         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6412         if(hds){
6413             for(var i = 0, len = hds.length; i < len; i++){
6414                 var h = hds[i];
6415                 if(h[0] == id && h[1] == ename){
6416                     hd = h[2];
6417                     hds.splice(i, 1);
6418                     break;
6419                 }
6420             }
6421         }
6422         E.un(el, ename, hd);
6423         el = Roo.getDom(el);
6424         if(ename == "mousewheel" && el.addEventListener){
6425             el.removeEventListener("DOMMouseScroll", hd, false);
6426         }
6427         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6428             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6429         }
6430     };
6431
6432     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6433     
6434     var pub = {
6435         
6436         
6437         /** 
6438          * Fix for doc tools
6439          * @scope Roo.EventManager
6440          */
6441         
6442         
6443         /** 
6444          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6445          * object with a Roo.EventObject
6446          * @param {Function} fn        The method the event invokes
6447          * @param {Object}   scope    An object that becomes the scope of the handler
6448          * @param {boolean}  override If true, the obj passed in becomes
6449          *                             the execution scope of the listener
6450          * @return {Function} The wrapped function
6451          * @deprecated
6452          */
6453         wrap : function(fn, scope, override){
6454             return function(e){
6455                 Roo.EventObject.setEvent(e);
6456                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6457             };
6458         },
6459         
6460         /**
6461      * Appends an event handler to an element (shorthand for addListener)
6462      * @param {String/HTMLElement}   element        The html element or id to assign the
6463      * @param {String}   eventName The type of event to listen for
6464      * @param {Function} handler The method the event invokes
6465      * @param {Object}   scope (optional) The scope in which to execute the handler
6466      * function. The handler function's "this" context.
6467      * @param {Object}   options (optional) An object containing handler configuration
6468      * properties. This may contain any of the following properties:<ul>
6469      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6470      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6471      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6472      * <li>preventDefault {Boolean} True to prevent the default action</li>
6473      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6474      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6475      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6476      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6477      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6478      * by the specified number of milliseconds. If the event fires again within that time, the original
6479      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6480      * </ul><br>
6481      * <p>
6482      * <b>Combining Options</b><br>
6483      * Using the options argument, it is possible to combine different types of listeners:<br>
6484      * <br>
6485      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6486      * Code:<pre><code>
6487 el.on('click', this.onClick, this, {
6488     single: true,
6489     delay: 100,
6490     stopEvent : true,
6491     forumId: 4
6492 });</code></pre>
6493      * <p>
6494      * <b>Attaching multiple handlers in 1 call</b><br>
6495       * The method also allows for a single argument to be passed which is a config object containing properties
6496      * which specify multiple handlers.
6497      * <p>
6498      * Code:<pre><code>
6499 el.on({
6500     'click' : {
6501         fn: this.onClick
6502         scope: this,
6503         delay: 100
6504     },
6505     'mouseover' : {
6506         fn: this.onMouseOver
6507         scope: this
6508     },
6509     'mouseout' : {
6510         fn: this.onMouseOut
6511         scope: this
6512     }
6513 });</code></pre>
6514      * <p>
6515      * Or a shorthand syntax:<br>
6516      * Code:<pre><code>
6517 el.on({
6518     'click' : this.onClick,
6519     'mouseover' : this.onMouseOver,
6520     'mouseout' : this.onMouseOut
6521     scope: this
6522 });</code></pre>
6523      */
6524         addListener : function(element, eventName, fn, scope, options){
6525             if(typeof eventName == "object"){
6526                 var o = eventName;
6527                 for(var e in o){
6528                     if(propRe.test(e)){
6529                         continue;
6530                     }
6531                     if(typeof o[e] == "function"){
6532                         // shared options
6533                         listen(element, e, o, o[e], o.scope);
6534                     }else{
6535                         // individual options
6536                         listen(element, e, o[e]);
6537                     }
6538                 }
6539                 return;
6540             }
6541             return listen(element, eventName, options, fn, scope);
6542         },
6543         
6544         /**
6545          * Removes an event handler
6546          *
6547          * @param {String/HTMLElement}   element        The id or html element to remove the 
6548          *                             event from
6549          * @param {String}   eventName     The type of event
6550          * @param {Function} fn
6551          * @return {Boolean} True if a listener was actually removed
6552          */
6553         removeListener : function(element, eventName, fn){
6554             return stopListening(element, eventName, fn);
6555         },
6556         
6557         /**
6558          * Fires when the document is ready (before onload and before images are loaded). Can be 
6559          * accessed shorthanded Roo.onReady().
6560          * @param {Function} fn        The method the event invokes
6561          * @param {Object}   scope    An  object that becomes the scope of the handler
6562          * @param {boolean}  options
6563          */
6564         onDocumentReady : function(fn, scope, options){
6565             if(docReadyState){ // if it already fired
6566                 docReadyEvent.addListener(fn, scope, options);
6567                 docReadyEvent.fire();
6568                 docReadyEvent.clearListeners();
6569                 return;
6570             }
6571             if(!docReadyEvent){
6572                 initDocReady();
6573             }
6574             docReadyEvent.addListener(fn, scope, options);
6575         },
6576         
6577         /**
6578          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6579          * @param {Function} fn        The method the event invokes
6580          * @param {Object}   scope    An object that becomes the scope of the handler
6581          * @param {boolean}  options
6582          */
6583         onWindowResize : function(fn, scope, options){
6584             if(!resizeEvent){
6585                 resizeEvent = new Roo.util.Event();
6586                 resizeTask = new Roo.util.DelayedTask(function(){
6587                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6588                 });
6589                 E.on(window, "resize", function(){
6590                     if(Roo.isIE){
6591                         resizeTask.delay(50);
6592                     }else{
6593                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6594                     }
6595                 });
6596             }
6597             resizeEvent.addListener(fn, scope, options);
6598         },
6599
6600         /**
6601          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6602          * @param {Function} fn        The method the event invokes
6603          * @param {Object}   scope    An object that becomes the scope of the handler
6604          * @param {boolean}  options
6605          */
6606         onTextResize : function(fn, scope, options){
6607             if(!textEvent){
6608                 textEvent = new Roo.util.Event();
6609                 var textEl = new Roo.Element(document.createElement('div'));
6610                 textEl.dom.className = 'x-text-resize';
6611                 textEl.dom.innerHTML = 'X';
6612                 textEl.appendTo(document.body);
6613                 textSize = textEl.dom.offsetHeight;
6614                 setInterval(function(){
6615                     if(textEl.dom.offsetHeight != textSize){
6616                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6617                     }
6618                 }, this.textResizeInterval);
6619             }
6620             textEvent.addListener(fn, scope, options);
6621         },
6622
6623         /**
6624          * Removes the passed window resize listener.
6625          * @param {Function} fn        The method the event invokes
6626          * @param {Object}   scope    The scope of handler
6627          */
6628         removeResizeListener : function(fn, scope){
6629             if(resizeEvent){
6630                 resizeEvent.removeListener(fn, scope);
6631             }
6632         },
6633
6634         // private
6635         fireResize : function(){
6636             if(resizeEvent){
6637                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6638             }   
6639         },
6640         /**
6641          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6642          */
6643         ieDeferSrc : false,
6644         /**
6645          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6646          */
6647         textResizeInterval : 50
6648     };
6649     
6650     /**
6651      * Fix for doc tools
6652      * @scopeAlias pub=Roo.EventManager
6653      */
6654     
6655      /**
6656      * Appends an event handler to an element (shorthand for addListener)
6657      * @param {String/HTMLElement}   element        The html element or id to assign the
6658      * @param {String}   eventName The type of event to listen for
6659      * @param {Function} handler The method the event invokes
6660      * @param {Object}   scope (optional) The scope in which to execute the handler
6661      * function. The handler function's "this" context.
6662      * @param {Object}   options (optional) An object containing handler configuration
6663      * properties. This may contain any of the following properties:<ul>
6664      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6665      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6666      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6667      * <li>preventDefault {Boolean} True to prevent the default action</li>
6668      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6669      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6670      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6671      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6672      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6673      * by the specified number of milliseconds. If the event fires again within that time, the original
6674      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6675      * </ul><br>
6676      * <p>
6677      * <b>Combining Options</b><br>
6678      * Using the options argument, it is possible to combine different types of listeners:<br>
6679      * <br>
6680      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6681      * Code:<pre><code>
6682 el.on('click', this.onClick, this, {
6683     single: true,
6684     delay: 100,
6685     stopEvent : true,
6686     forumId: 4
6687 });</code></pre>
6688      * <p>
6689      * <b>Attaching multiple handlers in 1 call</b><br>
6690       * The method also allows for a single argument to be passed which is a config object containing properties
6691      * which specify multiple handlers.
6692      * <p>
6693      * Code:<pre><code>
6694 el.on({
6695     'click' : {
6696         fn: this.onClick
6697         scope: this,
6698         delay: 100
6699     },
6700     'mouseover' : {
6701         fn: this.onMouseOver
6702         scope: this
6703     },
6704     'mouseout' : {
6705         fn: this.onMouseOut
6706         scope: this
6707     }
6708 });</code></pre>
6709      * <p>
6710      * Or a shorthand syntax:<br>
6711      * Code:<pre><code>
6712 el.on({
6713     'click' : this.onClick,
6714     'mouseover' : this.onMouseOver,
6715     'mouseout' : this.onMouseOut
6716     scope: this
6717 });</code></pre>
6718      */
6719     pub.on = pub.addListener;
6720     pub.un = pub.removeListener;
6721
6722     pub.stoppedMouseDownEvent = new Roo.util.Event();
6723     return pub;
6724 }();
6725 /**
6726   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6727   * @param {Function} fn        The method the event invokes
6728   * @param {Object}   scope    An  object that becomes the scope of the handler
6729   * @param {boolean}  override If true, the obj passed in becomes
6730   *                             the execution scope of the listener
6731   * @member Roo
6732   * @method onReady
6733  */
6734 Roo.onReady = Roo.EventManager.onDocumentReady;
6735
6736 Roo.onReady(function(){
6737     var bd = Roo.get(document.body);
6738     if(!bd){ return; }
6739
6740     var cls = [
6741             Roo.isIE ? "roo-ie"
6742             : Roo.isIE11 ? "roo-ie11"
6743             : Roo.isEdge ? "roo-edge"
6744             : Roo.isGecko ? "roo-gecko"
6745             : Roo.isOpera ? "roo-opera"
6746             : Roo.isSafari ? "roo-safari" : ""];
6747
6748     if(Roo.isMac){
6749         cls.push("roo-mac");
6750     }
6751     if(Roo.isLinux){
6752         cls.push("roo-linux");
6753     }
6754     if(Roo.isIOS){
6755         cls.push("roo-ios");
6756     }
6757     if(Roo.isTouch){
6758         cls.push("roo-touch");
6759     }
6760     if(Roo.isBorderBox){
6761         cls.push('roo-border-box');
6762     }
6763     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6764         var p = bd.dom.parentNode;
6765         if(p){
6766             p.className += ' roo-strict';
6767         }
6768     }
6769     bd.addClass(cls.join(' '));
6770 });
6771
6772 /**
6773  * @class Roo.EventObject
6774  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6775  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6776  * Example:
6777  * <pre><code>
6778  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6779     e.preventDefault();
6780     var target = e.getTarget();
6781     ...
6782  }
6783  var myDiv = Roo.get("myDiv");
6784  myDiv.on("click", handleClick);
6785  //or
6786  Roo.EventManager.on("myDiv", 'click', handleClick);
6787  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6788  </code></pre>
6789  * @singleton
6790  */
6791 Roo.EventObject = function(){
6792     
6793     var E = Roo.lib.Event;
6794     
6795     // safari keypress events for special keys return bad keycodes
6796     var safariKeys = {
6797         63234 : 37, // left
6798         63235 : 39, // right
6799         63232 : 38, // up
6800         63233 : 40, // down
6801         63276 : 33, // page up
6802         63277 : 34, // page down
6803         63272 : 46, // delete
6804         63273 : 36, // home
6805         63275 : 35  // end
6806     };
6807
6808     // normalize button clicks
6809     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6810                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6811
6812     Roo.EventObjectImpl = function(e){
6813         if(e){
6814             this.setEvent(e.browserEvent || e);
6815         }
6816     };
6817     Roo.EventObjectImpl.prototype = {
6818         /**
6819          * Used to fix doc tools.
6820          * @scope Roo.EventObject.prototype
6821          */
6822             
6823
6824         
6825         
6826         /** The normal browser event */
6827         browserEvent : null,
6828         /** The button pressed in a mouse event */
6829         button : -1,
6830         /** True if the shift key was down during the event */
6831         shiftKey : false,
6832         /** True if the control key was down during the event */
6833         ctrlKey : false,
6834         /** True if the alt key was down during the event */
6835         altKey : false,
6836
6837         /** Key constant 
6838         * @type Number */
6839         BACKSPACE : 8,
6840         /** Key constant 
6841         * @type Number */
6842         TAB : 9,
6843         /** Key constant 
6844         * @type Number */
6845         RETURN : 13,
6846         /** Key constant 
6847         * @type Number */
6848         ENTER : 13,
6849         /** Key constant 
6850         * @type Number */
6851         SHIFT : 16,
6852         /** Key constant 
6853         * @type Number */
6854         CONTROL : 17,
6855         /** Key constant 
6856         * @type Number */
6857         ESC : 27,
6858         /** Key constant 
6859         * @type Number */
6860         SPACE : 32,
6861         /** Key constant 
6862         * @type Number */
6863         PAGEUP : 33,
6864         /** Key constant 
6865         * @type Number */
6866         PAGEDOWN : 34,
6867         /** Key constant 
6868         * @type Number */
6869         END : 35,
6870         /** Key constant 
6871         * @type Number */
6872         HOME : 36,
6873         /** Key constant 
6874         * @type Number */
6875         LEFT : 37,
6876         /** Key constant 
6877         * @type Number */
6878         UP : 38,
6879         /** Key constant 
6880         * @type Number */
6881         RIGHT : 39,
6882         /** Key constant 
6883         * @type Number */
6884         DOWN : 40,
6885         /** Key constant 
6886         * @type Number */
6887         DELETE : 46,
6888         /** Key constant 
6889         * @type Number */
6890         F5 : 116,
6891
6892            /** @private */
6893         setEvent : function(e){
6894             if(e == this || (e && e.browserEvent)){ // already wrapped
6895                 return e;
6896             }
6897             this.browserEvent = e;
6898             if(e){
6899                 // normalize buttons
6900                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6901                 if(e.type == 'click' && this.button == -1){
6902                     this.button = 0;
6903                 }
6904                 this.type = e.type;
6905                 this.shiftKey = e.shiftKey;
6906                 // mac metaKey behaves like ctrlKey
6907                 this.ctrlKey = e.ctrlKey || e.metaKey;
6908                 this.altKey = e.altKey;
6909                 // in getKey these will be normalized for the mac
6910                 this.keyCode = e.keyCode;
6911                 // keyup warnings on firefox.
6912                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6913                 // cache the target for the delayed and or buffered events
6914                 this.target = E.getTarget(e);
6915                 // same for XY
6916                 this.xy = E.getXY(e);
6917             }else{
6918                 this.button = -1;
6919                 this.shiftKey = false;
6920                 this.ctrlKey = false;
6921                 this.altKey = false;
6922                 this.keyCode = 0;
6923                 this.charCode =0;
6924                 this.target = null;
6925                 this.xy = [0, 0];
6926             }
6927             return this;
6928         },
6929
6930         /**
6931          * Stop the event (preventDefault and stopPropagation)
6932          */
6933         stopEvent : function(){
6934             if(this.browserEvent){
6935                 if(this.browserEvent.type == 'mousedown'){
6936                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6937                 }
6938                 E.stopEvent(this.browserEvent);
6939             }
6940         },
6941
6942         /**
6943          * Prevents the browsers default handling of the event.
6944          */
6945         preventDefault : function(){
6946             if(this.browserEvent){
6947                 E.preventDefault(this.browserEvent);
6948             }
6949         },
6950
6951         /** @private */
6952         isNavKeyPress : function(){
6953             var k = this.keyCode;
6954             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6955             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6956         },
6957
6958         isSpecialKey : function(){
6959             var k = this.keyCode;
6960             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6961             (k == 16) || (k == 17) ||
6962             (k >= 18 && k <= 20) ||
6963             (k >= 33 && k <= 35) ||
6964             (k >= 36 && k <= 39) ||
6965             (k >= 44 && k <= 45);
6966         },
6967         /**
6968          * Cancels bubbling of the event.
6969          */
6970         stopPropagation : function(){
6971             if(this.browserEvent){
6972                 if(this.type == 'mousedown'){
6973                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6974                 }
6975                 E.stopPropagation(this.browserEvent);
6976             }
6977         },
6978
6979         /**
6980          * Gets the key code for the event.
6981          * @return {Number}
6982          */
6983         getCharCode : function(){
6984             return this.charCode || this.keyCode;
6985         },
6986
6987         /**
6988          * Returns a normalized keyCode for the event.
6989          * @return {Number} The key code
6990          */
6991         getKey : function(){
6992             var k = this.keyCode || this.charCode;
6993             return Roo.isSafari ? (safariKeys[k] || k) : k;
6994         },
6995
6996         /**
6997          * Gets the x coordinate of the event.
6998          * @return {Number}
6999          */
7000         getPageX : function(){
7001             return this.xy[0];
7002         },
7003
7004         /**
7005          * Gets the y coordinate of the event.
7006          * @return {Number}
7007          */
7008         getPageY : function(){
7009             return this.xy[1];
7010         },
7011
7012         /**
7013          * Gets the time of the event.
7014          * @return {Number}
7015          */
7016         getTime : function(){
7017             if(this.browserEvent){
7018                 return E.getTime(this.browserEvent);
7019             }
7020             return null;
7021         },
7022
7023         /**
7024          * Gets the page coordinates of the event.
7025          * @return {Array} The xy values like [x, y]
7026          */
7027         getXY : function(){
7028             return this.xy;
7029         },
7030
7031         /**
7032          * Gets the target for the event.
7033          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7034          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035                 search as a number or element (defaults to 10 || document.body)
7036          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037          * @return {HTMLelement}
7038          */
7039         getTarget : function(selector, maxDepth, returnEl){
7040             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7041         },
7042         /**
7043          * Gets the related target.
7044          * @return {HTMLElement}
7045          */
7046         getRelatedTarget : function(){
7047             if(this.browserEvent){
7048                 return E.getRelatedTarget(this.browserEvent);
7049             }
7050             return null;
7051         },
7052
7053         /**
7054          * Normalizes mouse wheel delta across browsers
7055          * @return {Number} The delta
7056          */
7057         getWheelDelta : function(){
7058             var e = this.browserEvent;
7059             var delta = 0;
7060             if(e.wheelDelta){ /* IE/Opera. */
7061                 delta = e.wheelDelta/120;
7062             }else if(e.detail){ /* Mozilla case. */
7063                 delta = -e.detail/3;
7064             }
7065             return delta;
7066         },
7067
7068         /**
7069          * Returns true if the control, meta, shift or alt key was pressed during this event.
7070          * @return {Boolean}
7071          */
7072         hasModifier : function(){
7073             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7074         },
7075
7076         /**
7077          * Returns true if the target of this event equals el or is a child of el
7078          * @param {String/HTMLElement/Element} el
7079          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7080          * @return {Boolean}
7081          */
7082         within : function(el, related){
7083             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7084             return t && Roo.fly(el).contains(t);
7085         },
7086
7087         getPoint : function(){
7088             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7089         }
7090     };
7091
7092     return new Roo.EventObjectImpl();
7093 }();
7094             
7095     /*
7096  * Based on:
7097  * Ext JS Library 1.1.1
7098  * Copyright(c) 2006-2007, Ext JS, LLC.
7099  *
7100  * Originally Released Under LGPL - original licence link has changed is not relivant.
7101  *
7102  * Fork - LGPL
7103  * <script type="text/javascript">
7104  */
7105
7106  
7107 // was in Composite Element!??!?!
7108  
7109 (function(){
7110     var D = Roo.lib.Dom;
7111     var E = Roo.lib.Event;
7112     var A = Roo.lib.Anim;
7113
7114     // local style camelizing for speed
7115     var propCache = {};
7116     var camelRe = /(-[a-z])/gi;
7117     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7118     var view = document.defaultView;
7119
7120 /**
7121  * @class Roo.Element
7122  * Represents an Element in the DOM.<br><br>
7123  * Usage:<br>
7124 <pre><code>
7125 var el = Roo.get("my-div");
7126
7127 // or with getEl
7128 var el = getEl("my-div");
7129
7130 // or with a DOM element
7131 var el = Roo.get(myDivElement);
7132 </code></pre>
7133  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7134  * each call instead of constructing a new one.<br><br>
7135  * <b>Animations</b><br />
7136  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7137  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7138 <pre>
7139 Option    Default   Description
7140 --------- --------  ---------------------------------------------
7141 duration  .35       The duration of the animation in seconds
7142 easing    easeOut   The YUI easing method
7143 callback  none      A function to execute when the anim completes
7144 scope     this      The scope (this) of the callback function
7145 </pre>
7146 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7147 * manipulate the animation. Here's an example:
7148 <pre><code>
7149 var el = Roo.get("my-div");
7150
7151 // no animation
7152 el.setWidth(100);
7153
7154 // default animation
7155 el.setWidth(100, true);
7156
7157 // animation with some options set
7158 el.setWidth(100, {
7159     duration: 1,
7160     callback: this.foo,
7161     scope: this
7162 });
7163
7164 // using the "anim" property to get the Anim object
7165 var opt = {
7166     duration: 1,
7167     callback: this.foo,
7168     scope: this
7169 };
7170 el.setWidth(100, opt);
7171 ...
7172 if(opt.anim.isAnimated()){
7173     opt.anim.stop();
7174 }
7175 </code></pre>
7176 * <b> Composite (Collections of) Elements</b><br />
7177  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7178  * @constructor Create a new Element directly.
7179  * @param {String/HTMLElement} element
7180  * @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).
7181  */
7182     Roo.Element = function(element, forceNew)
7183     {
7184         var dom = typeof element == "string" ?
7185                 document.getElementById(element) : element;
7186         
7187         this.listeners = {};
7188         
7189         if(!dom){ // invalid id/element
7190             return null;
7191         }
7192         var id = dom.id;
7193         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7194             return Roo.Element.cache[id];
7195         }
7196
7197         /**
7198          * The DOM element
7199          * @type HTMLElement
7200          */
7201         this.dom = dom;
7202
7203         /**
7204          * The DOM element ID
7205          * @type String
7206          */
7207         this.id = id || Roo.id(dom);
7208         
7209         return this; // assumed for cctor?
7210     };
7211
7212     var El = Roo.Element;
7213
7214     El.prototype = {
7215         /**
7216          * The element's default display mode  (defaults to "") 
7217          * @type String
7218          */
7219         originalDisplay : "",
7220
7221         
7222         // note this is overridden in BS version..
7223         visibilityMode : 1, 
7224         /**
7225          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7226          * @type String
7227          */
7228         defaultUnit : "px",
7229         
7230         /**
7231          * Sets the element's visibility mode. When setVisible() is called it
7232          * will use this to determine whether to set the visibility or the display property.
7233          * @param visMode Element.VISIBILITY or Element.DISPLAY
7234          * @return {Roo.Element} this
7235          */
7236         setVisibilityMode : function(visMode){
7237             this.visibilityMode = visMode;
7238             return this;
7239         },
7240         /**
7241          * Convenience method for setVisibilityMode(Element.DISPLAY)
7242          * @param {String} display (optional) What to set display to when visible
7243          * @return {Roo.Element} this
7244          */
7245         enableDisplayMode : function(display){
7246             this.setVisibilityMode(El.DISPLAY);
7247             if(typeof display != "undefined") { this.originalDisplay = display; }
7248             return this;
7249         },
7250
7251         /**
7252          * 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)
7253          * @param {String} selector The simple selector to test
7254          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7255                 search as a number or element (defaults to 10 || document.body)
7256          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7257          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7258          */
7259         findParent : function(simpleSelector, maxDepth, returnEl){
7260             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7261             maxDepth = maxDepth || 50;
7262             if(typeof maxDepth != "number"){
7263                 stopEl = Roo.getDom(maxDepth);
7264                 maxDepth = 10;
7265             }
7266             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7267                 if(dq.is(p, simpleSelector)){
7268                     return returnEl ? Roo.get(p) : p;
7269                 }
7270                 depth++;
7271                 p = p.parentNode;
7272             }
7273             return null;
7274         },
7275
7276
7277         /**
7278          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7279          * @param {String} selector The simple selector to test
7280          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7281                 search as a number or element (defaults to 10 || document.body)
7282          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7283          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7284          */
7285         findParentNode : function(simpleSelector, maxDepth, returnEl){
7286             var p = Roo.fly(this.dom.parentNode, '_internal');
7287             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7288         },
7289         
7290         /**
7291          * Looks at  the scrollable parent element
7292          */
7293         findScrollableParent : function()
7294         {
7295             var overflowRegex = /(auto|scroll)/;
7296             
7297             if(this.getStyle('position') === 'fixed'){
7298                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7299             }
7300             
7301             var excludeStaticParent = this.getStyle('position') === "absolute";
7302             
7303             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7304                 
7305                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7306                     continue;
7307                 }
7308                 
7309                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7310                     return parent;
7311                 }
7312                 
7313                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7314                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7315                 }
7316             }
7317             
7318             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7319         },
7320
7321         /**
7322          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7323          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7324          * @param {String} selector The simple selector to test
7325          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7326                 search as a number or element (defaults to 10 || document.body)
7327          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7328          */
7329         up : function(simpleSelector, maxDepth){
7330             return this.findParentNode(simpleSelector, maxDepth, true);
7331         },
7332
7333
7334
7335         /**
7336          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7337          * @param {String} selector The simple selector to test
7338          * @return {Boolean} True if this element matches the selector, else false
7339          */
7340         is : function(simpleSelector){
7341             return Roo.DomQuery.is(this.dom, simpleSelector);
7342         },
7343
7344         /**
7345          * Perform animation on this element.
7346          * @param {Object} args The YUI animation control args
7347          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7348          * @param {Function} onComplete (optional) Function to call when animation completes
7349          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7350          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7351          * @return {Roo.Element} this
7352          */
7353         animate : function(args, duration, onComplete, easing, animType){
7354             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7355             return this;
7356         },
7357
7358         /*
7359          * @private Internal animation call
7360          */
7361         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7362             animType = animType || 'run';
7363             opt = opt || {};
7364             var anim = Roo.lib.Anim[animType](
7365                 this.dom, args,
7366                 (opt.duration || defaultDur) || .35,
7367                 (opt.easing || defaultEase) || 'easeOut',
7368                 function(){
7369                     Roo.callback(cb, this);
7370                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7371                 },
7372                 this
7373             );
7374             opt.anim = anim;
7375             return anim;
7376         },
7377
7378         // private legacy anim prep
7379         preanim : function(a, i){
7380             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7381         },
7382
7383         /**
7384          * Removes worthless text nodes
7385          * @param {Boolean} forceReclean (optional) By default the element
7386          * keeps track if it has been cleaned already so
7387          * you can call this over and over. However, if you update the element and
7388          * need to force a reclean, you can pass true.
7389          */
7390         clean : function(forceReclean){
7391             if(this.isCleaned && forceReclean !== true){
7392                 return this;
7393             }
7394             var ns = /\S/;
7395             var d = this.dom, n = d.firstChild, ni = -1;
7396             while(n){
7397                 var nx = n.nextSibling;
7398                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7399                     d.removeChild(n);
7400                 }else{
7401                     n.nodeIndex = ++ni;
7402                 }
7403                 n = nx;
7404             }
7405             this.isCleaned = true;
7406             return this;
7407         },
7408
7409         // private
7410         calcOffsetsTo : function(el){
7411             el = Roo.get(el);
7412             var d = el.dom;
7413             var restorePos = false;
7414             if(el.getStyle('position') == 'static'){
7415                 el.position('relative');
7416                 restorePos = true;
7417             }
7418             var x = 0, y =0;
7419             var op = this.dom;
7420             while(op && op != d && op.tagName != 'HTML'){
7421                 x+= op.offsetLeft;
7422                 y+= op.offsetTop;
7423                 op = op.offsetParent;
7424             }
7425             if(restorePos){
7426                 el.position('static');
7427             }
7428             return [x, y];
7429         },
7430
7431         /**
7432          * Scrolls this element into view within the passed container.
7433          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7434          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7435          * @return {Roo.Element} this
7436          */
7437         scrollIntoView : function(container, hscroll){
7438             var c = Roo.getDom(container) || document.body;
7439             var el = this.dom;
7440
7441             var o = this.calcOffsetsTo(c),
7442                 l = o[0],
7443                 t = o[1],
7444                 b = t+el.offsetHeight,
7445                 r = l+el.offsetWidth;
7446
7447             var ch = c.clientHeight;
7448             var ct = parseInt(c.scrollTop, 10);
7449             var cl = parseInt(c.scrollLeft, 10);
7450             var cb = ct + ch;
7451             var cr = cl + c.clientWidth;
7452
7453             if(t < ct){
7454                 c.scrollTop = t;
7455             }else if(b > cb){
7456                 c.scrollTop = b-ch;
7457             }
7458
7459             if(hscroll !== false){
7460                 if(l < cl){
7461                     c.scrollLeft = l;
7462                 }else if(r > cr){
7463                     c.scrollLeft = r-c.clientWidth;
7464                 }
7465             }
7466             return this;
7467         },
7468
7469         // private
7470         scrollChildIntoView : function(child, hscroll){
7471             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7472         },
7473
7474         /**
7475          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7476          * the new height may not be available immediately.
7477          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7478          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7479          * @param {Function} onComplete (optional) Function to call when animation completes
7480          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7481          * @return {Roo.Element} this
7482          */
7483         autoHeight : function(animate, duration, onComplete, easing){
7484             var oldHeight = this.getHeight();
7485             this.clip();
7486             this.setHeight(1); // force clipping
7487             setTimeout(function(){
7488                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7489                 if(!animate){
7490                     this.setHeight(height);
7491                     this.unclip();
7492                     if(typeof onComplete == "function"){
7493                         onComplete();
7494                     }
7495                 }else{
7496                     this.setHeight(oldHeight); // restore original height
7497                     this.setHeight(height, animate, duration, function(){
7498                         this.unclip();
7499                         if(typeof onComplete == "function") { onComplete(); }
7500                     }.createDelegate(this), easing);
7501                 }
7502             }.createDelegate(this), 0);
7503             return this;
7504         },
7505
7506         /**
7507          * Returns true if this element is an ancestor of the passed element
7508          * @param {HTMLElement/String} el The element to check
7509          * @return {Boolean} True if this element is an ancestor of el, else false
7510          */
7511         contains : function(el){
7512             if(!el){return false;}
7513             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7514         },
7515
7516         /**
7517          * Checks whether the element is currently visible using both visibility and display properties.
7518          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7519          * @return {Boolean} True if the element is currently visible, else false
7520          */
7521         isVisible : function(deep) {
7522             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7523             if(deep !== true || !vis){
7524                 return vis;
7525             }
7526             var p = this.dom.parentNode;
7527             while(p && p.tagName.toLowerCase() != "body"){
7528                 if(!Roo.fly(p, '_isVisible').isVisible()){
7529                     return false;
7530                 }
7531                 p = p.parentNode;
7532             }
7533             return true;
7534         },
7535
7536         /**
7537          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7538          * @param {String} selector The CSS selector
7539          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7540          * @return {CompositeElement/CompositeElementLite} The composite element
7541          */
7542         select : function(selector, unique){
7543             return El.select(selector, unique, this.dom);
7544         },
7545
7546         /**
7547          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7548          * @param {String} selector The CSS selector
7549          * @return {Array} An array of the matched nodes
7550          */
7551         query : function(selector, unique){
7552             return Roo.DomQuery.select(selector, this.dom);
7553         },
7554
7555         /**
7556          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7557          * @param {String} selector The CSS selector
7558          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7559          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7560          */
7561         child : function(selector, returnDom){
7562             var n = Roo.DomQuery.selectNode(selector, this.dom);
7563             return returnDom ? n : Roo.get(n);
7564         },
7565
7566         /**
7567          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7568          * @param {String} selector The CSS selector
7569          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7570          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7571          */
7572         down : function(selector, returnDom){
7573             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7574             return returnDom ? n : Roo.get(n);
7575         },
7576
7577         /**
7578          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7579          * @param {String} group The group the DD object is member of
7580          * @param {Object} config The DD config object
7581          * @param {Object} overrides An object containing methods to override/implement on the DD object
7582          * @return {Roo.dd.DD} The DD object
7583          */
7584         initDD : function(group, config, overrides){
7585             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7586             return Roo.apply(dd, overrides);
7587         },
7588
7589         /**
7590          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7591          * @param {String} group The group the DDProxy object is member of
7592          * @param {Object} config The DDProxy config object
7593          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7594          * @return {Roo.dd.DDProxy} The DDProxy object
7595          */
7596         initDDProxy : function(group, config, overrides){
7597             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7598             return Roo.apply(dd, overrides);
7599         },
7600
7601         /**
7602          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7603          * @param {String} group The group the DDTarget object is member of
7604          * @param {Object} config The DDTarget config object
7605          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7606          * @return {Roo.dd.DDTarget} The DDTarget object
7607          */
7608         initDDTarget : function(group, config, overrides){
7609             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7610             return Roo.apply(dd, overrides);
7611         },
7612
7613         /**
7614          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7615          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7616          * @param {Boolean} visible Whether the element is visible
7617          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7618          * @return {Roo.Element} this
7619          */
7620          setVisible : function(visible, animate){
7621             if(!animate || !A){
7622                 if(this.visibilityMode == El.DISPLAY){
7623                     this.setDisplayed(visible);
7624                 }else{
7625                     this.fixDisplay();
7626                     this.dom.style.visibility = visible ? "visible" : "hidden";
7627                 }
7628             }else{
7629                 // closure for composites
7630                 var dom = this.dom;
7631                 var visMode = this.visibilityMode;
7632                 if(visible){
7633                     this.setOpacity(.01);
7634                     this.setVisible(true);
7635                 }
7636                 this.anim({opacity: { to: (visible?1:0) }},
7637                       this.preanim(arguments, 1),
7638                       null, .35, 'easeIn', function(){
7639                          if(!visible){
7640                              if(visMode == El.DISPLAY){
7641                                  dom.style.display = "none";
7642                              }else{
7643                                  dom.style.visibility = "hidden";
7644                              }
7645                              Roo.get(dom).setOpacity(1);
7646                          }
7647                      });
7648             }
7649             return this;
7650         },
7651
7652         /**
7653          * Returns true if display is not "none"
7654          * @return {Boolean}
7655          */
7656         isDisplayed : function() {
7657             return this.getStyle("display") != "none";
7658         },
7659
7660         /**
7661          * Toggles the element's visibility or display, depending on visibility mode.
7662          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7663          * @return {Roo.Element} this
7664          */
7665         toggle : function(animate){
7666             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7667             return this;
7668         },
7669
7670         /**
7671          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7672          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7673          * @return {Roo.Element} this
7674          */
7675         setDisplayed : function(value) {
7676             if(typeof value == "boolean"){
7677                value = value ? this.originalDisplay : "none";
7678             }
7679             this.setStyle("display", value);
7680             return this;
7681         },
7682
7683         /**
7684          * Tries to focus the element. Any exceptions are caught and ignored.
7685          * @return {Roo.Element} this
7686          */
7687         focus : function() {
7688             try{
7689                 this.dom.focus();
7690             }catch(e){}
7691             return this;
7692         },
7693
7694         /**
7695          * Tries to blur the element. Any exceptions are caught and ignored.
7696          * @return {Roo.Element} this
7697          */
7698         blur : function() {
7699             try{
7700                 this.dom.blur();
7701             }catch(e){}
7702             return this;
7703         },
7704
7705         /**
7706          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7707          * @param {String/Array} className The CSS class to add, or an array of classes
7708          * @return {Roo.Element} this
7709          */
7710         addClass : function(className){
7711             if(className instanceof Array){
7712                 for(var i = 0, len = className.length; i < len; i++) {
7713                     this.addClass(className[i]);
7714                 }
7715             }else{
7716                 if(className && !this.hasClass(className)){
7717                     if (this.dom instanceof SVGElement) {
7718                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
7719                     } else {
7720                         this.dom.className = this.dom.className + " " + className;
7721                     }
7722                 }
7723             }
7724             return this;
7725         },
7726
7727         /**
7728          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7729          * @param {String/Array} className The CSS class to add, or an array of classes
7730          * @return {Roo.Element} this
7731          */
7732         radioClass : function(className){
7733             var siblings = this.dom.parentNode.childNodes;
7734             for(var i = 0; i < siblings.length; i++) {
7735                 var s = siblings[i];
7736                 if(s.nodeType == 1){
7737                     Roo.get(s).removeClass(className);
7738                 }
7739             }
7740             this.addClass(className);
7741             return this;
7742         },
7743
7744         /**
7745          * Removes one or more CSS classes from the element.
7746          * @param {String/Array} className The CSS class to remove, or an array of classes
7747          * @return {Roo.Element} this
7748          */
7749         removeClass : function(className){
7750             
7751             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
7752             if(!className || !cn){
7753                 return this;
7754             }
7755             if(className instanceof Array){
7756                 for(var i = 0, len = className.length; i < len; i++) {
7757                     this.removeClass(className[i]);
7758                 }
7759             }else{
7760                 if(this.hasClass(className)){
7761                     var re = this.classReCache[className];
7762                     if (!re) {
7763                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7764                        this.classReCache[className] = re;
7765                     }
7766                     if (this.dom instanceof SVGElement) {
7767                         this.dom.className.baseVal = cn.replace(re, " ");
7768                     } else {
7769                         this.dom.className = cn.replace(re, " ");
7770                     }
7771                 }
7772             }
7773             return this;
7774         },
7775
7776         // private
7777         classReCache: {},
7778
7779         /**
7780          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7781          * @param {String} className The CSS class to toggle
7782          * @return {Roo.Element} this
7783          */
7784         toggleClass : function(className){
7785             if(this.hasClass(className)){
7786                 this.removeClass(className);
7787             }else{
7788                 this.addClass(className);
7789             }
7790             return this;
7791         },
7792
7793         /**
7794          * Checks if the specified CSS class exists on this element's DOM node.
7795          * @param {String} className The CSS class to check for
7796          * @return {Boolean} True if the class exists, else false
7797          */
7798         hasClass : function(className){
7799             if (this.dom instanceof SVGElement) {
7800                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
7801             } 
7802             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7803         },
7804
7805         /**
7806          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7807          * @param {String} oldClassName The CSS class to replace
7808          * @param {String} newClassName The replacement CSS class
7809          * @return {Roo.Element} this
7810          */
7811         replaceClass : function(oldClassName, newClassName){
7812             this.removeClass(oldClassName);
7813             this.addClass(newClassName);
7814             return this;
7815         },
7816
7817         /**
7818          * Returns an object with properties matching the styles requested.
7819          * For example, el.getStyles('color', 'font-size', 'width') might return
7820          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7821          * @param {String} style1 A style name
7822          * @param {String} style2 A style name
7823          * @param {String} etc.
7824          * @return {Object} The style object
7825          */
7826         getStyles : function(){
7827             var a = arguments, len = a.length, r = {};
7828             for(var i = 0; i < len; i++){
7829                 r[a[i]] = this.getStyle(a[i]);
7830             }
7831             return r;
7832         },
7833
7834         /**
7835          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7836          * @param {String} property The style property whose value is returned.
7837          * @return {String} The current value of the style property for this element.
7838          */
7839         getStyle : function(){
7840             return view && view.getComputedStyle ?
7841                 function(prop){
7842                     var el = this.dom, v, cs, camel;
7843                     if(prop == 'float'){
7844                         prop = "cssFloat";
7845                     }
7846                     if(el.style && (v = el.style[prop])){
7847                         return v;
7848                     }
7849                     if(cs = view.getComputedStyle(el, "")){
7850                         if(!(camel = propCache[prop])){
7851                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7852                         }
7853                         return cs[camel];
7854                     }
7855                     return null;
7856                 } :
7857                 function(prop){
7858                     var el = this.dom, v, cs, camel;
7859                     if(prop == 'opacity'){
7860                         if(typeof el.style.filter == 'string'){
7861                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7862                             if(m){
7863                                 var fv = parseFloat(m[1]);
7864                                 if(!isNaN(fv)){
7865                                     return fv ? fv / 100 : 0;
7866                                 }
7867                             }
7868                         }
7869                         return 1;
7870                     }else if(prop == 'float'){
7871                         prop = "styleFloat";
7872                     }
7873                     if(!(camel = propCache[prop])){
7874                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7875                     }
7876                     if(v = el.style[camel]){
7877                         return v;
7878                     }
7879                     if(cs = el.currentStyle){
7880                         return cs[camel];
7881                     }
7882                     return null;
7883                 };
7884         }(),
7885
7886         /**
7887          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7888          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7889          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7890          * @return {Roo.Element} this
7891          */
7892         setStyle : function(prop, value){
7893             if(typeof prop == "string"){
7894                 
7895                 if (prop == 'float') {
7896                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7897                     return this;
7898                 }
7899                 
7900                 var camel;
7901                 if(!(camel = propCache[prop])){
7902                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7903                 }
7904                 
7905                 if(camel == 'opacity') {
7906                     this.setOpacity(value);
7907                 }else{
7908                     this.dom.style[camel] = value;
7909                 }
7910             }else{
7911                 for(var style in prop){
7912                     if(typeof prop[style] != "function"){
7913                        this.setStyle(style, prop[style]);
7914                     }
7915                 }
7916             }
7917             return this;
7918         },
7919
7920         /**
7921          * More flexible version of {@link #setStyle} for setting style properties.
7922          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7923          * a function which returns such a specification.
7924          * @return {Roo.Element} this
7925          */
7926         applyStyles : function(style){
7927             Roo.DomHelper.applyStyles(this.dom, style);
7928             return this;
7929         },
7930
7931         /**
7932           * 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).
7933           * @return {Number} The X position of the element
7934           */
7935         getX : function(){
7936             return D.getX(this.dom);
7937         },
7938
7939         /**
7940           * 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).
7941           * @return {Number} The Y position of the element
7942           */
7943         getY : function(){
7944             return D.getY(this.dom);
7945         },
7946
7947         /**
7948           * 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).
7949           * @return {Array} The XY position of the element
7950           */
7951         getXY : function(){
7952             return D.getXY(this.dom);
7953         },
7954
7955         /**
7956          * 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).
7957          * @param {Number} The X position of the element
7958          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7959          * @return {Roo.Element} this
7960          */
7961         setX : function(x, animate){
7962             if(!animate || !A){
7963                 D.setX(this.dom, x);
7964             }else{
7965                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7966             }
7967             return this;
7968         },
7969
7970         /**
7971          * 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).
7972          * @param {Number} The Y position of the element
7973          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7974          * @return {Roo.Element} this
7975          */
7976         setY : function(y, animate){
7977             if(!animate || !A){
7978                 D.setY(this.dom, y);
7979             }else{
7980                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7981             }
7982             return this;
7983         },
7984
7985         /**
7986          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7987          * @param {String} left The left CSS property value
7988          * @return {Roo.Element} this
7989          */
7990         setLeft : function(left){
7991             this.setStyle("left", this.addUnits(left));
7992             return this;
7993         },
7994
7995         /**
7996          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7997          * @param {String} top The top CSS property value
7998          * @return {Roo.Element} this
7999          */
8000         setTop : function(top){
8001             this.setStyle("top", this.addUnits(top));
8002             return this;
8003         },
8004
8005         /**
8006          * Sets the element's CSS right style.
8007          * @param {String} right The right CSS property value
8008          * @return {Roo.Element} this
8009          */
8010         setRight : function(right){
8011             this.setStyle("right", this.addUnits(right));
8012             return this;
8013         },
8014
8015         /**
8016          * Sets the element's CSS bottom style.
8017          * @param {String} bottom The bottom CSS property value
8018          * @return {Roo.Element} this
8019          */
8020         setBottom : function(bottom){
8021             this.setStyle("bottom", this.addUnits(bottom));
8022             return this;
8023         },
8024
8025         /**
8026          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8027          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8028          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8029          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8030          * @return {Roo.Element} this
8031          */
8032         setXY : function(pos, animate){
8033             if(!animate || !A){
8034                 D.setXY(this.dom, pos);
8035             }else{
8036                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8037             }
8038             return this;
8039         },
8040
8041         /**
8042          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8043          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8044          * @param {Number} x X value for new position (coordinates are page-based)
8045          * @param {Number} y Y value for new position (coordinates are page-based)
8046          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8047          * @return {Roo.Element} this
8048          */
8049         setLocation : function(x, y, animate){
8050             this.setXY([x, y], this.preanim(arguments, 2));
8051             return this;
8052         },
8053
8054         /**
8055          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8056          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8057          * @param {Number} x X value for new position (coordinates are page-based)
8058          * @param {Number} y Y value for new position (coordinates are page-based)
8059          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8060          * @return {Roo.Element} this
8061          */
8062         moveTo : function(x, y, animate){
8063             this.setXY([x, y], this.preanim(arguments, 2));
8064             return this;
8065         },
8066
8067         /**
8068          * Returns the region of the given element.
8069          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8070          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8071          */
8072         getRegion : function(){
8073             return D.getRegion(this.dom);
8074         },
8075
8076         /**
8077          * Returns the offset height of the element
8078          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8079          * @return {Number} The element's height
8080          */
8081         getHeight : function(contentHeight){
8082             var h = this.dom.offsetHeight || 0;
8083             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8084         },
8085
8086         /**
8087          * Returns the offset width of the element
8088          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8089          * @return {Number} The element's width
8090          */
8091         getWidth : function(contentWidth){
8092             var w = this.dom.offsetWidth || 0;
8093             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8094         },
8095
8096         /**
8097          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8098          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8099          * if a height has not been set using CSS.
8100          * @return {Number}
8101          */
8102         getComputedHeight : function(){
8103             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8104             if(!h){
8105                 h = parseInt(this.getStyle('height'), 10) || 0;
8106                 if(!this.isBorderBox()){
8107                     h += this.getFrameWidth('tb');
8108                 }
8109             }
8110             return h;
8111         },
8112
8113         /**
8114          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8115          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8116          * if a width has not been set using CSS.
8117          * @return {Number}
8118          */
8119         getComputedWidth : function(){
8120             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8121             if(!w){
8122                 w = parseInt(this.getStyle('width'), 10) || 0;
8123                 if(!this.isBorderBox()){
8124                     w += this.getFrameWidth('lr');
8125                 }
8126             }
8127             return w;
8128         },
8129
8130         /**
8131          * Returns the size of the element.
8132          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8133          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8134          */
8135         getSize : function(contentSize){
8136             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8137         },
8138
8139         /**
8140          * Returns the width and height of the viewport.
8141          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8142          */
8143         getViewSize : function(){
8144             var d = this.dom, doc = document, aw = 0, ah = 0;
8145             if(d == doc || d == doc.body){
8146                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8147             }else{
8148                 return {
8149                     width : d.clientWidth,
8150                     height: d.clientHeight
8151                 };
8152             }
8153         },
8154
8155         /**
8156          * Returns the value of the "value" attribute
8157          * @param {Boolean} asNumber true to parse the value as a number
8158          * @return {String/Number}
8159          */
8160         getValue : function(asNumber){
8161             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8162         },
8163
8164         // private
8165         adjustWidth : function(width){
8166             if(typeof width == "number"){
8167                 if(this.autoBoxAdjust && !this.isBorderBox()){
8168                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8169                 }
8170                 if(width < 0){
8171                     width = 0;
8172                 }
8173             }
8174             return width;
8175         },
8176
8177         // private
8178         adjustHeight : function(height){
8179             if(typeof height == "number"){
8180                if(this.autoBoxAdjust && !this.isBorderBox()){
8181                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8182                }
8183                if(height < 0){
8184                    height = 0;
8185                }
8186             }
8187             return height;
8188         },
8189
8190         /**
8191          * Set the width of the element
8192          * @param {Number} width The new width
8193          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8194          * @return {Roo.Element} this
8195          */
8196         setWidth : function(width, animate){
8197             width = this.adjustWidth(width);
8198             if(!animate || !A){
8199                 this.dom.style.width = this.addUnits(width);
8200             }else{
8201                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8202             }
8203             return this;
8204         },
8205
8206         /**
8207          * Set the height of the element
8208          * @param {Number} height The new height
8209          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8210          * @return {Roo.Element} this
8211          */
8212          setHeight : function(height, animate){
8213             height = this.adjustHeight(height);
8214             if(!animate || !A){
8215                 this.dom.style.height = this.addUnits(height);
8216             }else{
8217                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8218             }
8219             return this;
8220         },
8221
8222         /**
8223          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8224          * @param {Number} width The new width
8225          * @param {Number} height The new height
8226          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8227          * @return {Roo.Element} this
8228          */
8229          setSize : function(width, height, animate){
8230             if(typeof width == "object"){ // in case of object from getSize()
8231                 height = width.height; width = width.width;
8232             }
8233             width = this.adjustWidth(width); height = this.adjustHeight(height);
8234             if(!animate || !A){
8235                 this.dom.style.width = this.addUnits(width);
8236                 this.dom.style.height = this.addUnits(height);
8237             }else{
8238                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8239             }
8240             return this;
8241         },
8242
8243         /**
8244          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8245          * @param {Number} x X value for new position (coordinates are page-based)
8246          * @param {Number} y Y value for new position (coordinates are page-based)
8247          * @param {Number} width The new width
8248          * @param {Number} height The new height
8249          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8250          * @return {Roo.Element} this
8251          */
8252         setBounds : function(x, y, width, height, animate){
8253             if(!animate || !A){
8254                 this.setSize(width, height);
8255                 this.setLocation(x, y);
8256             }else{
8257                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8258                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8259                               this.preanim(arguments, 4), 'motion');
8260             }
8261             return this;
8262         },
8263
8264         /**
8265          * 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.
8266          * @param {Roo.lib.Region} region The region to fill
8267          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8268          * @return {Roo.Element} this
8269          */
8270         setRegion : function(region, animate){
8271             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8272             return this;
8273         },
8274
8275         /**
8276          * Appends an event handler
8277          *
8278          * @param {String}   eventName     The type of event to append
8279          * @param {Function} fn        The method the event invokes
8280          * @param {Object} scope       (optional) The scope (this object) of the fn
8281          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8282          */
8283         addListener : function(eventName, fn, scope, options)
8284         {
8285             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
8286                 this.addListener('touchstart', this.onTapHandler, this);
8287             }
8288             
8289             // we need to handle a special case where dom element is a svg element.
8290             // in this case we do not actua
8291             if (!this.dom) {
8292                 return;
8293             }
8294             
8295             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
8296                 if (typeof(this.listeners[eventName]) == 'undefined') {
8297                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
8298                 }
8299                 this.listeners[eventName].addListener(fn, scope, options);
8300                 return;
8301             }
8302             
8303                 
8304             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8305             
8306             
8307         },
8308         tapedTwice : false,
8309         onTapHandler : function(event)
8310         {
8311             if(!this.tapedTwice) {
8312                 this.tapedTwice = true;
8313                 var s = this;
8314                 setTimeout( function() {
8315                     s.tapedTwice = false;
8316                 }, 300 );
8317                 return;
8318             }
8319             event.preventDefault();
8320             var revent = new MouseEvent('dblclick',  {
8321                 view: window,
8322                 bubbles: true,
8323                 cancelable: true
8324             });
8325              
8326             this.dom.dispatchEvent(revent);
8327             //action on double tap goes below
8328              
8329         }, 
8330  
8331         /**
8332          * Removes an event handler from this element
8333          * @param {String} eventName the type of event to remove
8334          * @param {Function} fn the method the event invokes
8335          * @param {Function} scope (needed for svg fake listeners)
8336          * @return {Roo.Element} this
8337          */
8338         removeListener : function(eventName, fn, scope){
8339             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8340             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
8341                 return this;
8342             }
8343             this.listeners[eventName].removeListener(fn, scope);
8344             return this;
8345         },
8346
8347         /**
8348          * Removes all previous added listeners from this element
8349          * @return {Roo.Element} this
8350          */
8351         removeAllListeners : function(){
8352             E.purgeElement(this.dom);
8353             this.listeners = {};
8354             return this;
8355         },
8356
8357         relayEvent : function(eventName, observable){
8358             this.on(eventName, function(e){
8359                 observable.fireEvent(eventName, e);
8360             });
8361         },
8362
8363         
8364         /**
8365          * Set the opacity of the element
8366          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8367          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8368          * @return {Roo.Element} this
8369          */
8370          setOpacity : function(opacity, animate){
8371             if(!animate || !A){
8372                 var s = this.dom.style;
8373                 if(Roo.isIE){
8374                     s.zoom = 1;
8375                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8376                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8377                 }else{
8378                     s.opacity = opacity;
8379                 }
8380             }else{
8381                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8382             }
8383             return this;
8384         },
8385
8386         /**
8387          * Gets the left X coordinate
8388          * @param {Boolean} local True to get the local css position instead of page coordinate
8389          * @return {Number}
8390          */
8391         getLeft : function(local){
8392             if(!local){
8393                 return this.getX();
8394             }else{
8395                 return parseInt(this.getStyle("left"), 10) || 0;
8396             }
8397         },
8398
8399         /**
8400          * Gets the right X coordinate of the element (element X position + element width)
8401          * @param {Boolean} local True to get the local css position instead of page coordinate
8402          * @return {Number}
8403          */
8404         getRight : function(local){
8405             if(!local){
8406                 return this.getX() + this.getWidth();
8407             }else{
8408                 return (this.getLeft(true) + this.getWidth()) || 0;
8409             }
8410         },
8411
8412         /**
8413          * Gets the top Y coordinate
8414          * @param {Boolean} local True to get the local css position instead of page coordinate
8415          * @return {Number}
8416          */
8417         getTop : function(local) {
8418             if(!local){
8419                 return this.getY();
8420             }else{
8421                 return parseInt(this.getStyle("top"), 10) || 0;
8422             }
8423         },
8424
8425         /**
8426          * Gets the bottom Y coordinate of the element (element Y position + element height)
8427          * @param {Boolean} local True to get the local css position instead of page coordinate
8428          * @return {Number}
8429          */
8430         getBottom : function(local){
8431             if(!local){
8432                 return this.getY() + this.getHeight();
8433             }else{
8434                 return (this.getTop(true) + this.getHeight()) || 0;
8435             }
8436         },
8437
8438         /**
8439         * Initializes positioning on this element. If a desired position is not passed, it will make the
8440         * the element positioned relative IF it is not already positioned.
8441         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8442         * @param {Number} zIndex (optional) The zIndex to apply
8443         * @param {Number} x (optional) Set the page X position
8444         * @param {Number} y (optional) Set the page Y position
8445         */
8446         position : function(pos, zIndex, x, y){
8447             if(!pos){
8448                if(this.getStyle('position') == 'static'){
8449                    this.setStyle('position', 'relative');
8450                }
8451             }else{
8452                 this.setStyle("position", pos);
8453             }
8454             if(zIndex){
8455                 this.setStyle("z-index", zIndex);
8456             }
8457             if(x !== undefined && y !== undefined){
8458                 this.setXY([x, y]);
8459             }else if(x !== undefined){
8460                 this.setX(x);
8461             }else if(y !== undefined){
8462                 this.setY(y);
8463             }
8464         },
8465
8466         /**
8467         * Clear positioning back to the default when the document was loaded
8468         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8469         * @return {Roo.Element} this
8470          */
8471         clearPositioning : function(value){
8472             value = value ||'';
8473             this.setStyle({
8474                 "left": value,
8475                 "right": value,
8476                 "top": value,
8477                 "bottom": value,
8478                 "z-index": "",
8479                 "position" : "static"
8480             });
8481             return this;
8482         },
8483
8484         /**
8485         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8486         * snapshot before performing an update and then restoring the element.
8487         * @return {Object}
8488         */
8489         getPositioning : function(){
8490             var l = this.getStyle("left");
8491             var t = this.getStyle("top");
8492             return {
8493                 "position" : this.getStyle("position"),
8494                 "left" : l,
8495                 "right" : l ? "" : this.getStyle("right"),
8496                 "top" : t,
8497                 "bottom" : t ? "" : this.getStyle("bottom"),
8498                 "z-index" : this.getStyle("z-index")
8499             };
8500         },
8501
8502         /**
8503          * Gets the width of the border(s) for the specified side(s)
8504          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8505          * passing lr would get the border (l)eft width + the border (r)ight width.
8506          * @return {Number} The width of the sides passed added together
8507          */
8508         getBorderWidth : function(side){
8509             return this.addStyles(side, El.borders);
8510         },
8511
8512         /**
8513          * Gets the width of the padding(s) for the specified side(s)
8514          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8515          * passing lr would get the padding (l)eft + the padding (r)ight.
8516          * @return {Number} The padding of the sides passed added together
8517          */
8518         getPadding : function(side){
8519             return this.addStyles(side, El.paddings);
8520         },
8521
8522         /**
8523         * Set positioning with an object returned by getPositioning().
8524         * @param {Object} posCfg
8525         * @return {Roo.Element} this
8526          */
8527         setPositioning : function(pc){
8528             this.applyStyles(pc);
8529             if(pc.right == "auto"){
8530                 this.dom.style.right = "";
8531             }
8532             if(pc.bottom == "auto"){
8533                 this.dom.style.bottom = "";
8534             }
8535             return this;
8536         },
8537
8538         // private
8539         fixDisplay : function(){
8540             if(this.getStyle("display") == "none"){
8541                 this.setStyle("visibility", "hidden");
8542                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8543                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8544                     this.setStyle("display", "block");
8545                 }
8546             }
8547         },
8548
8549         /**
8550          * Quick set left and top adding default units
8551          * @param {String} left The left CSS property value
8552          * @param {String} top The top CSS property value
8553          * @return {Roo.Element} this
8554          */
8555          setLeftTop : function(left, top){
8556             this.dom.style.left = this.addUnits(left);
8557             this.dom.style.top = this.addUnits(top);
8558             return this;
8559         },
8560
8561         /**
8562          * Move this element relative to its current position.
8563          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8564          * @param {Number} distance How far to move the element in pixels
8565          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8566          * @return {Roo.Element} this
8567          */
8568          move : function(direction, distance, animate){
8569             var xy = this.getXY();
8570             direction = direction.toLowerCase();
8571             switch(direction){
8572                 case "l":
8573                 case "left":
8574                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8575                     break;
8576                case "r":
8577                case "right":
8578                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8579                     break;
8580                case "t":
8581                case "top":
8582                case "up":
8583                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8584                     break;
8585                case "b":
8586                case "bottom":
8587                case "down":
8588                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8589                     break;
8590             }
8591             return this;
8592         },
8593
8594         /**
8595          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8596          * @return {Roo.Element} this
8597          */
8598         clip : function(){
8599             if(!this.isClipped){
8600                this.isClipped = true;
8601                this.originalClip = {
8602                    "o": this.getStyle("overflow"),
8603                    "x": this.getStyle("overflow-x"),
8604                    "y": this.getStyle("overflow-y")
8605                };
8606                this.setStyle("overflow", "hidden");
8607                this.setStyle("overflow-x", "hidden");
8608                this.setStyle("overflow-y", "hidden");
8609             }
8610             return this;
8611         },
8612
8613         /**
8614          *  Return clipping (overflow) to original clipping before clip() was called
8615          * @return {Roo.Element} this
8616          */
8617         unclip : function(){
8618             if(this.isClipped){
8619                 this.isClipped = false;
8620                 var o = this.originalClip;
8621                 if(o.o){this.setStyle("overflow", o.o);}
8622                 if(o.x){this.setStyle("overflow-x", o.x);}
8623                 if(o.y){this.setStyle("overflow-y", o.y);}
8624             }
8625             return this;
8626         },
8627
8628
8629         /**
8630          * Gets the x,y coordinates specified by the anchor position on the element.
8631          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8632          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8633          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8634          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8635          * @return {Array} [x, y] An array containing the element's x and y coordinates
8636          */
8637         getAnchorXY : function(anchor, local, s){
8638             //Passing a different size is useful for pre-calculating anchors,
8639             //especially for anchored animations that change the el size.
8640
8641             var w, h, vp = false;
8642             if(!s){
8643                 var d = this.dom;
8644                 if(d == document.body || d == document){
8645                     vp = true;
8646                     w = D.getViewWidth(); h = D.getViewHeight();
8647                 }else{
8648                     w = this.getWidth(); h = this.getHeight();
8649                 }
8650             }else{
8651                 w = s.width;  h = s.height;
8652             }
8653             var x = 0, y = 0, r = Math.round;
8654             switch((anchor || "tl").toLowerCase()){
8655                 case "c":
8656                     x = r(w*.5);
8657                     y = r(h*.5);
8658                 break;
8659                 case "t":
8660                     x = r(w*.5);
8661                     y = 0;
8662                 break;
8663                 case "l":
8664                     x = 0;
8665                     y = r(h*.5);
8666                 break;
8667                 case "r":
8668                     x = w;
8669                     y = r(h*.5);
8670                 break;
8671                 case "b":
8672                     x = r(w*.5);
8673                     y = h;
8674                 break;
8675                 case "tl":
8676                     x = 0;
8677                     y = 0;
8678                 break;
8679                 case "bl":
8680                     x = 0;
8681                     y = h;
8682                 break;
8683                 case "br":
8684                     x = w;
8685                     y = h;
8686                 break;
8687                 case "tr":
8688                     x = w;
8689                     y = 0;
8690                 break;
8691             }
8692             if(local === true){
8693                 return [x, y];
8694             }
8695             if(vp){
8696                 var sc = this.getScroll();
8697                 return [x + sc.left, y + sc.top];
8698             }
8699             //Add the element's offset xy
8700             var o = this.getXY();
8701             return [x+o[0], y+o[1]];
8702         },
8703
8704         /**
8705          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8706          * supported position values.
8707          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8708          * @param {String} position The position to align to.
8709          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8710          * @return {Array} [x, y]
8711          */
8712         getAlignToXY : function(el, p, o)
8713         {
8714             el = Roo.get(el);
8715             var d = this.dom;
8716             if(!el.dom){
8717                 throw "Element.alignTo with an element that doesn't exist";
8718             }
8719             var c = false; //constrain to viewport
8720             var p1 = "", p2 = "";
8721             o = o || [0,0];
8722
8723             if(!p){
8724                 p = "tl-bl";
8725             }else if(p == "?"){
8726                 p = "tl-bl?";
8727             }else if(p.indexOf("-") == -1){
8728                 p = "tl-" + p;
8729             }
8730             p = p.toLowerCase();
8731             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8732             if(!m){
8733                throw "Element.alignTo with an invalid alignment " + p;
8734             }
8735             p1 = m[1]; p2 = m[2]; c = !!m[3];
8736
8737             //Subtract the aligned el's internal xy from the target's offset xy
8738             //plus custom offset to get the aligned el's new offset xy
8739             var a1 = this.getAnchorXY(p1, true);
8740             var a2 = el.getAnchorXY(p2, false);
8741             var x = a2[0] - a1[0] + o[0];
8742             var y = a2[1] - a1[1] + o[1];
8743             if(c){
8744                 //constrain the aligned el to viewport if necessary
8745                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8746                 // 5px of margin for ie
8747                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8748
8749                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8750                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8751                 //otherwise swap the aligned el to the opposite border of the target.
8752                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8753                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8754                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
8755                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8756
8757                var doc = document;
8758                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8759                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8760
8761                if((x+w) > dw + scrollX){
8762                     x = swapX ? r.left-w : dw+scrollX-w;
8763                 }
8764                if(x < scrollX){
8765                    x = swapX ? r.right : scrollX;
8766                }
8767                if((y+h) > dh + scrollY){
8768                     y = swapY ? r.top-h : dh+scrollY-h;
8769                 }
8770                if (y < scrollY){
8771                    y = swapY ? r.bottom : scrollY;
8772                }
8773             }
8774             return [x,y];
8775         },
8776
8777         // private
8778         getConstrainToXY : function(){
8779             var os = {top:0, left:0, bottom:0, right: 0};
8780
8781             return function(el, local, offsets, proposedXY){
8782                 el = Roo.get(el);
8783                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8784
8785                 var vw, vh, vx = 0, vy = 0;
8786                 if(el.dom == document.body || el.dom == document){
8787                     vw = Roo.lib.Dom.getViewWidth();
8788                     vh = Roo.lib.Dom.getViewHeight();
8789                 }else{
8790                     vw = el.dom.clientWidth;
8791                     vh = el.dom.clientHeight;
8792                     if(!local){
8793                         var vxy = el.getXY();
8794                         vx = vxy[0];
8795                         vy = vxy[1];
8796                     }
8797                 }
8798
8799                 var s = el.getScroll();
8800
8801                 vx += offsets.left + s.left;
8802                 vy += offsets.top + s.top;
8803
8804                 vw -= offsets.right;
8805                 vh -= offsets.bottom;
8806
8807                 var vr = vx+vw;
8808                 var vb = vy+vh;
8809
8810                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8811                 var x = xy[0], y = xy[1];
8812                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8813
8814                 // only move it if it needs it
8815                 var moved = false;
8816
8817                 // first validate right/bottom
8818                 if((x + w) > vr){
8819                     x = vr - w;
8820                     moved = true;
8821                 }
8822                 if((y + h) > vb){
8823                     y = vb - h;
8824                     moved = true;
8825                 }
8826                 // then make sure top/left isn't negative
8827                 if(x < vx){
8828                     x = vx;
8829                     moved = true;
8830                 }
8831                 if(y < vy){
8832                     y = vy;
8833                     moved = true;
8834                 }
8835                 return moved ? [x, y] : false;
8836             };
8837         }(),
8838
8839         // private
8840         adjustForConstraints : function(xy, parent, offsets){
8841             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8842         },
8843
8844         /**
8845          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8846          * document it aligns it to the viewport.
8847          * The position parameter is optional, and can be specified in any one of the following formats:
8848          * <ul>
8849          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8850          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8851          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8852          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8853          *   <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
8854          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8855          * </ul>
8856          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8857          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8858          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8859          * that specified in order to enforce the viewport constraints.
8860          * Following are all of the supported anchor positions:
8861     <pre>
8862     Value  Description
8863     -----  -----------------------------
8864     tl     The top left corner (default)
8865     t      The center of the top edge
8866     tr     The top right corner
8867     l      The center of the left edge
8868     c      In the center of the element
8869     r      The center of the right edge
8870     bl     The bottom left corner
8871     b      The center of the bottom edge
8872     br     The bottom right corner
8873     </pre>
8874     Example Usage:
8875     <pre><code>
8876     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8877     el.alignTo("other-el");
8878
8879     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8880     el.alignTo("other-el", "tr?");
8881
8882     // align the bottom right corner of el with the center left edge of other-el
8883     el.alignTo("other-el", "br-l?");
8884
8885     // align the center of el with the bottom left corner of other-el and
8886     // adjust the x position by -6 pixels (and the y position by 0)
8887     el.alignTo("other-el", "c-bl", [-6, 0]);
8888     </code></pre>
8889          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8890          * @param {String} position The position to align to.
8891          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8892          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8893          * @return {Roo.Element} this
8894          */
8895         alignTo : function(element, position, offsets, animate){
8896             var xy = this.getAlignToXY(element, position, offsets);
8897             this.setXY(xy, this.preanim(arguments, 3));
8898             return this;
8899         },
8900
8901         /**
8902          * Anchors an element to another element and realigns it when the window is resized.
8903          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8904          * @param {String} position The position to align to.
8905          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8906          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8907          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8908          * is a number, it is used as the buffer delay (defaults to 50ms).
8909          * @param {Function} callback The function to call after the animation finishes
8910          * @return {Roo.Element} this
8911          */
8912         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8913             var action = function(){
8914                 this.alignTo(el, alignment, offsets, animate);
8915                 Roo.callback(callback, this);
8916             };
8917             Roo.EventManager.onWindowResize(action, this);
8918             var tm = typeof monitorScroll;
8919             if(tm != 'undefined'){
8920                 Roo.EventManager.on(window, 'scroll', action, this,
8921                     {buffer: tm == 'number' ? monitorScroll : 50});
8922             }
8923             action.call(this); // align immediately
8924             return this;
8925         },
8926         /**
8927          * Clears any opacity settings from this element. Required in some cases for IE.
8928          * @return {Roo.Element} this
8929          */
8930         clearOpacity : function(){
8931             if (window.ActiveXObject) {
8932                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8933                     this.dom.style.filter = "";
8934                 }
8935             } else {
8936                 this.dom.style.opacity = "";
8937                 this.dom.style["-moz-opacity"] = "";
8938                 this.dom.style["-khtml-opacity"] = "";
8939             }
8940             return this;
8941         },
8942
8943         /**
8944          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8945          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8946          * @return {Roo.Element} this
8947          */
8948         hide : function(animate){
8949             this.setVisible(false, this.preanim(arguments, 0));
8950             return this;
8951         },
8952
8953         /**
8954         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8955         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8956          * @return {Roo.Element} this
8957          */
8958         show : function(animate){
8959             this.setVisible(true, this.preanim(arguments, 0));
8960             return this;
8961         },
8962
8963         /**
8964          * @private Test if size has a unit, otherwise appends the default
8965          */
8966         addUnits : function(size){
8967             return Roo.Element.addUnits(size, this.defaultUnit);
8968         },
8969
8970         /**
8971          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8972          * @return {Roo.Element} this
8973          */
8974         beginMeasure : function(){
8975             var el = this.dom;
8976             if(el.offsetWidth || el.offsetHeight){
8977                 return this; // offsets work already
8978             }
8979             var changed = [];
8980             var p = this.dom, b = document.body; // start with this element
8981             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8982                 var pe = Roo.get(p);
8983                 if(pe.getStyle('display') == 'none'){
8984                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8985                     p.style.visibility = "hidden";
8986                     p.style.display = "block";
8987                 }
8988                 p = p.parentNode;
8989             }
8990             this._measureChanged = changed;
8991             return this;
8992
8993         },
8994
8995         /**
8996          * Restores displays to before beginMeasure was called
8997          * @return {Roo.Element} this
8998          */
8999         endMeasure : function(){
9000             var changed = this._measureChanged;
9001             if(changed){
9002                 for(var i = 0, len = changed.length; i < len; i++) {
9003                     var r = changed[i];
9004                     r.el.style.visibility = r.visibility;
9005                     r.el.style.display = "none";
9006                 }
9007                 this._measureChanged = null;
9008             }
9009             return this;
9010         },
9011
9012         /**
9013         * Update the innerHTML of this element, optionally searching for and processing scripts
9014         * @param {String} html The new HTML
9015         * @param {Boolean} loadScripts (optional) true to look for and process scripts
9016         * @param {Function} callback For async script loading you can be noticed when the update completes
9017         * @return {Roo.Element} this
9018          */
9019         update : function(html, loadScripts, callback){
9020             if(typeof html == "undefined"){
9021                 html = "";
9022             }
9023             if(loadScripts !== true){
9024                 this.dom.innerHTML = html;
9025                 if(typeof callback == "function"){
9026                     callback();
9027                 }
9028                 return this;
9029             }
9030             var id = Roo.id();
9031             var dom = this.dom;
9032
9033             html += '<span id="' + id + '"></span>';
9034
9035             E.onAvailable(id, function(){
9036                 var hd = document.getElementsByTagName("head")[0];
9037                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9038                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9039                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9040
9041                 var match;
9042                 while(match = re.exec(html)){
9043                     var attrs = match[1];
9044                     var srcMatch = attrs ? attrs.match(srcRe) : false;
9045                     if(srcMatch && srcMatch[2]){
9046                        var s = document.createElement("script");
9047                        s.src = srcMatch[2];
9048                        var typeMatch = attrs.match(typeRe);
9049                        if(typeMatch && typeMatch[2]){
9050                            s.type = typeMatch[2];
9051                        }
9052                        hd.appendChild(s);
9053                     }else if(match[2] && match[2].length > 0){
9054                         if(window.execScript) {
9055                            window.execScript(match[2]);
9056                         } else {
9057                             /**
9058                              * eval:var:id
9059                              * eval:var:dom
9060                              * eval:var:html
9061                              * 
9062                              */
9063                            window.eval(match[2]);
9064                         }
9065                     }
9066                 }
9067                 var el = document.getElementById(id);
9068                 if(el){el.parentNode.removeChild(el);}
9069                 if(typeof callback == "function"){
9070                     callback();
9071                 }
9072             });
9073             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9074             return this;
9075         },
9076
9077         /**
9078          * Direct access to the UpdateManager update() method (takes the same parameters).
9079          * @param {String/Function} url The url for this request or a function to call to get the url
9080          * @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}
9081          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9082          * @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.
9083          * @return {Roo.Element} this
9084          */
9085         load : function(){
9086             var um = this.getUpdateManager();
9087             um.update.apply(um, arguments);
9088             return this;
9089         },
9090
9091         /**
9092         * Gets this element's UpdateManager
9093         * @return {Roo.UpdateManager} The UpdateManager
9094         */
9095         getUpdateManager : function(){
9096             if(!this.updateManager){
9097                 this.updateManager = new Roo.UpdateManager(this);
9098             }
9099             return this.updateManager;
9100         },
9101
9102         /**
9103          * Disables text selection for this element (normalized across browsers)
9104          * @return {Roo.Element} this
9105          */
9106         unselectable : function(){
9107             this.dom.unselectable = "on";
9108             this.swallowEvent("selectstart", true);
9109             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9110             this.addClass("x-unselectable");
9111             return this;
9112         },
9113
9114         /**
9115         * Calculates the x, y to center this element on the screen
9116         * @return {Array} The x, y values [x, y]
9117         */
9118         getCenterXY : function(){
9119             return this.getAlignToXY(document, 'c-c');
9120         },
9121
9122         /**
9123         * Centers the Element in either the viewport, or another Element.
9124         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9125         */
9126         center : function(centerIn){
9127             this.alignTo(centerIn || document, 'c-c');
9128             return this;
9129         },
9130
9131         /**
9132          * Tests various css rules/browsers to determine if this element uses a border box
9133          * @return {Boolean}
9134          */
9135         isBorderBox : function(){
9136             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9137         },
9138
9139         /**
9140          * Return a box {x, y, width, height} that can be used to set another elements
9141          * size/location to match this element.
9142          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9143          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9144          * @return {Object} box An object in the format {x, y, width, height}
9145          */
9146         getBox : function(contentBox, local){
9147             var xy;
9148             if(!local){
9149                 xy = this.getXY();
9150             }else{
9151                 var left = parseInt(this.getStyle("left"), 10) || 0;
9152                 var top = parseInt(this.getStyle("top"), 10) || 0;
9153                 xy = [left, top];
9154             }
9155             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9156             if(!contentBox){
9157                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9158             }else{
9159                 var l = this.getBorderWidth("l")+this.getPadding("l");
9160                 var r = this.getBorderWidth("r")+this.getPadding("r");
9161                 var t = this.getBorderWidth("t")+this.getPadding("t");
9162                 var b = this.getBorderWidth("b")+this.getPadding("b");
9163                 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)};
9164             }
9165             bx.right = bx.x + bx.width;
9166             bx.bottom = bx.y + bx.height;
9167             return bx;
9168         },
9169
9170         /**
9171          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9172          for more information about the sides.
9173          * @param {String} sides
9174          * @return {Number}
9175          */
9176         getFrameWidth : function(sides, onlyContentBox){
9177             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9178         },
9179
9180         /**
9181          * 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.
9182          * @param {Object} box The box to fill {x, y, width, height}
9183          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9184          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9185          * @return {Roo.Element} this
9186          */
9187         setBox : function(box, adjust, animate){
9188             var w = box.width, h = box.height;
9189             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9190                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9191                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9192             }
9193             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9194             return this;
9195         },
9196
9197         /**
9198          * Forces the browser to repaint this element
9199          * @return {Roo.Element} this
9200          */
9201          repaint : function(){
9202             var dom = this.dom;
9203             this.addClass("x-repaint");
9204             setTimeout(function(){
9205                 Roo.get(dom).removeClass("x-repaint");
9206             }, 1);
9207             return this;
9208         },
9209
9210         /**
9211          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9212          * then it returns the calculated width of the sides (see getPadding)
9213          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9214          * @return {Object/Number}
9215          */
9216         getMargins : function(side){
9217             if(!side){
9218                 return {
9219                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9220                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9221                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9222                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9223                 };
9224             }else{
9225                 return this.addStyles(side, El.margins);
9226              }
9227         },
9228
9229         // private
9230         addStyles : function(sides, styles){
9231             var val = 0, v, w;
9232             for(var i = 0, len = sides.length; i < len; i++){
9233                 v = this.getStyle(styles[sides.charAt(i)]);
9234                 if(v){
9235                      w = parseInt(v, 10);
9236                      if(w){ val += w; }
9237                 }
9238             }
9239             return val;
9240         },
9241
9242         /**
9243          * Creates a proxy element of this element
9244          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9245          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9246          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9247          * @return {Roo.Element} The new proxy element
9248          */
9249         createProxy : function(config, renderTo, matchBox){
9250             if(renderTo){
9251                 renderTo = Roo.getDom(renderTo);
9252             }else{
9253                 renderTo = document.body;
9254             }
9255             config = typeof config == "object" ?
9256                 config : {tag : "div", cls: config};
9257             var proxy = Roo.DomHelper.append(renderTo, config, true);
9258             if(matchBox){
9259                proxy.setBox(this.getBox());
9260             }
9261             return proxy;
9262         },
9263
9264         /**
9265          * Puts a mask over this element to disable user interaction. Requires core.css.
9266          * This method can only be applied to elements which accept child nodes.
9267          * @param {String} msg (optional) A message to display in the mask
9268          * @param {String} msgCls (optional) A css class to apply to the msg element
9269          * @return {Element} The mask  element
9270          */
9271         mask : function(msg, msgCls)
9272         {
9273             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9274                 this.setStyle("position", "relative");
9275             }
9276             if(!this._mask){
9277                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9278             }
9279             
9280             this.addClass("x-masked");
9281             this._mask.setDisplayed(true);
9282             
9283             // we wander
9284             var z = 0;
9285             var dom = this.dom;
9286             while (dom && dom.style) {
9287                 if (!isNaN(parseInt(dom.style.zIndex))) {
9288                     z = Math.max(z, parseInt(dom.style.zIndex));
9289                 }
9290                 dom = dom.parentNode;
9291             }
9292             // if we are masking the body - then it hides everything..
9293             if (this.dom == document.body) {
9294                 z = 1000000;
9295                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9296                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9297             }
9298            
9299             if(typeof msg == 'string'){
9300                 if(!this._maskMsg){
9301                     this._maskMsg = Roo.DomHelper.append(this.dom, {
9302                         cls: "roo-el-mask-msg", 
9303                         cn: [
9304                             {
9305                                 tag: 'i',
9306                                 cls: 'fa fa-spinner fa-spin'
9307                             },
9308                             {
9309                                 tag: 'div'
9310                             }   
9311                         ]
9312                     }, true);
9313                 }
9314                 var mm = this._maskMsg;
9315                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9316                 if (mm.dom.lastChild) { // weird IE issue?
9317                     mm.dom.lastChild.innerHTML = msg;
9318                 }
9319                 mm.setDisplayed(true);
9320                 mm.center(this);
9321                 mm.setStyle('z-index', z + 102);
9322             }
9323             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9324                 this._mask.setHeight(this.getHeight());
9325             }
9326             this._mask.setStyle('z-index', z + 100);
9327             
9328             return this._mask;
9329         },
9330
9331         /**
9332          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9333          * it is cached for reuse.
9334          */
9335         unmask : function(removeEl){
9336             if(this._mask){
9337                 if(removeEl === true){
9338                     this._mask.remove();
9339                     delete this._mask;
9340                     if(this._maskMsg){
9341                         this._maskMsg.remove();
9342                         delete this._maskMsg;
9343                     }
9344                 }else{
9345                     this._mask.setDisplayed(false);
9346                     if(this._maskMsg){
9347                         this._maskMsg.setDisplayed(false);
9348                     }
9349                 }
9350             }
9351             this.removeClass("x-masked");
9352         },
9353
9354         /**
9355          * Returns true if this element is masked
9356          * @return {Boolean}
9357          */
9358         isMasked : function(){
9359             return this._mask && this._mask.isVisible();
9360         },
9361
9362         /**
9363          * Creates an iframe shim for this element to keep selects and other windowed objects from
9364          * showing through.
9365          * @return {Roo.Element} The new shim element
9366          */
9367         createShim : function(){
9368             var el = document.createElement('iframe');
9369             el.frameBorder = 'no';
9370             el.className = 'roo-shim';
9371             if(Roo.isIE && Roo.isSecure){
9372                 el.src = Roo.SSL_SECURE_URL;
9373             }
9374             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9375             shim.autoBoxAdjust = false;
9376             return shim;
9377         },
9378
9379         /**
9380          * Removes this element from the DOM and deletes it from the cache
9381          */
9382         remove : function(){
9383             if(this.dom.parentNode){
9384                 this.dom.parentNode.removeChild(this.dom);
9385             }
9386             delete El.cache[this.dom.id];
9387         },
9388
9389         /**
9390          * Sets up event handlers to add and remove a css class when the mouse is over this element
9391          * @param {String} className
9392          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9393          * mouseout events for children elements
9394          * @return {Roo.Element} this
9395          */
9396         addClassOnOver : function(className, preventFlicker){
9397             this.on("mouseover", function(){
9398                 Roo.fly(this, '_internal').addClass(className);
9399             }, this.dom);
9400             var removeFn = function(e){
9401                 if(preventFlicker !== true || !e.within(this, true)){
9402                     Roo.fly(this, '_internal').removeClass(className);
9403                 }
9404             };
9405             this.on("mouseout", removeFn, this.dom);
9406             return this;
9407         },
9408
9409         /**
9410          * Sets up event handlers to add and remove a css class when this element has the focus
9411          * @param {String} className
9412          * @return {Roo.Element} this
9413          */
9414         addClassOnFocus : function(className){
9415             this.on("focus", function(){
9416                 Roo.fly(this, '_internal').addClass(className);
9417             }, this.dom);
9418             this.on("blur", function(){
9419                 Roo.fly(this, '_internal').removeClass(className);
9420             }, this.dom);
9421             return this;
9422         },
9423         /**
9424          * 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)
9425          * @param {String} className
9426          * @return {Roo.Element} this
9427          */
9428         addClassOnClick : function(className){
9429             var dom = this.dom;
9430             this.on("mousedown", function(){
9431                 Roo.fly(dom, '_internal').addClass(className);
9432                 var d = Roo.get(document);
9433                 var fn = function(){
9434                     Roo.fly(dom, '_internal').removeClass(className);
9435                     d.removeListener("mouseup", fn);
9436                 };
9437                 d.on("mouseup", fn);
9438             });
9439             return this;
9440         },
9441
9442         /**
9443          * Stops the specified event from bubbling and optionally prevents the default action
9444          * @param {String} eventName
9445          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9446          * @return {Roo.Element} this
9447          */
9448         swallowEvent : function(eventName, preventDefault){
9449             var fn = function(e){
9450                 e.stopPropagation();
9451                 if(preventDefault){
9452                     e.preventDefault();
9453                 }
9454             };
9455             if(eventName instanceof Array){
9456                 for(var i = 0, len = eventName.length; i < len; i++){
9457                      this.on(eventName[i], fn);
9458                 }
9459                 return this;
9460             }
9461             this.on(eventName, fn);
9462             return this;
9463         },
9464
9465         /**
9466          * @private
9467          */
9468         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9469
9470         /**
9471          * Sizes this element to its parent element's dimensions performing
9472          * neccessary box adjustments.
9473          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9474          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9475          * @return {Roo.Element} this
9476          */
9477         fitToParent : function(monitorResize, targetParent) {
9478           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9479           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9480           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9481             return this;
9482           }
9483           var p = Roo.get(targetParent || this.dom.parentNode);
9484           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9485           if (monitorResize === true) {
9486             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9487             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9488           }
9489           return this;
9490         },
9491
9492         /**
9493          * Gets the next sibling, skipping text nodes
9494          * @return {HTMLElement} The next sibling or null
9495          */
9496         getNextSibling : function(){
9497             var n = this.dom.nextSibling;
9498             while(n && n.nodeType != 1){
9499                 n = n.nextSibling;
9500             }
9501             return n;
9502         },
9503
9504         /**
9505          * Gets the previous sibling, skipping text nodes
9506          * @return {HTMLElement} The previous sibling or null
9507          */
9508         getPrevSibling : function(){
9509             var n = this.dom.previousSibling;
9510             while(n && n.nodeType != 1){
9511                 n = n.previousSibling;
9512             }
9513             return n;
9514         },
9515
9516
9517         /**
9518          * Appends the passed element(s) to this element
9519          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9520          * @return {Roo.Element} this
9521          */
9522         appendChild: function(el){
9523             el = Roo.get(el);
9524             el.appendTo(this);
9525             return this;
9526         },
9527
9528         /**
9529          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9530          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9531          * automatically generated with the specified attributes.
9532          * @param {HTMLElement} insertBefore (optional) a child element of this element
9533          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9534          * @return {Roo.Element} The new child element
9535          */
9536         createChild: function(config, insertBefore, returnDom){
9537             config = config || {tag:'div'};
9538             if(insertBefore){
9539                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9540             }
9541             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9542         },
9543
9544         /**
9545          * Appends this element to the passed element
9546          * @param {String/HTMLElement/Element} el The new parent element
9547          * @return {Roo.Element} this
9548          */
9549         appendTo: function(el){
9550             el = Roo.getDom(el);
9551             el.appendChild(this.dom);
9552             return this;
9553         },
9554
9555         /**
9556          * Inserts this element before the passed element in the DOM
9557          * @param {String/HTMLElement/Element} el The element to insert before
9558          * @return {Roo.Element} this
9559          */
9560         insertBefore: function(el){
9561             el = Roo.getDom(el);
9562             el.parentNode.insertBefore(this.dom, el);
9563             return this;
9564         },
9565
9566         /**
9567          * Inserts this element after the passed element in the DOM
9568          * @param {String/HTMLElement/Element} el The element to insert after
9569          * @return {Roo.Element} this
9570          */
9571         insertAfter: function(el){
9572             el = Roo.getDom(el);
9573             el.parentNode.insertBefore(this.dom, el.nextSibling);
9574             return this;
9575         },
9576
9577         /**
9578          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9579          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9580          * @return {Roo.Element} The new child
9581          */
9582         insertFirst: function(el, returnDom){
9583             el = el || {};
9584             if(typeof el == 'object' && !el.nodeType){ // dh config
9585                 return this.createChild(el, this.dom.firstChild, returnDom);
9586             }else{
9587                 el = Roo.getDom(el);
9588                 this.dom.insertBefore(el, this.dom.firstChild);
9589                 return !returnDom ? Roo.get(el) : el;
9590             }
9591         },
9592
9593         /**
9594          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9595          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9596          * @param {String} where (optional) 'before' or 'after' defaults to before
9597          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9598          * @return {Roo.Element} the inserted Element
9599          */
9600         insertSibling: function(el, where, returnDom){
9601             where = where ? where.toLowerCase() : 'before';
9602             el = el || {};
9603             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9604
9605             if(typeof el == 'object' && !el.nodeType){ // dh config
9606                 if(where == 'after' && !this.dom.nextSibling){
9607                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9608                 }else{
9609                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9610                 }
9611
9612             }else{
9613                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9614                             where == 'before' ? this.dom : this.dom.nextSibling);
9615                 if(!returnDom){
9616                     rt = Roo.get(rt);
9617                 }
9618             }
9619             return rt;
9620         },
9621
9622         /**
9623          * Creates and wraps this element with another element
9624          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9625          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9626          * @return {HTMLElement/Element} The newly created wrapper element
9627          */
9628         wrap: function(config, returnDom){
9629             if(!config){
9630                 config = {tag: "div"};
9631             }
9632             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9633             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9634             return newEl;
9635         },
9636
9637         /**
9638          * Replaces the passed element with this element
9639          * @param {String/HTMLElement/Element} el The element to replace
9640          * @return {Roo.Element} this
9641          */
9642         replace: function(el){
9643             el = Roo.get(el);
9644             this.insertBefore(el);
9645             el.remove();
9646             return this;
9647         },
9648
9649         /**
9650          * Inserts an html fragment into this element
9651          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9652          * @param {String} html The HTML fragment
9653          * @param {Boolean} returnEl True to return an Roo.Element
9654          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9655          */
9656         insertHtml : function(where, html, returnEl){
9657             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9658             return returnEl ? Roo.get(el) : el;
9659         },
9660
9661         /**
9662          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9663          * @param {Object} o The object with the attributes
9664          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9665          * @return {Roo.Element} this
9666          */
9667         set : function(o, useSet){
9668             var el = this.dom;
9669             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9670             for(var attr in o){
9671                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9672                 if(attr=="cls"){
9673                     el.className = o["cls"];
9674                 }else{
9675                     if(useSet) {
9676                         el.setAttribute(attr, o[attr]);
9677                     } else {
9678                         el[attr] = o[attr];
9679                     }
9680                 }
9681             }
9682             if(o.style){
9683                 Roo.DomHelper.applyStyles(el, o.style);
9684             }
9685             return this;
9686         },
9687
9688         /**
9689          * Convenience method for constructing a KeyMap
9690          * @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:
9691          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9692          * @param {Function} fn The function to call
9693          * @param {Object} scope (optional) The scope of the function
9694          * @return {Roo.KeyMap} The KeyMap created
9695          */
9696         addKeyListener : function(key, fn, scope){
9697             var config;
9698             if(typeof key != "object" || key instanceof Array){
9699                 config = {
9700                     key: key,
9701                     fn: fn,
9702                     scope: scope
9703                 };
9704             }else{
9705                 config = {
9706                     key : key.key,
9707                     shift : key.shift,
9708                     ctrl : key.ctrl,
9709                     alt : key.alt,
9710                     fn: fn,
9711                     scope: scope
9712                 };
9713             }
9714             return new Roo.KeyMap(this, config);
9715         },
9716
9717         /**
9718          * Creates a KeyMap for this element
9719          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9720          * @return {Roo.KeyMap} The KeyMap created
9721          */
9722         addKeyMap : function(config){
9723             return new Roo.KeyMap(this, config);
9724         },
9725
9726         /**
9727          * Returns true if this element is scrollable.
9728          * @return {Boolean}
9729          */
9730          isScrollable : function(){
9731             var dom = this.dom;
9732             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9733         },
9734
9735         /**
9736          * 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().
9737          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9738          * @param {Number} value The new scroll value
9739          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9740          * @return {Element} this
9741          */
9742
9743         scrollTo : function(side, value, animate){
9744             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9745             if(!animate || !A){
9746                 this.dom[prop] = value;
9747             }else{
9748                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9749                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9750             }
9751             return this;
9752         },
9753
9754         /**
9755          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9756          * within this element's scrollable range.
9757          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9758          * @param {Number} distance How far to scroll the element in pixels
9759          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9760          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9761          * was scrolled as far as it could go.
9762          */
9763          scroll : function(direction, distance, animate){
9764              if(!this.isScrollable()){
9765                  return;
9766              }
9767              var el = this.dom;
9768              var l = el.scrollLeft, t = el.scrollTop;
9769              var w = el.scrollWidth, h = el.scrollHeight;
9770              var cw = el.clientWidth, ch = el.clientHeight;
9771              direction = direction.toLowerCase();
9772              var scrolled = false;
9773              var a = this.preanim(arguments, 2);
9774              switch(direction){
9775                  case "l":
9776                  case "left":
9777                      if(w - l > cw){
9778                          var v = Math.min(l + distance, w-cw);
9779                          this.scrollTo("left", v, a);
9780                          scrolled = true;
9781                      }
9782                      break;
9783                 case "r":
9784                 case "right":
9785                      if(l > 0){
9786                          var v = Math.max(l - distance, 0);
9787                          this.scrollTo("left", v, a);
9788                          scrolled = true;
9789                      }
9790                      break;
9791                 case "t":
9792                 case "top":
9793                 case "up":
9794                      if(t > 0){
9795                          var v = Math.max(t - distance, 0);
9796                          this.scrollTo("top", v, a);
9797                          scrolled = true;
9798                      }
9799                      break;
9800                 case "b":
9801                 case "bottom":
9802                 case "down":
9803                      if(h - t > ch){
9804                          var v = Math.min(t + distance, h-ch);
9805                          this.scrollTo("top", v, a);
9806                          scrolled = true;
9807                      }
9808                      break;
9809              }
9810              return scrolled;
9811         },
9812
9813         /**
9814          * Translates the passed page coordinates into left/top css values for this element
9815          * @param {Number/Array} x The page x or an array containing [x, y]
9816          * @param {Number} y The page y
9817          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9818          */
9819         translatePoints : function(x, y){
9820             if(typeof x == 'object' || x instanceof Array){
9821                 y = x[1]; x = x[0];
9822             }
9823             var p = this.getStyle('position');
9824             var o = this.getXY();
9825
9826             var l = parseInt(this.getStyle('left'), 10);
9827             var t = parseInt(this.getStyle('top'), 10);
9828
9829             if(isNaN(l)){
9830                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9831             }
9832             if(isNaN(t)){
9833                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9834             }
9835
9836             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9837         },
9838
9839         /**
9840          * Returns the current scroll position of the element.
9841          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9842          */
9843         getScroll : function(){
9844             var d = this.dom, doc = document;
9845             if(d == doc || d == doc.body){
9846                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9847                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9848                 return {left: l, top: t};
9849             }else{
9850                 return {left: d.scrollLeft, top: d.scrollTop};
9851             }
9852         },
9853
9854         /**
9855          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9856          * are convert to standard 6 digit hex color.
9857          * @param {String} attr The css attribute
9858          * @param {String} defaultValue The default value to use when a valid color isn't found
9859          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9860          * YUI color anims.
9861          */
9862         getColor : function(attr, defaultValue, prefix){
9863             var v = this.getStyle(attr);
9864             if(!v || v == "transparent" || v == "inherit") {
9865                 return defaultValue;
9866             }
9867             var color = typeof prefix == "undefined" ? "#" : prefix;
9868             if(v.substr(0, 4) == "rgb("){
9869                 var rvs = v.slice(4, v.length -1).split(",");
9870                 for(var i = 0; i < 3; i++){
9871                     var h = parseInt(rvs[i]).toString(16);
9872                     if(h < 16){
9873                         h = "0" + h;
9874                     }
9875                     color += h;
9876                 }
9877             } else {
9878                 if(v.substr(0, 1) == "#"){
9879                     if(v.length == 4) {
9880                         for(var i = 1; i < 4; i++){
9881                             var c = v.charAt(i);
9882                             color +=  c + c;
9883                         }
9884                     }else if(v.length == 7){
9885                         color += v.substr(1);
9886                     }
9887                 }
9888             }
9889             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9890         },
9891
9892         /**
9893          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9894          * gradient background, rounded corners and a 4-way shadow.
9895          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9896          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9897          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9898          * @return {Roo.Element} this
9899          */
9900         boxWrap : function(cls){
9901             cls = cls || 'x-box';
9902             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9903             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9904             return el;
9905         },
9906
9907         /**
9908          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9909          * @param {String} namespace The namespace in which to look for the attribute
9910          * @param {String} name The attribute name
9911          * @return {String} The attribute value
9912          */
9913         getAttributeNS : Roo.isIE ? function(ns, name){
9914             var d = this.dom;
9915             var type = typeof d[ns+":"+name];
9916             if(type != 'undefined' && type != 'unknown'){
9917                 return d[ns+":"+name];
9918             }
9919             return d[name];
9920         } : function(ns, name){
9921             var d = this.dom;
9922             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9923         },
9924         
9925         
9926         /**
9927          * Sets or Returns the value the dom attribute value
9928          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9929          * @param {String} value (optional) The value to set the attribute to
9930          * @return {String} The attribute value
9931          */
9932         attr : function(name){
9933             if (arguments.length > 1) {
9934                 this.dom.setAttribute(name, arguments[1]);
9935                 return arguments[1];
9936             }
9937             if (typeof(name) == 'object') {
9938                 for(var i in name) {
9939                     this.attr(i, name[i]);
9940                 }
9941                 return name;
9942             }
9943             
9944             
9945             if (!this.dom.hasAttribute(name)) {
9946                 return undefined;
9947             }
9948             return this.dom.getAttribute(name);
9949         }
9950         
9951         
9952         
9953     };
9954
9955     var ep = El.prototype;
9956
9957     /**
9958      * Appends an event handler (Shorthand for addListener)
9959      * @param {String}   eventName     The type of event to append
9960      * @param {Function} fn        The method the event invokes
9961      * @param {Object} scope       (optional) The scope (this object) of the fn
9962      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9963      * @method
9964      */
9965     ep.on = ep.addListener;
9966         // backwards compat
9967     ep.mon = ep.addListener;
9968
9969     /**
9970      * Removes an event handler from this element (shorthand for removeListener)
9971      * @param {String} eventName the type of event to remove
9972      * @param {Function} fn the method the event invokes
9973      * @return {Roo.Element} this
9974      * @method
9975      */
9976     ep.un = ep.removeListener;
9977
9978     /**
9979      * true to automatically adjust width and height settings for box-model issues (default to true)
9980      */
9981     ep.autoBoxAdjust = true;
9982
9983     // private
9984     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9985
9986     // private
9987     El.addUnits = function(v, defaultUnit){
9988         if(v === "" || v == "auto"){
9989             return v;
9990         }
9991         if(v === undefined){
9992             return '';
9993         }
9994         if(typeof v == "number" || !El.unitPattern.test(v)){
9995             return v + (defaultUnit || 'px');
9996         }
9997         return v;
9998     };
9999
10000     // special markup used throughout Roo when box wrapping elements
10001     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>';
10002     /**
10003      * Visibility mode constant - Use visibility to hide element
10004      * @static
10005      * @type Number
10006      */
10007     El.VISIBILITY = 1;
10008     /**
10009      * Visibility mode constant - Use display to hide element
10010      * @static
10011      * @type Number
10012      */
10013     El.DISPLAY = 2;
10014
10015     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10016     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10017     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10018
10019
10020
10021     /**
10022      * @private
10023      */
10024     El.cache = {};
10025
10026     var docEl;
10027
10028     /**
10029      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10030      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10031      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10032      * @return {Element} The Element object
10033      * @static
10034      */
10035     El.get = function(el){
10036         var ex, elm, id;
10037         if(!el){ return null; }
10038         if(typeof el == "string"){ // element id
10039             if(!(elm = document.getElementById(el))){
10040                 return null;
10041             }
10042             if(ex = El.cache[el]){
10043                 ex.dom = elm;
10044             }else{
10045                 ex = El.cache[el] = new El(elm);
10046             }
10047             return ex;
10048         }else if(el.tagName){ // dom element
10049             if(!(id = el.id)){
10050                 id = Roo.id(el);
10051             }
10052             if(ex = El.cache[id]){
10053                 ex.dom = el;
10054             }else{
10055                 ex = El.cache[id] = new El(el);
10056             }
10057             return ex;
10058         }else if(el instanceof El){
10059             if(el != docEl){
10060                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10061                                                               // catch case where it hasn't been appended
10062                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10063             }
10064             return el;
10065         }else if(el.isComposite){
10066             return el;
10067         }else if(el instanceof Array){
10068             return El.select(el);
10069         }else if(el == document){
10070             // create a bogus element object representing the document object
10071             if(!docEl){
10072                 var f = function(){};
10073                 f.prototype = El.prototype;
10074                 docEl = new f();
10075                 docEl.dom = document;
10076             }
10077             return docEl;
10078         }
10079         return null;
10080     };
10081
10082     // private
10083     El.uncache = function(el){
10084         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10085             if(a[i]){
10086                 delete El.cache[a[i].id || a[i]];
10087             }
10088         }
10089     };
10090
10091     // private
10092     // Garbage collection - uncache elements/purge listeners on orphaned elements
10093     // so we don't hold a reference and cause the browser to retain them
10094     El.garbageCollect = function(){
10095         if(!Roo.enableGarbageCollector){
10096             clearInterval(El.collectorThread);
10097             return;
10098         }
10099         for(var eid in El.cache){
10100             var el = El.cache[eid], d = el.dom;
10101             // -------------------------------------------------------
10102             // Determining what is garbage:
10103             // -------------------------------------------------------
10104             // !d
10105             // dom node is null, definitely garbage
10106             // -------------------------------------------------------
10107             // !d.parentNode
10108             // no parentNode == direct orphan, definitely garbage
10109             // -------------------------------------------------------
10110             // !d.offsetParent && !document.getElementById(eid)
10111             // display none elements have no offsetParent so we will
10112             // also try to look it up by it's id. However, check
10113             // offsetParent first so we don't do unneeded lookups.
10114             // This enables collection of elements that are not orphans
10115             // directly, but somewhere up the line they have an orphan
10116             // parent.
10117             // -------------------------------------------------------
10118             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10119                 delete El.cache[eid];
10120                 if(d && Roo.enableListenerCollection){
10121                     E.purgeElement(d);
10122                 }
10123             }
10124         }
10125     }
10126     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10127
10128
10129     // dom is optional
10130     El.Flyweight = function(dom){
10131         this.dom = dom;
10132     };
10133     El.Flyweight.prototype = El.prototype;
10134
10135     El._flyweights = {};
10136     /**
10137      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10138      * the dom node can be overwritten by other code.
10139      * @param {String/HTMLElement} el The dom node or id
10140      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10141      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10142      * @static
10143      * @return {Element} The shared Element object
10144      */
10145     El.fly = function(el, named){
10146         named = named || '_global';
10147         el = Roo.getDom(el);
10148         if(!el){
10149             return null;
10150         }
10151         if(!El._flyweights[named]){
10152             El._flyweights[named] = new El.Flyweight();
10153         }
10154         El._flyweights[named].dom = el;
10155         return El._flyweights[named];
10156     };
10157
10158     /**
10159      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10160      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10161      * Shorthand of {@link Roo.Element#get}
10162      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10163      * @return {Element} The Element object
10164      * @member Roo
10165      * @method get
10166      */
10167     Roo.get = El.get;
10168     /**
10169      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10170      * the dom node can be overwritten by other code.
10171      * Shorthand of {@link Roo.Element#fly}
10172      * @param {String/HTMLElement} el The dom node or id
10173      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10174      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10175      * @static
10176      * @return {Element} The shared Element object
10177      * @member Roo
10178      * @method fly
10179      */
10180     Roo.fly = El.fly;
10181
10182     // speedy lookup for elements never to box adjust
10183     var noBoxAdjust = Roo.isStrict ? {
10184         select:1
10185     } : {
10186         input:1, select:1, textarea:1
10187     };
10188     if(Roo.isIE || Roo.isGecko){
10189         noBoxAdjust['button'] = 1;
10190     }
10191
10192
10193     Roo.EventManager.on(window, 'unload', function(){
10194         delete El.cache;
10195         delete El._flyweights;
10196     });
10197 })();
10198
10199
10200
10201
10202 if(Roo.DomQuery){
10203     Roo.Element.selectorFunction = Roo.DomQuery.select;
10204 }
10205
10206 Roo.Element.select = function(selector, unique, root){
10207     var els;
10208     if(typeof selector == "string"){
10209         els = Roo.Element.selectorFunction(selector, root);
10210     }else if(selector.length !== undefined){
10211         els = selector;
10212     }else{
10213         throw "Invalid selector";
10214     }
10215     if(unique === true){
10216         return new Roo.CompositeElement(els);
10217     }else{
10218         return new Roo.CompositeElementLite(els);
10219     }
10220 };
10221 /**
10222  * Selects elements based on the passed CSS selector to enable working on them as 1.
10223  * @param {String/Array} selector The CSS selector or an array of elements
10224  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10225  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10226  * @return {CompositeElementLite/CompositeElement}
10227  * @member Roo
10228  * @method select
10229  */
10230 Roo.select = Roo.Element.select;
10231
10232
10233
10234
10235
10236
10237
10238
10239
10240
10241
10242
10243
10244
10245 /*
10246  * Based on:
10247  * Ext JS Library 1.1.1
10248  * Copyright(c) 2006-2007, Ext JS, LLC.
10249  *
10250  * Originally Released Under LGPL - original licence link has changed is not relivant.
10251  *
10252  * Fork - LGPL
10253  * <script type="text/javascript">
10254  */
10255
10256
10257
10258 //Notifies Element that fx methods are available
10259 Roo.enableFx = true;
10260
10261 /**
10262  * @class Roo.Fx
10263  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10264  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10265  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10266  * Element effects to work.</p><br/>
10267  *
10268  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10269  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10270  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10271  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10272  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10273  * expected results and should be done with care.</p><br/>
10274  *
10275  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10276  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10277 <pre>
10278 Value  Description
10279 -----  -----------------------------
10280 tl     The top left corner
10281 t      The center of the top edge
10282 tr     The top right corner
10283 l      The center of the left edge
10284 r      The center of the right edge
10285 bl     The bottom left corner
10286 b      The center of the bottom edge
10287 br     The bottom right corner
10288 </pre>
10289  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10290  * below are common options that can be passed to any Fx method.</b>
10291  * @cfg {Function} callback A function called when the effect is finished
10292  * @cfg {Object} scope The scope of the effect function
10293  * @cfg {String} easing A valid Easing value for the effect
10294  * @cfg {String} afterCls A css class to apply after the effect
10295  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10296  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10297  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10298  * effects that end with the element being visually hidden, ignored otherwise)
10299  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10300  * a function which returns such a specification that will be applied to the Element after the effect finishes
10301  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10302  * @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
10303  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10304  */
10305 Roo.Fx = {
10306         /**
10307          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10308          * origin for the slide effect.  This function automatically handles wrapping the element with
10309          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10310          * Usage:
10311          *<pre><code>
10312 // default: slide the element in from the top
10313 el.slideIn();
10314
10315 // custom: slide the element in from the right with a 2-second duration
10316 el.slideIn('r', { duration: 2 });
10317
10318 // common config options shown with default values
10319 el.slideIn('t', {
10320     easing: 'easeOut',
10321     duration: .5
10322 });
10323 </code></pre>
10324          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10325          * @param {Object} options (optional) Object literal with any of the Fx config options
10326          * @return {Roo.Element} The Element
10327          */
10328     slideIn : function(anchor, o){
10329         var el = this.getFxEl();
10330         o = o || {};
10331
10332         el.queueFx(o, function(){
10333
10334             anchor = anchor || "t";
10335
10336             // fix display to visibility
10337             this.fixDisplay();
10338
10339             // restore values after effect
10340             var r = this.getFxRestore();
10341             var b = this.getBox();
10342             // fixed size for slide
10343             this.setSize(b);
10344
10345             // wrap if needed
10346             var wrap = this.fxWrap(r.pos, o, "hidden");
10347
10348             var st = this.dom.style;
10349             st.visibility = "visible";
10350             st.position = "absolute";
10351
10352             // clear out temp styles after slide and unwrap
10353             var after = function(){
10354                 el.fxUnwrap(wrap, r.pos, o);
10355                 st.width = r.width;
10356                 st.height = r.height;
10357                 el.afterFx(o);
10358             };
10359             // time to calc the positions
10360             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10361
10362             switch(anchor.toLowerCase()){
10363                 case "t":
10364                     wrap.setSize(b.width, 0);
10365                     st.left = st.bottom = "0";
10366                     a = {height: bh};
10367                 break;
10368                 case "l":
10369                     wrap.setSize(0, b.height);
10370                     st.right = st.top = "0";
10371                     a = {width: bw};
10372                 break;
10373                 case "r":
10374                     wrap.setSize(0, b.height);
10375                     wrap.setX(b.right);
10376                     st.left = st.top = "0";
10377                     a = {width: bw, points: pt};
10378                 break;
10379                 case "b":
10380                     wrap.setSize(b.width, 0);
10381                     wrap.setY(b.bottom);
10382                     st.left = st.top = "0";
10383                     a = {height: bh, points: pt};
10384                 break;
10385                 case "tl":
10386                     wrap.setSize(0, 0);
10387                     st.right = st.bottom = "0";
10388                     a = {width: bw, height: bh};
10389                 break;
10390                 case "bl":
10391                     wrap.setSize(0, 0);
10392                     wrap.setY(b.y+b.height);
10393                     st.right = st.top = "0";
10394                     a = {width: bw, height: bh, points: pt};
10395                 break;
10396                 case "br":
10397                     wrap.setSize(0, 0);
10398                     wrap.setXY([b.right, b.bottom]);
10399                     st.left = st.top = "0";
10400                     a = {width: bw, height: bh, points: pt};
10401                 break;
10402                 case "tr":
10403                     wrap.setSize(0, 0);
10404                     wrap.setX(b.x+b.width);
10405                     st.left = st.bottom = "0";
10406                     a = {width: bw, height: bh, points: pt};
10407                 break;
10408             }
10409             this.dom.style.visibility = "visible";
10410             wrap.show();
10411
10412             arguments.callee.anim = wrap.fxanim(a,
10413                 o,
10414                 'motion',
10415                 .5,
10416                 'easeOut', after);
10417         });
10418         return this;
10419     },
10420     
10421         /**
10422          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10423          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10424          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10425          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10426          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10427          * Usage:
10428          *<pre><code>
10429 // default: slide the element out to the top
10430 el.slideOut();
10431
10432 // custom: slide the element out to the right with a 2-second duration
10433 el.slideOut('r', { duration: 2 });
10434
10435 // common config options shown with default values
10436 el.slideOut('t', {
10437     easing: 'easeOut',
10438     duration: .5,
10439     remove: false,
10440     useDisplay: false
10441 });
10442 </code></pre>
10443          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10444          * @param {Object} options (optional) Object literal with any of the Fx config options
10445          * @return {Roo.Element} The Element
10446          */
10447     slideOut : function(anchor, o){
10448         var el = this.getFxEl();
10449         o = o || {};
10450
10451         el.queueFx(o, function(){
10452
10453             anchor = anchor || "t";
10454
10455             // restore values after effect
10456             var r = this.getFxRestore();
10457             
10458             var b = this.getBox();
10459             // fixed size for slide
10460             this.setSize(b);
10461
10462             // wrap if needed
10463             var wrap = this.fxWrap(r.pos, o, "visible");
10464
10465             var st = this.dom.style;
10466             st.visibility = "visible";
10467             st.position = "absolute";
10468
10469             wrap.setSize(b);
10470
10471             var after = function(){
10472                 if(o.useDisplay){
10473                     el.setDisplayed(false);
10474                 }else{
10475                     el.hide();
10476                 }
10477
10478                 el.fxUnwrap(wrap, r.pos, o);
10479
10480                 st.width = r.width;
10481                 st.height = r.height;
10482
10483                 el.afterFx(o);
10484             };
10485
10486             var a, zero = {to: 0};
10487             switch(anchor.toLowerCase()){
10488                 case "t":
10489                     st.left = st.bottom = "0";
10490                     a = {height: zero};
10491                 break;
10492                 case "l":
10493                     st.right = st.top = "0";
10494                     a = {width: zero};
10495                 break;
10496                 case "r":
10497                     st.left = st.top = "0";
10498                     a = {width: zero, points: {to:[b.right, b.y]}};
10499                 break;
10500                 case "b":
10501                     st.left = st.top = "0";
10502                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10503                 break;
10504                 case "tl":
10505                     st.right = st.bottom = "0";
10506                     a = {width: zero, height: zero};
10507                 break;
10508                 case "bl":
10509                     st.right = st.top = "0";
10510                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10511                 break;
10512                 case "br":
10513                     st.left = st.top = "0";
10514                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10515                 break;
10516                 case "tr":
10517                     st.left = st.bottom = "0";
10518                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10519                 break;
10520             }
10521
10522             arguments.callee.anim = wrap.fxanim(a,
10523                 o,
10524                 'motion',
10525                 .5,
10526                 "easeOut", after);
10527         });
10528         return this;
10529     },
10530
10531         /**
10532          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10533          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10534          * The element must be removed from the DOM using the 'remove' config option if desired.
10535          * Usage:
10536          *<pre><code>
10537 // default
10538 el.puff();
10539
10540 // common config options shown with default values
10541 el.puff({
10542     easing: 'easeOut',
10543     duration: .5,
10544     remove: false,
10545     useDisplay: false
10546 });
10547 </code></pre>
10548          * @param {Object} options (optional) Object literal with any of the Fx config options
10549          * @return {Roo.Element} The Element
10550          */
10551     puff : function(o){
10552         var el = this.getFxEl();
10553         o = o || {};
10554
10555         el.queueFx(o, function(){
10556             this.clearOpacity();
10557             this.show();
10558
10559             // restore values after effect
10560             var r = this.getFxRestore();
10561             var st = this.dom.style;
10562
10563             var after = function(){
10564                 if(o.useDisplay){
10565                     el.setDisplayed(false);
10566                 }else{
10567                     el.hide();
10568                 }
10569
10570                 el.clearOpacity();
10571
10572                 el.setPositioning(r.pos);
10573                 st.width = r.width;
10574                 st.height = r.height;
10575                 st.fontSize = '';
10576                 el.afterFx(o);
10577             };
10578
10579             var width = this.getWidth();
10580             var height = this.getHeight();
10581
10582             arguments.callee.anim = this.fxanim({
10583                     width : {to: this.adjustWidth(width * 2)},
10584                     height : {to: this.adjustHeight(height * 2)},
10585                     points : {by: [-(width * .5), -(height * .5)]},
10586                     opacity : {to: 0},
10587                     fontSize: {to:200, unit: "%"}
10588                 },
10589                 o,
10590                 'motion',
10591                 .5,
10592                 "easeOut", after);
10593         });
10594         return this;
10595     },
10596
10597         /**
10598          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10599          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10600          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10601          * Usage:
10602          *<pre><code>
10603 // default
10604 el.switchOff();
10605
10606 // all config options shown with default values
10607 el.switchOff({
10608     easing: 'easeIn',
10609     duration: .3,
10610     remove: false,
10611     useDisplay: false
10612 });
10613 </code></pre>
10614          * @param {Object} options (optional) Object literal with any of the Fx config options
10615          * @return {Roo.Element} The Element
10616          */
10617     switchOff : function(o){
10618         var el = this.getFxEl();
10619         o = o || {};
10620
10621         el.queueFx(o, function(){
10622             this.clearOpacity();
10623             this.clip();
10624
10625             // restore values after effect
10626             var r = this.getFxRestore();
10627             var st = this.dom.style;
10628
10629             var after = function(){
10630                 if(o.useDisplay){
10631                     el.setDisplayed(false);
10632                 }else{
10633                     el.hide();
10634                 }
10635
10636                 el.clearOpacity();
10637                 el.setPositioning(r.pos);
10638                 st.width = r.width;
10639                 st.height = r.height;
10640
10641                 el.afterFx(o);
10642             };
10643
10644             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10645                 this.clearOpacity();
10646                 (function(){
10647                     this.fxanim({
10648                         height:{to:1},
10649                         points:{by:[0, this.getHeight() * .5]}
10650                     }, o, 'motion', 0.3, 'easeIn', after);
10651                 }).defer(100, this);
10652             });
10653         });
10654         return this;
10655     },
10656
10657     /**
10658      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10659      * changed using the "attr" config option) and then fading back to the original color. If no original
10660      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10661      * Usage:
10662 <pre><code>
10663 // default: highlight background to yellow
10664 el.highlight();
10665
10666 // custom: highlight foreground text to blue for 2 seconds
10667 el.highlight("0000ff", { attr: 'color', duration: 2 });
10668
10669 // common config options shown with default values
10670 el.highlight("ffff9c", {
10671     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10672     endColor: (current color) or "ffffff",
10673     easing: 'easeIn',
10674     duration: 1
10675 });
10676 </code></pre>
10677      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10678      * @param {Object} options (optional) Object literal with any of the Fx config options
10679      * @return {Roo.Element} The Element
10680      */ 
10681     highlight : function(color, o){
10682         var el = this.getFxEl();
10683         o = o || {};
10684
10685         el.queueFx(o, function(){
10686             color = color || "ffff9c";
10687             attr = o.attr || "backgroundColor";
10688
10689             this.clearOpacity();
10690             this.show();
10691
10692             var origColor = this.getColor(attr);
10693             var restoreColor = this.dom.style[attr];
10694             endColor = (o.endColor || origColor) || "ffffff";
10695
10696             var after = function(){
10697                 el.dom.style[attr] = restoreColor;
10698                 el.afterFx(o);
10699             };
10700
10701             var a = {};
10702             a[attr] = {from: color, to: endColor};
10703             arguments.callee.anim = this.fxanim(a,
10704                 o,
10705                 'color',
10706                 1,
10707                 'easeIn', after);
10708         });
10709         return this;
10710     },
10711
10712    /**
10713     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10714     * Usage:
10715 <pre><code>
10716 // default: a single light blue ripple
10717 el.frame();
10718
10719 // custom: 3 red ripples lasting 3 seconds total
10720 el.frame("ff0000", 3, { duration: 3 });
10721
10722 // common config options shown with default values
10723 el.frame("C3DAF9", 1, {
10724     duration: 1 //duration of entire animation (not each individual ripple)
10725     // Note: Easing is not configurable and will be ignored if included
10726 });
10727 </code></pre>
10728     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10729     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10730     * @param {Object} options (optional) Object literal with any of the Fx config options
10731     * @return {Roo.Element} The Element
10732     */
10733     frame : function(color, count, o){
10734         var el = this.getFxEl();
10735         o = o || {};
10736
10737         el.queueFx(o, function(){
10738             color = color || "#C3DAF9";
10739             if(color.length == 6){
10740                 color = "#" + color;
10741             }
10742             count = count || 1;
10743             duration = o.duration || 1;
10744             this.show();
10745
10746             var b = this.getBox();
10747             var animFn = function(){
10748                 var proxy = this.createProxy({
10749
10750                      style:{
10751                         visbility:"hidden",
10752                         position:"absolute",
10753                         "z-index":"35000", // yee haw
10754                         border:"0px solid " + color
10755                      }
10756                   });
10757                 var scale = Roo.isBorderBox ? 2 : 1;
10758                 proxy.animate({
10759                     top:{from:b.y, to:b.y - 20},
10760                     left:{from:b.x, to:b.x - 20},
10761                     borderWidth:{from:0, to:10},
10762                     opacity:{from:1, to:0},
10763                     height:{from:b.height, to:(b.height + (20*scale))},
10764                     width:{from:b.width, to:(b.width + (20*scale))}
10765                 }, duration, function(){
10766                     proxy.remove();
10767                 });
10768                 if(--count > 0){
10769                      animFn.defer((duration/2)*1000, this);
10770                 }else{
10771                     el.afterFx(o);
10772                 }
10773             };
10774             animFn.call(this);
10775         });
10776         return this;
10777     },
10778
10779    /**
10780     * Creates a pause before any subsequent queued effects begin.  If there are
10781     * no effects queued after the pause it will have no effect.
10782     * Usage:
10783 <pre><code>
10784 el.pause(1);
10785 </code></pre>
10786     * @param {Number} seconds The length of time to pause (in seconds)
10787     * @return {Roo.Element} The Element
10788     */
10789     pause : function(seconds){
10790         var el = this.getFxEl();
10791         var o = {};
10792
10793         el.queueFx(o, function(){
10794             setTimeout(function(){
10795                 el.afterFx(o);
10796             }, seconds * 1000);
10797         });
10798         return this;
10799     },
10800
10801    /**
10802     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10803     * using the "endOpacity" config option.
10804     * Usage:
10805 <pre><code>
10806 // default: fade in from opacity 0 to 100%
10807 el.fadeIn();
10808
10809 // custom: fade in from opacity 0 to 75% over 2 seconds
10810 el.fadeIn({ endOpacity: .75, duration: 2});
10811
10812 // common config options shown with default values
10813 el.fadeIn({
10814     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10815     easing: 'easeOut',
10816     duration: .5
10817 });
10818 </code></pre>
10819     * @param {Object} options (optional) Object literal with any of the Fx config options
10820     * @return {Roo.Element} The Element
10821     */
10822     fadeIn : function(o){
10823         var el = this.getFxEl();
10824         o = o || {};
10825         el.queueFx(o, function(){
10826             this.setOpacity(0);
10827             this.fixDisplay();
10828             this.dom.style.visibility = 'visible';
10829             var to = o.endOpacity || 1;
10830             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10831                 o, null, .5, "easeOut", function(){
10832                 if(to == 1){
10833                     this.clearOpacity();
10834                 }
10835                 el.afterFx(o);
10836             });
10837         });
10838         return this;
10839     },
10840
10841    /**
10842     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10843     * using the "endOpacity" config option.
10844     * Usage:
10845 <pre><code>
10846 // default: fade out from the element's current opacity to 0
10847 el.fadeOut();
10848
10849 // custom: fade out from the element's current opacity to 25% over 2 seconds
10850 el.fadeOut({ endOpacity: .25, duration: 2});
10851
10852 // common config options shown with default values
10853 el.fadeOut({
10854     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10855     easing: 'easeOut',
10856     duration: .5
10857     remove: false,
10858     useDisplay: false
10859 });
10860 </code></pre>
10861     * @param {Object} options (optional) Object literal with any of the Fx config options
10862     * @return {Roo.Element} The Element
10863     */
10864     fadeOut : function(o){
10865         var el = this.getFxEl();
10866         o = o || {};
10867         el.queueFx(o, function(){
10868             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10869                 o, null, .5, "easeOut", function(){
10870                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10871                      this.dom.style.display = "none";
10872                 }else{
10873                      this.dom.style.visibility = "hidden";
10874                 }
10875                 this.clearOpacity();
10876                 el.afterFx(o);
10877             });
10878         });
10879         return this;
10880     },
10881
10882    /**
10883     * Animates the transition of an element's dimensions from a starting height/width
10884     * to an ending height/width.
10885     * Usage:
10886 <pre><code>
10887 // change height and width to 100x100 pixels
10888 el.scale(100, 100);
10889
10890 // common config options shown with default values.  The height and width will default to
10891 // the element's existing values if passed as null.
10892 el.scale(
10893     [element's width],
10894     [element's height], {
10895     easing: 'easeOut',
10896     duration: .35
10897 });
10898 </code></pre>
10899     * @param {Number} width  The new width (pass undefined to keep the original width)
10900     * @param {Number} height  The new height (pass undefined to keep the original height)
10901     * @param {Object} options (optional) Object literal with any of the Fx config options
10902     * @return {Roo.Element} The Element
10903     */
10904     scale : function(w, h, o){
10905         this.shift(Roo.apply({}, o, {
10906             width: w,
10907             height: h
10908         }));
10909         return this;
10910     },
10911
10912    /**
10913     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10914     * Any of these properties not specified in the config object will not be changed.  This effect 
10915     * requires that at least one new dimension, position or opacity setting must be passed in on
10916     * the config object in order for the function to have any effect.
10917     * Usage:
10918 <pre><code>
10919 // slide the element horizontally to x position 200 while changing the height and opacity
10920 el.shift({ x: 200, height: 50, opacity: .8 });
10921
10922 // common config options shown with default values.
10923 el.shift({
10924     width: [element's width],
10925     height: [element's height],
10926     x: [element's x position],
10927     y: [element's y position],
10928     opacity: [element's opacity],
10929     easing: 'easeOut',
10930     duration: .35
10931 });
10932 </code></pre>
10933     * @param {Object} options  Object literal with any of the Fx config options
10934     * @return {Roo.Element} The Element
10935     */
10936     shift : function(o){
10937         var el = this.getFxEl();
10938         o = o || {};
10939         el.queueFx(o, function(){
10940             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10941             if(w !== undefined){
10942                 a.width = {to: this.adjustWidth(w)};
10943             }
10944             if(h !== undefined){
10945                 a.height = {to: this.adjustHeight(h)};
10946             }
10947             if(x !== undefined || y !== undefined){
10948                 a.points = {to: [
10949                     x !== undefined ? x : this.getX(),
10950                     y !== undefined ? y : this.getY()
10951                 ]};
10952             }
10953             if(op !== undefined){
10954                 a.opacity = {to: op};
10955             }
10956             if(o.xy !== undefined){
10957                 a.points = {to: o.xy};
10958             }
10959             arguments.callee.anim = this.fxanim(a,
10960                 o, 'motion', .35, "easeOut", function(){
10961                 el.afterFx(o);
10962             });
10963         });
10964         return this;
10965     },
10966
10967         /**
10968          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10969          * ending point of the effect.
10970          * Usage:
10971          *<pre><code>
10972 // default: slide the element downward while fading out
10973 el.ghost();
10974
10975 // custom: slide the element out to the right with a 2-second duration
10976 el.ghost('r', { duration: 2 });
10977
10978 // common config options shown with default values
10979 el.ghost('b', {
10980     easing: 'easeOut',
10981     duration: .5
10982     remove: false,
10983     useDisplay: false
10984 });
10985 </code></pre>
10986          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10987          * @param {Object} options (optional) Object literal with any of the Fx config options
10988          * @return {Roo.Element} The Element
10989          */
10990     ghost : function(anchor, o){
10991         var el = this.getFxEl();
10992         o = o || {};
10993
10994         el.queueFx(o, function(){
10995             anchor = anchor || "b";
10996
10997             // restore values after effect
10998             var r = this.getFxRestore();
10999             var w = this.getWidth(),
11000                 h = this.getHeight();
11001
11002             var st = this.dom.style;
11003
11004             var after = function(){
11005                 if(o.useDisplay){
11006                     el.setDisplayed(false);
11007                 }else{
11008                     el.hide();
11009                 }
11010
11011                 el.clearOpacity();
11012                 el.setPositioning(r.pos);
11013                 st.width = r.width;
11014                 st.height = r.height;
11015
11016                 el.afterFx(o);
11017             };
11018
11019             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11020             switch(anchor.toLowerCase()){
11021                 case "t":
11022                     pt.by = [0, -h];
11023                 break;
11024                 case "l":
11025                     pt.by = [-w, 0];
11026                 break;
11027                 case "r":
11028                     pt.by = [w, 0];
11029                 break;
11030                 case "b":
11031                     pt.by = [0, h];
11032                 break;
11033                 case "tl":
11034                     pt.by = [-w, -h];
11035                 break;
11036                 case "bl":
11037                     pt.by = [-w, h];
11038                 break;
11039                 case "br":
11040                     pt.by = [w, h];
11041                 break;
11042                 case "tr":
11043                     pt.by = [w, -h];
11044                 break;
11045             }
11046
11047             arguments.callee.anim = this.fxanim(a,
11048                 o,
11049                 'motion',
11050                 .5,
11051                 "easeOut", after);
11052         });
11053         return this;
11054     },
11055
11056         /**
11057          * Ensures that all effects queued after syncFx is called on the element are
11058          * run concurrently.  This is the opposite of {@link #sequenceFx}.
11059          * @return {Roo.Element} The Element
11060          */
11061     syncFx : function(){
11062         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11063             block : false,
11064             concurrent : true,
11065             stopFx : false
11066         });
11067         return this;
11068     },
11069
11070         /**
11071          * Ensures that all effects queued after sequenceFx is called on the element are
11072          * run in sequence.  This is the opposite of {@link #syncFx}.
11073          * @return {Roo.Element} The Element
11074          */
11075     sequenceFx : function(){
11076         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11077             block : false,
11078             concurrent : false,
11079             stopFx : false
11080         });
11081         return this;
11082     },
11083
11084         /* @private */
11085     nextFx : function(){
11086         var ef = this.fxQueue[0];
11087         if(ef){
11088             ef.call(this);
11089         }
11090     },
11091
11092         /**
11093          * Returns true if the element has any effects actively running or queued, else returns false.
11094          * @return {Boolean} True if element has active effects, else false
11095          */
11096     hasActiveFx : function(){
11097         return this.fxQueue && this.fxQueue[0];
11098     },
11099
11100         /**
11101          * Stops any running effects and clears the element's internal effects queue if it contains
11102          * any additional effects that haven't started yet.
11103          * @return {Roo.Element} The Element
11104          */
11105     stopFx : function(){
11106         if(this.hasActiveFx()){
11107             var cur = this.fxQueue[0];
11108             if(cur && cur.anim && cur.anim.isAnimated()){
11109                 this.fxQueue = [cur]; // clear out others
11110                 cur.anim.stop(true);
11111             }
11112         }
11113         return this;
11114     },
11115
11116         /* @private */
11117     beforeFx : function(o){
11118         if(this.hasActiveFx() && !o.concurrent){
11119            if(o.stopFx){
11120                this.stopFx();
11121                return true;
11122            }
11123            return false;
11124         }
11125         return true;
11126     },
11127
11128         /**
11129          * Returns true if the element is currently blocking so that no other effect can be queued
11130          * until this effect is finished, else returns false if blocking is not set.  This is commonly
11131          * used to ensure that an effect initiated by a user action runs to completion prior to the
11132          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11133          * @return {Boolean} True if blocking, else false
11134          */
11135     hasFxBlock : function(){
11136         var q = this.fxQueue;
11137         return q && q[0] && q[0].block;
11138     },
11139
11140         /* @private */
11141     queueFx : function(o, fn){
11142         if(!this.fxQueue){
11143             this.fxQueue = [];
11144         }
11145         if(!this.hasFxBlock()){
11146             Roo.applyIf(o, this.fxDefaults);
11147             if(!o.concurrent){
11148                 var run = this.beforeFx(o);
11149                 fn.block = o.block;
11150                 this.fxQueue.push(fn);
11151                 if(run){
11152                     this.nextFx();
11153                 }
11154             }else{
11155                 fn.call(this);
11156             }
11157         }
11158         return this;
11159     },
11160
11161         /* @private */
11162     fxWrap : function(pos, o, vis){
11163         var wrap;
11164         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11165             var wrapXY;
11166             if(o.fixPosition){
11167                 wrapXY = this.getXY();
11168             }
11169             var div = document.createElement("div");
11170             div.style.visibility = vis;
11171             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11172             wrap.setPositioning(pos);
11173             if(wrap.getStyle("position") == "static"){
11174                 wrap.position("relative");
11175             }
11176             this.clearPositioning('auto');
11177             wrap.clip();
11178             wrap.dom.appendChild(this.dom);
11179             if(wrapXY){
11180                 wrap.setXY(wrapXY);
11181             }
11182         }
11183         return wrap;
11184     },
11185
11186         /* @private */
11187     fxUnwrap : function(wrap, pos, o){
11188         this.clearPositioning();
11189         this.setPositioning(pos);
11190         if(!o.wrap){
11191             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11192             wrap.remove();
11193         }
11194     },
11195
11196         /* @private */
11197     getFxRestore : function(){
11198         var st = this.dom.style;
11199         return {pos: this.getPositioning(), width: st.width, height : st.height};
11200     },
11201
11202         /* @private */
11203     afterFx : function(o){
11204         if(o.afterStyle){
11205             this.applyStyles(o.afterStyle);
11206         }
11207         if(o.afterCls){
11208             this.addClass(o.afterCls);
11209         }
11210         if(o.remove === true){
11211             this.remove();
11212         }
11213         Roo.callback(o.callback, o.scope, [this]);
11214         if(!o.concurrent){
11215             this.fxQueue.shift();
11216             this.nextFx();
11217         }
11218     },
11219
11220         /* @private */
11221     getFxEl : function(){ // support for composite element fx
11222         return Roo.get(this.dom);
11223     },
11224
11225         /* @private */
11226     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11227         animType = animType || 'run';
11228         opt = opt || {};
11229         var anim = Roo.lib.Anim[animType](
11230             this.dom, args,
11231             (opt.duration || defaultDur) || .35,
11232             (opt.easing || defaultEase) || 'easeOut',
11233             function(){
11234                 Roo.callback(cb, this);
11235             },
11236             this
11237         );
11238         opt.anim = anim;
11239         return anim;
11240     }
11241 };
11242
11243 // backwords compat
11244 Roo.Fx.resize = Roo.Fx.scale;
11245
11246 //When included, Roo.Fx is automatically applied to Element so that all basic
11247 //effects are available directly via the Element API
11248 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11249  * Based on:
11250  * Ext JS Library 1.1.1
11251  * Copyright(c) 2006-2007, Ext JS, LLC.
11252  *
11253  * Originally Released Under LGPL - original licence link has changed is not relivant.
11254  *
11255  * Fork - LGPL
11256  * <script type="text/javascript">
11257  */
11258
11259
11260 /**
11261  * @class Roo.CompositeElement
11262  * Standard composite class. Creates a Roo.Element for every element in the collection.
11263  * <br><br>
11264  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11265  * actions will be performed on all the elements in this collection.</b>
11266  * <br><br>
11267  * All methods return <i>this</i> and can be chained.
11268  <pre><code>
11269  var els = Roo.select("#some-el div.some-class", true);
11270  // or select directly from an existing element
11271  var el = Roo.get('some-el');
11272  el.select('div.some-class', true);
11273
11274  els.setWidth(100); // all elements become 100 width
11275  els.hide(true); // all elements fade out and hide
11276  // or
11277  els.setWidth(100).hide(true);
11278  </code></pre>
11279  */
11280 Roo.CompositeElement = function(els){
11281     this.elements = [];
11282     this.addElements(els);
11283 };
11284 Roo.CompositeElement.prototype = {
11285     isComposite: true,
11286     addElements : function(els){
11287         if(!els) {
11288             return this;
11289         }
11290         if(typeof els == "string"){
11291             els = Roo.Element.selectorFunction(els);
11292         }
11293         var yels = this.elements;
11294         var index = yels.length-1;
11295         for(var i = 0, len = els.length; i < len; i++) {
11296                 yels[++index] = Roo.get(els[i]);
11297         }
11298         return this;
11299     },
11300
11301     /**
11302     * Clears this composite and adds the elements returned by the passed selector.
11303     * @param {String/Array} els A string CSS selector, an array of elements or an element
11304     * @return {CompositeElement} this
11305     */
11306     fill : function(els){
11307         this.elements = [];
11308         this.add(els);
11309         return this;
11310     },
11311
11312     /**
11313     * Filters this composite to only elements that match the passed selector.
11314     * @param {String} selector A string CSS selector
11315     * @param {Boolean} inverse return inverse filter (not matches)
11316     * @return {CompositeElement} this
11317     */
11318     filter : function(selector, inverse){
11319         var els = [];
11320         inverse = inverse || false;
11321         this.each(function(el){
11322             var match = inverse ? !el.is(selector) : el.is(selector);
11323             if(match){
11324                 els[els.length] = el.dom;
11325             }
11326         });
11327         this.fill(els);
11328         return this;
11329     },
11330
11331     invoke : function(fn, args){
11332         var els = this.elements;
11333         for(var i = 0, len = els.length; i < len; i++) {
11334                 Roo.Element.prototype[fn].apply(els[i], args);
11335         }
11336         return this;
11337     },
11338     /**
11339     * Adds elements to this composite.
11340     * @param {String/Array} els A string CSS selector, an array of elements or an element
11341     * @return {CompositeElement} this
11342     */
11343     add : function(els){
11344         if(typeof els == "string"){
11345             this.addElements(Roo.Element.selectorFunction(els));
11346         }else if(els.length !== undefined){
11347             this.addElements(els);
11348         }else{
11349             this.addElements([els]);
11350         }
11351         return this;
11352     },
11353     /**
11354     * Calls the passed function passing (el, this, index) for each element in this composite.
11355     * @param {Function} fn The function to call
11356     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11357     * @return {CompositeElement} this
11358     */
11359     each : function(fn, scope){
11360         var els = this.elements;
11361         for(var i = 0, len = els.length; i < len; i++){
11362             if(fn.call(scope || els[i], els[i], this, i) === false) {
11363                 break;
11364             }
11365         }
11366         return this;
11367     },
11368
11369     /**
11370      * Returns the Element object at the specified index
11371      * @param {Number} index
11372      * @return {Roo.Element}
11373      */
11374     item : function(index){
11375         return this.elements[index] || null;
11376     },
11377
11378     /**
11379      * Returns the first Element
11380      * @return {Roo.Element}
11381      */
11382     first : function(){
11383         return this.item(0);
11384     },
11385
11386     /**
11387      * Returns the last Element
11388      * @return {Roo.Element}
11389      */
11390     last : function(){
11391         return this.item(this.elements.length-1);
11392     },
11393
11394     /**
11395      * Returns the number of elements in this composite
11396      * @return Number
11397      */
11398     getCount : function(){
11399         return this.elements.length;
11400     },
11401
11402     /**
11403      * Returns true if this composite contains the passed element
11404      * @return Boolean
11405      */
11406     contains : function(el){
11407         return this.indexOf(el) !== -1;
11408     },
11409
11410     /**
11411      * Returns true if this composite contains the passed element
11412      * @return Boolean
11413      */
11414     indexOf : function(el){
11415         return this.elements.indexOf(Roo.get(el));
11416     },
11417
11418
11419     /**
11420     * Removes the specified element(s).
11421     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11422     * or an array of any of those.
11423     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11424     * @return {CompositeElement} this
11425     */
11426     removeElement : function(el, removeDom){
11427         if(el instanceof Array){
11428             for(var i = 0, len = el.length; i < len; i++){
11429                 this.removeElement(el[i]);
11430             }
11431             return this;
11432         }
11433         var index = typeof el == 'number' ? el : this.indexOf(el);
11434         if(index !== -1){
11435             if(removeDom){
11436                 var d = this.elements[index];
11437                 if(d.dom){
11438                     d.remove();
11439                 }else{
11440                     d.parentNode.removeChild(d);
11441                 }
11442             }
11443             this.elements.splice(index, 1);
11444         }
11445         return this;
11446     },
11447
11448     /**
11449     * Replaces the specified element with the passed element.
11450     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11451     * to replace.
11452     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11453     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11454     * @return {CompositeElement} this
11455     */
11456     replaceElement : function(el, replacement, domReplace){
11457         var index = typeof el == 'number' ? el : this.indexOf(el);
11458         if(index !== -1){
11459             if(domReplace){
11460                 this.elements[index].replaceWith(replacement);
11461             }else{
11462                 this.elements.splice(index, 1, Roo.get(replacement))
11463             }
11464         }
11465         return this;
11466     },
11467
11468     /**
11469      * Removes all elements.
11470      */
11471     clear : function(){
11472         this.elements = [];
11473     }
11474 };
11475 (function(){
11476     Roo.CompositeElement.createCall = function(proto, fnName){
11477         if(!proto[fnName]){
11478             proto[fnName] = function(){
11479                 return this.invoke(fnName, arguments);
11480             };
11481         }
11482     };
11483     for(var fnName in Roo.Element.prototype){
11484         if(typeof Roo.Element.prototype[fnName] == "function"){
11485             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11486         }
11487     };
11488 })();
11489 /*
11490  * Based on:
11491  * Ext JS Library 1.1.1
11492  * Copyright(c) 2006-2007, Ext JS, LLC.
11493  *
11494  * Originally Released Under LGPL - original licence link has changed is not relivant.
11495  *
11496  * Fork - LGPL
11497  * <script type="text/javascript">
11498  */
11499
11500 /**
11501  * @class Roo.CompositeElementLite
11502  * @extends Roo.CompositeElement
11503  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11504  <pre><code>
11505  var els = Roo.select("#some-el div.some-class");
11506  // or select directly from an existing element
11507  var el = Roo.get('some-el');
11508  el.select('div.some-class');
11509
11510  els.setWidth(100); // all elements become 100 width
11511  els.hide(true); // all elements fade out and hide
11512  // or
11513  els.setWidth(100).hide(true);
11514  </code></pre><br><br>
11515  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11516  * actions will be performed on all the elements in this collection.</b>
11517  */
11518 Roo.CompositeElementLite = function(els){
11519     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11520     this.el = new Roo.Element.Flyweight();
11521 };
11522 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11523     addElements : function(els){
11524         if(els){
11525             if(els instanceof Array){
11526                 this.elements = this.elements.concat(els);
11527             }else{
11528                 var yels = this.elements;
11529                 var index = yels.length-1;
11530                 for(var i = 0, len = els.length; i < len; i++) {
11531                     yels[++index] = els[i];
11532                 }
11533             }
11534         }
11535         return this;
11536     },
11537     invoke : function(fn, args){
11538         var els = this.elements;
11539         var el = this.el;
11540         for(var i = 0, len = els.length; i < len; i++) {
11541             el.dom = els[i];
11542                 Roo.Element.prototype[fn].apply(el, args);
11543         }
11544         return this;
11545     },
11546     /**
11547      * Returns a flyweight Element of the dom element object at the specified index
11548      * @param {Number} index
11549      * @return {Roo.Element}
11550      */
11551     item : function(index){
11552         if(!this.elements[index]){
11553             return null;
11554         }
11555         this.el.dom = this.elements[index];
11556         return this.el;
11557     },
11558
11559     // fixes scope with flyweight
11560     addListener : function(eventName, handler, scope, opt){
11561         var els = this.elements;
11562         for(var i = 0, len = els.length; i < len; i++) {
11563             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11564         }
11565         return this;
11566     },
11567
11568     /**
11569     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11570     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11571     * a reference to the dom node, use el.dom.</b>
11572     * @param {Function} fn The function to call
11573     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11574     * @return {CompositeElement} this
11575     */
11576     each : function(fn, scope){
11577         var els = this.elements;
11578         var el = this.el;
11579         for(var i = 0, len = els.length; i < len; i++){
11580             el.dom = els[i];
11581                 if(fn.call(scope || el, el, this, i) === false){
11582                 break;
11583             }
11584         }
11585         return this;
11586     },
11587
11588     indexOf : function(el){
11589         return this.elements.indexOf(Roo.getDom(el));
11590     },
11591
11592     replaceElement : function(el, replacement, domReplace){
11593         var index = typeof el == 'number' ? el : this.indexOf(el);
11594         if(index !== -1){
11595             replacement = Roo.getDom(replacement);
11596             if(domReplace){
11597                 var d = this.elements[index];
11598                 d.parentNode.insertBefore(replacement, d);
11599                 d.parentNode.removeChild(d);
11600             }
11601             this.elements.splice(index, 1, replacement);
11602         }
11603         return this;
11604     }
11605 });
11606 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11607
11608 /*
11609  * Based on:
11610  * Ext JS Library 1.1.1
11611  * Copyright(c) 2006-2007, Ext JS, LLC.
11612  *
11613  * Originally Released Under LGPL - original licence link has changed is not relivant.
11614  *
11615  * Fork - LGPL
11616  * <script type="text/javascript">
11617  */
11618
11619  
11620
11621 /**
11622  * @class Roo.data.Connection
11623  * @extends Roo.util.Observable
11624  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11625  * either to a configured URL, or to a URL specified at request time. 
11626  * 
11627  * Requests made by this class are asynchronous, and will return immediately. No data from
11628  * the server will be available to the statement immediately following the {@link #request} call.
11629  * To process returned data, use a callback in the request options object, or an event listener.
11630  * 
11631  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11632  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11633  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11634  * property and, if present, the IFRAME's XML document as the responseXML property.
11635  * 
11636  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11637  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11638  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11639  * standard DOM methods.
11640  * @constructor
11641  * @param {Object} config a configuration object.
11642  */
11643 Roo.data.Connection = function(config){
11644     Roo.apply(this, config);
11645     this.addEvents({
11646         /**
11647          * @event beforerequest
11648          * Fires before a network request is made to retrieve a data object.
11649          * @param {Connection} conn This Connection object.
11650          * @param {Object} options The options config object passed to the {@link #request} method.
11651          */
11652         "beforerequest" : true,
11653         /**
11654          * @event requestcomplete
11655          * Fires if the request was successfully completed.
11656          * @param {Connection} conn This Connection object.
11657          * @param {Object} response The XHR object containing the response data.
11658          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11659          * @param {Object} options The options config object passed to the {@link #request} method.
11660          */
11661         "requestcomplete" : true,
11662         /**
11663          * @event requestexception
11664          * Fires if an error HTTP status was returned from the server.
11665          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11666          * @param {Connection} conn This Connection object.
11667          * @param {Object} response The XHR object containing the response data.
11668          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11669          * @param {Object} options The options config object passed to the {@link #request} method.
11670          */
11671         "requestexception" : true
11672     });
11673     Roo.data.Connection.superclass.constructor.call(this);
11674 };
11675
11676 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11677     /**
11678      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11679      */
11680     /**
11681      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11682      * extra parameters to each request made by this object. (defaults to undefined)
11683      */
11684     /**
11685      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11686      *  to each request made by this object. (defaults to undefined)
11687      */
11688     /**
11689      * @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)
11690      */
11691     /**
11692      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11693      */
11694     timeout : 30000,
11695     /**
11696      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11697      * @type Boolean
11698      */
11699     autoAbort:false,
11700
11701     /**
11702      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11703      * @type Boolean
11704      */
11705     disableCaching: true,
11706
11707     /**
11708      * Sends an HTTP request to a remote server.
11709      * @param {Object} options An object which may contain the following properties:<ul>
11710      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11711      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11712      * request, a url encoded string or a function to call to get either.</li>
11713      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11714      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11715      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11716      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11717      * <li>options {Object} The parameter to the request call.</li>
11718      * <li>success {Boolean} True if the request succeeded.</li>
11719      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11720      * </ul></li>
11721      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11722      * The callback is passed the following parameters:<ul>
11723      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11724      * <li>options {Object} The parameter to the request call.</li>
11725      * </ul></li>
11726      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11727      * The callback is passed the following parameters:<ul>
11728      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11729      * <li>options {Object} The parameter to the request call.</li>
11730      * </ul></li>
11731      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11732      * for the callback function. Defaults to the browser window.</li>
11733      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11734      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11735      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11736      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11737      * params for the post data. Any params will be appended to the URL.</li>
11738      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11739      * </ul>
11740      * @return {Number} transactionId
11741      */
11742     request : function(o){
11743         if(this.fireEvent("beforerequest", this, o) !== false){
11744             var p = o.params;
11745
11746             if(typeof p == "function"){
11747                 p = p.call(o.scope||window, o);
11748             }
11749             if(typeof p == "object"){
11750                 p = Roo.urlEncode(o.params);
11751             }
11752             if(this.extraParams){
11753                 var extras = Roo.urlEncode(this.extraParams);
11754                 p = p ? (p + '&' + extras) : extras;
11755             }
11756
11757             var url = o.url || this.url;
11758             if(typeof url == 'function'){
11759                 url = url.call(o.scope||window, o);
11760             }
11761
11762             if(o.form){
11763                 var form = Roo.getDom(o.form);
11764                 url = url || form.action;
11765
11766                 var enctype = form.getAttribute("enctype");
11767                 
11768                 if (o.formData) {
11769                     return this.doFormDataUpload(o, url);
11770                 }
11771                 
11772                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11773                     return this.doFormUpload(o, p, url);
11774                 }
11775                 var f = Roo.lib.Ajax.serializeForm(form);
11776                 p = p ? (p + '&' + f) : f;
11777             }
11778             
11779             if (!o.form && o.formData) {
11780                 o.formData = o.formData === true ? new FormData() : o.formData;
11781                 for (var k in o.params) {
11782                     o.formData.append(k,o.params[k]);
11783                 }
11784                     
11785                 return this.doFormDataUpload(o, url);
11786             }
11787             
11788
11789             var hs = o.headers;
11790             if(this.defaultHeaders){
11791                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11792                 if(!o.headers){
11793                     o.headers = hs;
11794                 }
11795             }
11796
11797             var cb = {
11798                 success: this.handleResponse,
11799                 failure: this.handleFailure,
11800                 scope: this,
11801                 argument: {options: o},
11802                 timeout : o.timeout || this.timeout
11803             };
11804
11805             var method = o.method||this.method||(p ? "POST" : "GET");
11806
11807             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11808                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11809             }
11810
11811             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11812                 if(o.autoAbort){
11813                     this.abort();
11814                 }
11815             }else if(this.autoAbort !== false){
11816                 this.abort();
11817             }
11818
11819             if((method == 'GET' && p) || o.xmlData){
11820                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11821                 p = '';
11822             }
11823             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11824             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11825             Roo.lib.Ajax.useDefaultHeader == true;
11826             return this.transId;
11827         }else{
11828             Roo.callback(o.callback, o.scope, [o, null, null]);
11829             return null;
11830         }
11831     },
11832
11833     /**
11834      * Determine whether this object has a request outstanding.
11835      * @param {Number} transactionId (Optional) defaults to the last transaction
11836      * @return {Boolean} True if there is an outstanding request.
11837      */
11838     isLoading : function(transId){
11839         if(transId){
11840             return Roo.lib.Ajax.isCallInProgress(transId);
11841         }else{
11842             return this.transId ? true : false;
11843         }
11844     },
11845
11846     /**
11847      * Aborts any outstanding request.
11848      * @param {Number} transactionId (Optional) defaults to the last transaction
11849      */
11850     abort : function(transId){
11851         if(transId || this.isLoading()){
11852             Roo.lib.Ajax.abort(transId || this.transId);
11853         }
11854     },
11855
11856     // private
11857     handleResponse : function(response){
11858         this.transId = false;
11859         var options = response.argument.options;
11860         response.argument = options ? options.argument : null;
11861         this.fireEvent("requestcomplete", this, response, options);
11862         Roo.callback(options.success, options.scope, [response, options]);
11863         Roo.callback(options.callback, options.scope, [options, true, response]);
11864     },
11865
11866     // private
11867     handleFailure : function(response, e){
11868         this.transId = false;
11869         var options = response.argument.options;
11870         response.argument = options ? options.argument : null;
11871         this.fireEvent("requestexception", this, response, options, e);
11872         Roo.callback(options.failure, options.scope, [response, options]);
11873         Roo.callback(options.callback, options.scope, [options, false, response]);
11874     },
11875
11876     // private
11877     doFormUpload : function(o, ps, url){
11878         var id = Roo.id();
11879         var frame = document.createElement('iframe');
11880         frame.id = id;
11881         frame.name = id;
11882         frame.className = 'x-hidden';
11883         if(Roo.isIE){
11884             frame.src = Roo.SSL_SECURE_URL;
11885         }
11886         document.body.appendChild(frame);
11887
11888         if(Roo.isIE){
11889            document.frames[id].name = id;
11890         }
11891
11892         var form = Roo.getDom(o.form);
11893         form.target = id;
11894         form.method = 'POST';
11895         form.enctype = form.encoding = 'multipart/form-data';
11896         if(url){
11897             form.action = url;
11898         }
11899
11900         var hiddens, hd;
11901         if(ps){ // add dynamic params
11902             hiddens = [];
11903             ps = Roo.urlDecode(ps, false);
11904             for(var k in ps){
11905                 if(ps.hasOwnProperty(k)){
11906                     hd = document.createElement('input');
11907                     hd.type = 'hidden';
11908                     hd.name = k;
11909                     hd.value = ps[k];
11910                     form.appendChild(hd);
11911                     hiddens.push(hd);
11912                 }
11913             }
11914         }
11915
11916         function cb(){
11917             var r = {  // bogus response object
11918                 responseText : '',
11919                 responseXML : null
11920             };
11921
11922             r.argument = o ? o.argument : null;
11923
11924             try { //
11925                 var doc;
11926                 if(Roo.isIE){
11927                     doc = frame.contentWindow.document;
11928                 }else {
11929                     doc = (frame.contentDocument || window.frames[id].document);
11930                 }
11931                 if(doc && doc.body){
11932                     r.responseText = doc.body.innerHTML;
11933                 }
11934                 if(doc && doc.XMLDocument){
11935                     r.responseXML = doc.XMLDocument;
11936                 }else {
11937                     r.responseXML = doc;
11938                 }
11939             }
11940             catch(e) {
11941                 // ignore
11942             }
11943
11944             Roo.EventManager.removeListener(frame, 'load', cb, this);
11945
11946             this.fireEvent("requestcomplete", this, r, o);
11947             Roo.callback(o.success, o.scope, [r, o]);
11948             Roo.callback(o.callback, o.scope, [o, true, r]);
11949
11950             setTimeout(function(){document.body.removeChild(frame);}, 100);
11951         }
11952
11953         Roo.EventManager.on(frame, 'load', cb, this);
11954         form.submit();
11955
11956         if(hiddens){ // remove dynamic params
11957             for(var i = 0, len = hiddens.length; i < len; i++){
11958                 form.removeChild(hiddens[i]);
11959             }
11960         }
11961     },
11962     // this is a 'formdata version???'
11963     
11964     
11965     doFormDataUpload : function(o,  url)
11966     {
11967         var formData;
11968         if (o.form) {
11969             var form =  Roo.getDom(o.form);
11970             form.enctype = form.encoding = 'multipart/form-data';
11971             formData = o.formData === true ? new FormData(form) : o.formData;
11972         } else {
11973             formData = o.formData === true ? new FormData() : o.formData;
11974         }
11975         
11976       
11977         var cb = {
11978             success: this.handleResponse,
11979             failure: this.handleFailure,
11980             scope: this,
11981             argument: {options: o},
11982             timeout : o.timeout || this.timeout
11983         };
11984  
11985         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11986             if(o.autoAbort){
11987                 this.abort();
11988             }
11989         }else if(this.autoAbort !== false){
11990             this.abort();
11991         }
11992
11993         //Roo.lib.Ajax.defaultPostHeader = null;
11994         Roo.lib.Ajax.useDefaultHeader = false;
11995         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
11996         Roo.lib.Ajax.useDefaultHeader = true;
11997  
11998          
11999     }
12000     
12001 });
12002 /*
12003  * Based on:
12004  * Ext JS Library 1.1.1
12005  * Copyright(c) 2006-2007, Ext JS, LLC.
12006  *
12007  * Originally Released Under LGPL - original licence link has changed is not relivant.
12008  *
12009  * Fork - LGPL
12010  * <script type="text/javascript">
12011  */
12012  
12013 /**
12014  * Global Ajax request class.
12015  * 
12016  * @class Roo.Ajax
12017  * @extends Roo.data.Connection
12018  * @static
12019  * 
12020  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
12021  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12022  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
12023  * @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)
12024  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12025  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12026  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
12027  */
12028 Roo.Ajax = new Roo.data.Connection({
12029     // fix up the docs
12030     /**
12031      * @scope Roo.Ajax
12032      * @type {Boolear} 
12033      */
12034     autoAbort : false,
12035
12036     /**
12037      * Serialize the passed form into a url encoded string
12038      * @scope Roo.Ajax
12039      * @param {String/HTMLElement} form
12040      * @return {String}
12041      */
12042     serializeForm : function(form){
12043         return Roo.lib.Ajax.serializeForm(form);
12044     }
12045 });/*
12046  * Based on:
12047  * Ext JS Library 1.1.1
12048  * Copyright(c) 2006-2007, Ext JS, LLC.
12049  *
12050  * Originally Released Under LGPL - original licence link has changed is not relivant.
12051  *
12052  * Fork - LGPL
12053  * <script type="text/javascript">
12054  */
12055
12056  
12057 /**
12058  * @class Roo.UpdateManager
12059  * @extends Roo.util.Observable
12060  * Provides AJAX-style update for Element object.<br><br>
12061  * Usage:<br>
12062  * <pre><code>
12063  * // Get it from a Roo.Element object
12064  * var el = Roo.get("foo");
12065  * var mgr = el.getUpdateManager();
12066  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
12067  * ...
12068  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12069  * <br>
12070  * // or directly (returns the same UpdateManager instance)
12071  * var mgr = new Roo.UpdateManager("myElementId");
12072  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12073  * mgr.on("update", myFcnNeedsToKnow);
12074  * <br>
12075    // short handed call directly from the element object
12076    Roo.get("foo").load({
12077         url: "bar.php",
12078         scripts:true,
12079         params: "for=bar",
12080         text: "Loading Foo..."
12081    });
12082  * </code></pre>
12083  * @constructor
12084  * Create new UpdateManager directly.
12085  * @param {String/HTMLElement/Roo.Element} el The element to update
12086  * @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).
12087  */
12088 Roo.UpdateManager = function(el, forceNew){
12089     el = Roo.get(el);
12090     if(!forceNew && el.updateManager){
12091         return el.updateManager;
12092     }
12093     /**
12094      * The Element object
12095      * @type Roo.Element
12096      */
12097     this.el = el;
12098     /**
12099      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12100      * @type String
12101      */
12102     this.defaultUrl = null;
12103
12104     this.addEvents({
12105         /**
12106          * @event beforeupdate
12107          * Fired before an update is made, return false from your handler and the update is cancelled.
12108          * @param {Roo.Element} el
12109          * @param {String/Object/Function} url
12110          * @param {String/Object} params
12111          */
12112         "beforeupdate": true,
12113         /**
12114          * @event update
12115          * Fired after successful update is made.
12116          * @param {Roo.Element} el
12117          * @param {Object} oResponseObject The response Object
12118          */
12119         "update": true,
12120         /**
12121          * @event failure
12122          * Fired on update failure.
12123          * @param {Roo.Element} el
12124          * @param {Object} oResponseObject The response Object
12125          */
12126         "failure": true
12127     });
12128     var d = Roo.UpdateManager.defaults;
12129     /**
12130      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12131      * @type String
12132      */
12133     this.sslBlankUrl = d.sslBlankUrl;
12134     /**
12135      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12136      * @type Boolean
12137      */
12138     this.disableCaching = d.disableCaching;
12139     /**
12140      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12141      * @type String
12142      */
12143     this.indicatorText = d.indicatorText;
12144     /**
12145      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12146      * @type String
12147      */
12148     this.showLoadIndicator = d.showLoadIndicator;
12149     /**
12150      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12151      * @type Number
12152      */
12153     this.timeout = d.timeout;
12154
12155     /**
12156      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12157      * @type Boolean
12158      */
12159     this.loadScripts = d.loadScripts;
12160
12161     /**
12162      * Transaction object of current executing transaction
12163      */
12164     this.transaction = null;
12165
12166     /**
12167      * @private
12168      */
12169     this.autoRefreshProcId = null;
12170     /**
12171      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12172      * @type Function
12173      */
12174     this.refreshDelegate = this.refresh.createDelegate(this);
12175     /**
12176      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12177      * @type Function
12178      */
12179     this.updateDelegate = this.update.createDelegate(this);
12180     /**
12181      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12182      * @type Function
12183      */
12184     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12185     /**
12186      * @private
12187      */
12188     this.successDelegate = this.processSuccess.createDelegate(this);
12189     /**
12190      * @private
12191      */
12192     this.failureDelegate = this.processFailure.createDelegate(this);
12193
12194     if(!this.renderer){
12195      /**
12196       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12197       */
12198     this.renderer = new Roo.UpdateManager.BasicRenderer();
12199     }
12200     
12201     Roo.UpdateManager.superclass.constructor.call(this);
12202 };
12203
12204 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12205     /**
12206      * Get the Element this UpdateManager is bound to
12207      * @return {Roo.Element} The element
12208      */
12209     getEl : function(){
12210         return this.el;
12211     },
12212     /**
12213      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12214      * @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:
12215 <pre><code>
12216 um.update({<br/>
12217     url: "your-url.php",<br/>
12218     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12219     callback: yourFunction,<br/>
12220     scope: yourObject, //(optional scope)  <br/>
12221     discardUrl: false, <br/>
12222     nocache: false,<br/>
12223     text: "Loading...",<br/>
12224     timeout: 30,<br/>
12225     scripts: false<br/>
12226 });
12227 </code></pre>
12228      * The only required property is url. The optional properties nocache, text and scripts
12229      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12230      * @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}
12231      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12232      * @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.
12233      */
12234     update : function(url, params, callback, discardUrl){
12235         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12236             var method = this.method,
12237                 cfg;
12238             if(typeof url == "object"){ // must be config object
12239                 cfg = url;
12240                 url = cfg.url;
12241                 params = params || cfg.params;
12242                 callback = callback || cfg.callback;
12243                 discardUrl = discardUrl || cfg.discardUrl;
12244                 if(callback && cfg.scope){
12245                     callback = callback.createDelegate(cfg.scope);
12246                 }
12247                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12248                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12249                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12250                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12251                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12252             }
12253             this.showLoading();
12254             if(!discardUrl){
12255                 this.defaultUrl = url;
12256             }
12257             if(typeof url == "function"){
12258                 url = url.call(this);
12259             }
12260
12261             method = method || (params ? "POST" : "GET");
12262             if(method == "GET"){
12263                 url = this.prepareUrl(url);
12264             }
12265
12266             var o = Roo.apply(cfg ||{}, {
12267                 url : url,
12268                 params: params,
12269                 success: this.successDelegate,
12270                 failure: this.failureDelegate,
12271                 callback: undefined,
12272                 timeout: (this.timeout*1000),
12273                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12274             });
12275             Roo.log("updated manager called with timeout of " + o.timeout);
12276             this.transaction = Roo.Ajax.request(o);
12277         }
12278     },
12279
12280     /**
12281      * 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.
12282      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12283      * @param {String/HTMLElement} form The form Id or form element
12284      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12285      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12286      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12287      */
12288     formUpdate : function(form, url, reset, callback){
12289         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12290             if(typeof url == "function"){
12291                 url = url.call(this);
12292             }
12293             form = Roo.getDom(form);
12294             this.transaction = Roo.Ajax.request({
12295                 form: form,
12296                 url:url,
12297                 success: this.successDelegate,
12298                 failure: this.failureDelegate,
12299                 timeout: (this.timeout*1000),
12300                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12301             });
12302             this.showLoading.defer(1, this);
12303         }
12304     },
12305
12306     /**
12307      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12308      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12309      */
12310     refresh : function(callback){
12311         if(this.defaultUrl == null){
12312             return;
12313         }
12314         this.update(this.defaultUrl, null, callback, true);
12315     },
12316
12317     /**
12318      * Set this element to auto refresh.
12319      * @param {Number} interval How often to update (in seconds).
12320      * @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)
12321      * @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}
12322      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12323      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12324      */
12325     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12326         if(refreshNow){
12327             this.update(url || this.defaultUrl, params, callback, true);
12328         }
12329         if(this.autoRefreshProcId){
12330             clearInterval(this.autoRefreshProcId);
12331         }
12332         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12333     },
12334
12335     /**
12336      * Stop auto refresh on this element.
12337      */
12338      stopAutoRefresh : function(){
12339         if(this.autoRefreshProcId){
12340             clearInterval(this.autoRefreshProcId);
12341             delete this.autoRefreshProcId;
12342         }
12343     },
12344
12345     isAutoRefreshing : function(){
12346        return this.autoRefreshProcId ? true : false;
12347     },
12348     /**
12349      * Called to update the element to "Loading" state. Override to perform custom action.
12350      */
12351     showLoading : function(){
12352         if(this.showLoadIndicator){
12353             this.el.update(this.indicatorText);
12354         }
12355     },
12356
12357     /**
12358      * Adds unique parameter to query string if disableCaching = true
12359      * @private
12360      */
12361     prepareUrl : function(url){
12362         if(this.disableCaching){
12363             var append = "_dc=" + (new Date().getTime());
12364             if(url.indexOf("?") !== -1){
12365                 url += "&" + append;
12366             }else{
12367                 url += "?" + append;
12368             }
12369         }
12370         return url;
12371     },
12372
12373     /**
12374      * @private
12375      */
12376     processSuccess : function(response){
12377         this.transaction = null;
12378         if(response.argument.form && response.argument.reset){
12379             try{ // put in try/catch since some older FF releases had problems with this
12380                 response.argument.form.reset();
12381             }catch(e){}
12382         }
12383         if(this.loadScripts){
12384             this.renderer.render(this.el, response, this,
12385                 this.updateComplete.createDelegate(this, [response]));
12386         }else{
12387             this.renderer.render(this.el, response, this);
12388             this.updateComplete(response);
12389         }
12390     },
12391
12392     updateComplete : function(response){
12393         this.fireEvent("update", this.el, response);
12394         if(typeof response.argument.callback == "function"){
12395             response.argument.callback(this.el, true, response);
12396         }
12397     },
12398
12399     /**
12400      * @private
12401      */
12402     processFailure : function(response){
12403         this.transaction = null;
12404         this.fireEvent("failure", this.el, response);
12405         if(typeof response.argument.callback == "function"){
12406             response.argument.callback(this.el, false, response);
12407         }
12408     },
12409
12410     /**
12411      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12412      * @param {Object} renderer The object implementing the render() method
12413      */
12414     setRenderer : function(renderer){
12415         this.renderer = renderer;
12416     },
12417
12418     getRenderer : function(){
12419        return this.renderer;
12420     },
12421
12422     /**
12423      * Set the defaultUrl used for updates
12424      * @param {String/Function} defaultUrl The url or a function to call to get the url
12425      */
12426     setDefaultUrl : function(defaultUrl){
12427         this.defaultUrl = defaultUrl;
12428     },
12429
12430     /**
12431      * Aborts the executing transaction
12432      */
12433     abort : function(){
12434         if(this.transaction){
12435             Roo.Ajax.abort(this.transaction);
12436         }
12437     },
12438
12439     /**
12440      * Returns true if an update is in progress
12441      * @return {Boolean}
12442      */
12443     isUpdating : function(){
12444         if(this.transaction){
12445             return Roo.Ajax.isLoading(this.transaction);
12446         }
12447         return false;
12448     }
12449 });
12450
12451 /**
12452  * @class Roo.UpdateManager.defaults
12453  * @static (not really - but it helps the doc tool)
12454  * The defaults collection enables customizing the default properties of UpdateManager
12455  */
12456    Roo.UpdateManager.defaults = {
12457        /**
12458          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12459          * @type Number
12460          */
12461          timeout : 30,
12462
12463          /**
12464          * True to process scripts by default (Defaults to false).
12465          * @type Boolean
12466          */
12467         loadScripts : false,
12468
12469         /**
12470         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12471         * @type String
12472         */
12473         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12474         /**
12475          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12476          * @type Boolean
12477          */
12478         disableCaching : false,
12479         /**
12480          * Whether to show indicatorText when loading (Defaults to true).
12481          * @type Boolean
12482          */
12483         showLoadIndicator : true,
12484         /**
12485          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12486          * @type String
12487          */
12488         indicatorText : '<div class="loading-indicator">Loading...</div>'
12489    };
12490
12491 /**
12492  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12493  *Usage:
12494  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12495  * @param {String/HTMLElement/Roo.Element} el The element to update
12496  * @param {String} url The url
12497  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12498  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12499  * @static
12500  * @deprecated
12501  * @member Roo.UpdateManager
12502  */
12503 Roo.UpdateManager.updateElement = function(el, url, params, options){
12504     var um = Roo.get(el, true).getUpdateManager();
12505     Roo.apply(um, options);
12506     um.update(url, params, options ? options.callback : null);
12507 };
12508 // alias for backwards compat
12509 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12510 /**
12511  * @class Roo.UpdateManager.BasicRenderer
12512  * Default Content renderer. Updates the elements innerHTML with the responseText.
12513  */
12514 Roo.UpdateManager.BasicRenderer = function(){};
12515
12516 Roo.UpdateManager.BasicRenderer.prototype = {
12517     /**
12518      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12519      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12520      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12521      * @param {Roo.Element} el The element being rendered
12522      * @param {Object} response The YUI Connect response object
12523      * @param {UpdateManager} updateManager The calling update manager
12524      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12525      */
12526      render : function(el, response, updateManager, callback){
12527         el.update(response.responseText, updateManager.loadScripts, callback);
12528     }
12529 };
12530 /*
12531  * Based on:
12532  * Roo JS
12533  * (c)) Alan Knowles
12534  * Licence : LGPL
12535  */
12536
12537
12538 /**
12539  * @class Roo.DomTemplate
12540  * @extends Roo.Template
12541  * An effort at a dom based template engine..
12542  *
12543  * Similar to XTemplate, except it uses dom parsing to create the template..
12544  *
12545  * Supported features:
12546  *
12547  *  Tags:
12548
12549 <pre><code>
12550       {a_variable} - output encoded.
12551       {a_variable.format:("Y-m-d")} - call a method on the variable
12552       {a_variable:raw} - unencoded output
12553       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12554       {a_variable:this.method_on_template(...)} - call a method on the template object.
12555  
12556 </code></pre>
12557  *  The tpl tag:
12558 <pre><code>
12559         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12560         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12561         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12562         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12563   
12564 </code></pre>
12565  *      
12566  */
12567 Roo.DomTemplate = function()
12568 {
12569      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12570      if (this.html) {
12571         this.compile();
12572      }
12573 };
12574
12575
12576 Roo.extend(Roo.DomTemplate, Roo.Template, {
12577     /**
12578      * id counter for sub templates.
12579      */
12580     id : 0,
12581     /**
12582      * flag to indicate if dom parser is inside a pre,
12583      * it will strip whitespace if not.
12584      */
12585     inPre : false,
12586     
12587     /**
12588      * The various sub templates
12589      */
12590     tpls : false,
12591     
12592     
12593     
12594     /**
12595      *
12596      * basic tag replacing syntax
12597      * WORD:WORD()
12598      *
12599      * // you can fake an object call by doing this
12600      *  x.t:(test,tesT) 
12601      * 
12602      */
12603     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12604     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12605     
12606     iterChild : function (node, method) {
12607         
12608         var oldPre = this.inPre;
12609         if (node.tagName == 'PRE') {
12610             this.inPre = true;
12611         }
12612         for( var i = 0; i < node.childNodes.length; i++) {
12613             method.call(this, node.childNodes[i]);
12614         }
12615         this.inPre = oldPre;
12616     },
12617     
12618     
12619     
12620     /**
12621      * compile the template
12622      *
12623      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12624      *
12625      */
12626     compile: function()
12627     {
12628         var s = this.html;
12629         
12630         // covert the html into DOM...
12631         var doc = false;
12632         var div =false;
12633         try {
12634             doc = document.implementation.createHTMLDocument("");
12635             doc.documentElement.innerHTML =   this.html  ;
12636             div = doc.documentElement;
12637         } catch (e) {
12638             // old IE... - nasty -- it causes all sorts of issues.. with
12639             // images getting pulled from server..
12640             div = document.createElement('div');
12641             div.innerHTML = this.html;
12642         }
12643         //doc.documentElement.innerHTML = htmlBody
12644          
12645         
12646         
12647         this.tpls = [];
12648         var _t = this;
12649         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12650         
12651         var tpls = this.tpls;
12652         
12653         // create a top level template from the snippet..
12654         
12655         //Roo.log(div.innerHTML);
12656         
12657         var tpl = {
12658             uid : 'master',
12659             id : this.id++,
12660             attr : false,
12661             value : false,
12662             body : div.innerHTML,
12663             
12664             forCall : false,
12665             execCall : false,
12666             dom : div,
12667             isTop : true
12668             
12669         };
12670         tpls.unshift(tpl);
12671         
12672         
12673         // compile them...
12674         this.tpls = [];
12675         Roo.each(tpls, function(tp){
12676             this.compileTpl(tp);
12677             this.tpls[tp.id] = tp;
12678         }, this);
12679         
12680         this.master = tpls[0];
12681         return this;
12682         
12683         
12684     },
12685     
12686     compileNode : function(node, istop) {
12687         // test for
12688         //Roo.log(node);
12689         
12690         
12691         // skip anything not a tag..
12692         if (node.nodeType != 1) {
12693             if (node.nodeType == 3 && !this.inPre) {
12694                 // reduce white space..
12695                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12696                 
12697             }
12698             return;
12699         }
12700         
12701         var tpl = {
12702             uid : false,
12703             id : false,
12704             attr : false,
12705             value : false,
12706             body : '',
12707             
12708             forCall : false,
12709             execCall : false,
12710             dom : false,
12711             isTop : istop
12712             
12713             
12714         };
12715         
12716         
12717         switch(true) {
12718             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12719             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12720             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12721             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12722             // no default..
12723         }
12724         
12725         
12726         if (!tpl.attr) {
12727             // just itterate children..
12728             this.iterChild(node,this.compileNode);
12729             return;
12730         }
12731         tpl.uid = this.id++;
12732         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12733         node.removeAttribute('roo-'+ tpl.attr);
12734         if (tpl.attr != 'name') {
12735             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12736             node.parentNode.replaceChild(placeholder,  node);
12737         } else {
12738             
12739             var placeholder =  document.createElement('span');
12740             placeholder.className = 'roo-tpl-' + tpl.value;
12741             node.parentNode.replaceChild(placeholder,  node);
12742         }
12743         
12744         // parent now sees '{domtplXXXX}
12745         this.iterChild(node,this.compileNode);
12746         
12747         // we should now have node body...
12748         var div = document.createElement('div');
12749         div.appendChild(node);
12750         tpl.dom = node;
12751         // this has the unfortunate side effect of converting tagged attributes
12752         // eg. href="{...}" into %7C...%7D
12753         // this has been fixed by searching for those combo's although it's a bit hacky..
12754         
12755         
12756         tpl.body = div.innerHTML;
12757         
12758         
12759          
12760         tpl.id = tpl.uid;
12761         switch(tpl.attr) {
12762             case 'for' :
12763                 switch (tpl.value) {
12764                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12765                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12766                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12767                 }
12768                 break;
12769             
12770             case 'exec':
12771                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12772                 break;
12773             
12774             case 'if':     
12775                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12776                 break;
12777             
12778             case 'name':
12779                 tpl.id  = tpl.value; // replace non characters???
12780                 break;
12781             
12782         }
12783         
12784         
12785         this.tpls.push(tpl);
12786         
12787         
12788         
12789     },
12790     
12791     
12792     
12793     
12794     /**
12795      * Compile a segment of the template into a 'sub-template'
12796      *
12797      * 
12798      * 
12799      *
12800      */
12801     compileTpl : function(tpl)
12802     {
12803         var fm = Roo.util.Format;
12804         var useF = this.disableFormats !== true;
12805         
12806         var sep = Roo.isGecko ? "+\n" : ",\n";
12807         
12808         var undef = function(str) {
12809             Roo.debug && Roo.log("Property not found :"  + str);
12810             return '';
12811         };
12812           
12813         //Roo.log(tpl.body);
12814         
12815         
12816         
12817         var fn = function(m, lbrace, name, format, args)
12818         {
12819             //Roo.log("ARGS");
12820             //Roo.log(arguments);
12821             args = args ? args.replace(/\\'/g,"'") : args;
12822             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12823             if (typeof(format) == 'undefined') {
12824                 format =  'htmlEncode'; 
12825             }
12826             if (format == 'raw' ) {
12827                 format = false;
12828             }
12829             
12830             if(name.substr(0, 6) == 'domtpl'){
12831                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12832             }
12833             
12834             // build an array of options to determine if value is undefined..
12835             
12836             // basically get 'xxxx.yyyy' then do
12837             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12838             //    (function () { Roo.log("Property not found"); return ''; })() :
12839             //    ......
12840             
12841             var udef_ar = [];
12842             var lookfor = '';
12843             Roo.each(name.split('.'), function(st) {
12844                 lookfor += (lookfor.length ? '.': '') + st;
12845                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12846             });
12847             
12848             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12849             
12850             
12851             if(format && useF){
12852                 
12853                 args = args ? ',' + args : "";
12854                  
12855                 if(format.substr(0, 5) != "this."){
12856                     format = "fm." + format + '(';
12857                 }else{
12858                     format = 'this.call("'+ format.substr(5) + '", ';
12859                     args = ", values";
12860                 }
12861                 
12862                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12863             }
12864              
12865             if (args && args.length) {
12866                 // called with xxyx.yuu:(test,test)
12867                 // change to ()
12868                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12869             }
12870             // raw.. - :raw modifier..
12871             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12872             
12873         };
12874         var body;
12875         // branched to use + in gecko and [].join() in others
12876         if(Roo.isGecko){
12877             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12878                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12879                     "';};};";
12880         }else{
12881             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12882             body.push(tpl.body.replace(/(\r\n|\n)/g,
12883                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12884             body.push("'].join('');};};");
12885             body = body.join('');
12886         }
12887         
12888         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12889        
12890         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12891         eval(body);
12892         
12893         return this;
12894     },
12895      
12896     /**
12897      * same as applyTemplate, except it's done to one of the subTemplates
12898      * when using named templates, you can do:
12899      *
12900      * var str = pl.applySubTemplate('your-name', values);
12901      *
12902      * 
12903      * @param {Number} id of the template
12904      * @param {Object} values to apply to template
12905      * @param {Object} parent (normaly the instance of this object)
12906      */
12907     applySubTemplate : function(id, values, parent)
12908     {
12909         
12910         
12911         var t = this.tpls[id];
12912         
12913         
12914         try { 
12915             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12916                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12917                 return '';
12918             }
12919         } catch(e) {
12920             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12921             Roo.log(values);
12922           
12923             return '';
12924         }
12925         try { 
12926             
12927             if(t.execCall && t.execCall.call(this, values, parent)){
12928                 return '';
12929             }
12930         } catch(e) {
12931             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12932             Roo.log(values);
12933             return '';
12934         }
12935         
12936         try {
12937             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12938             parent = t.target ? values : parent;
12939             if(t.forCall && vs instanceof Array){
12940                 var buf = [];
12941                 for(var i = 0, len = vs.length; i < len; i++){
12942                     try {
12943                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12944                     } catch (e) {
12945                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12946                         Roo.log(e.body);
12947                         //Roo.log(t.compiled);
12948                         Roo.log(vs[i]);
12949                     }   
12950                 }
12951                 return buf.join('');
12952             }
12953         } catch (e) {
12954             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12955             Roo.log(values);
12956             return '';
12957         }
12958         try {
12959             return t.compiled.call(this, vs, parent);
12960         } catch (e) {
12961             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12962             Roo.log(e.body);
12963             //Roo.log(t.compiled);
12964             Roo.log(values);
12965             return '';
12966         }
12967     },
12968
12969    
12970
12971     applyTemplate : function(values){
12972         return this.master.compiled.call(this, values, {});
12973         //var s = this.subs;
12974     },
12975
12976     apply : function(){
12977         return this.applyTemplate.apply(this, arguments);
12978     }
12979
12980  });
12981
12982 Roo.DomTemplate.from = function(el){
12983     el = Roo.getDom(el);
12984     return new Roo.Domtemplate(el.value || el.innerHTML);
12985 };/*
12986  * Based on:
12987  * Ext JS Library 1.1.1
12988  * Copyright(c) 2006-2007, Ext JS, LLC.
12989  *
12990  * Originally Released Under LGPL - original licence link has changed is not relivant.
12991  *
12992  * Fork - LGPL
12993  * <script type="text/javascript">
12994  */
12995
12996 /**
12997  * @class Roo.util.DelayedTask
12998  * Provides a convenient method of performing setTimeout where a new
12999  * timeout cancels the old timeout. An example would be performing validation on a keypress.
13000  * You can use this class to buffer
13001  * the keypress events for a certain number of milliseconds, and perform only if they stop
13002  * for that amount of time.
13003  * @constructor The parameters to this constructor serve as defaults and are not required.
13004  * @param {Function} fn (optional) The default function to timeout
13005  * @param {Object} scope (optional) The default scope of that timeout
13006  * @param {Array} args (optional) The default Array of arguments
13007  */
13008 Roo.util.DelayedTask = function(fn, scope, args){
13009     var id = null, d, t;
13010
13011     var call = function(){
13012         var now = new Date().getTime();
13013         if(now - t >= d){
13014             clearInterval(id);
13015             id = null;
13016             fn.apply(scope, args || []);
13017         }
13018     };
13019     /**
13020      * Cancels any pending timeout and queues a new one
13021      * @param {Number} delay The milliseconds to delay
13022      * @param {Function} newFn (optional) Overrides function passed to constructor
13023      * @param {Object} newScope (optional) Overrides scope passed to constructor
13024      * @param {Array} newArgs (optional) Overrides args passed to constructor
13025      */
13026     this.delay = function(delay, newFn, newScope, newArgs){
13027         if(id && delay != d){
13028             this.cancel();
13029         }
13030         d = delay;
13031         t = new Date().getTime();
13032         fn = newFn || fn;
13033         scope = newScope || scope;
13034         args = newArgs || args;
13035         if(!id){
13036             id = setInterval(call, d);
13037         }
13038     };
13039
13040     /**
13041      * Cancel the last queued timeout
13042      */
13043     this.cancel = function(){
13044         if(id){
13045             clearInterval(id);
13046             id = null;
13047         }
13048     };
13049 };/*
13050  * Based on:
13051  * Ext JS Library 1.1.1
13052  * Copyright(c) 2006-2007, Ext JS, LLC.
13053  *
13054  * Originally Released Under LGPL - original licence link has changed is not relivant.
13055  *
13056  * Fork - LGPL
13057  * <script type="text/javascript">
13058  */
13059  
13060  
13061 Roo.util.TaskRunner = function(interval){
13062     interval = interval || 10;
13063     var tasks = [], removeQueue = [];
13064     var id = 0;
13065     var running = false;
13066
13067     var stopThread = function(){
13068         running = false;
13069         clearInterval(id);
13070         id = 0;
13071     };
13072
13073     var startThread = function(){
13074         if(!running){
13075             running = true;
13076             id = setInterval(runTasks, interval);
13077         }
13078     };
13079
13080     var removeTask = function(task){
13081         removeQueue.push(task);
13082         if(task.onStop){
13083             task.onStop();
13084         }
13085     };
13086
13087     var runTasks = function(){
13088         if(removeQueue.length > 0){
13089             for(var i = 0, len = removeQueue.length; i < len; i++){
13090                 tasks.remove(removeQueue[i]);
13091             }
13092             removeQueue = [];
13093             if(tasks.length < 1){
13094                 stopThread();
13095                 return;
13096             }
13097         }
13098         var now = new Date().getTime();
13099         for(var i = 0, len = tasks.length; i < len; ++i){
13100             var t = tasks[i];
13101             var itime = now - t.taskRunTime;
13102             if(t.interval <= itime){
13103                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13104                 t.taskRunTime = now;
13105                 if(rt === false || t.taskRunCount === t.repeat){
13106                     removeTask(t);
13107                     return;
13108                 }
13109             }
13110             if(t.duration && t.duration <= (now - t.taskStartTime)){
13111                 removeTask(t);
13112             }
13113         }
13114     };
13115
13116     /**
13117      * Queues a new task.
13118      * @param {Object} task
13119      */
13120     this.start = function(task){
13121         tasks.push(task);
13122         task.taskStartTime = new Date().getTime();
13123         task.taskRunTime = 0;
13124         task.taskRunCount = 0;
13125         startThread();
13126         return task;
13127     };
13128
13129     this.stop = function(task){
13130         removeTask(task);
13131         return task;
13132     };
13133
13134     this.stopAll = function(){
13135         stopThread();
13136         for(var i = 0, len = tasks.length; i < len; i++){
13137             if(tasks[i].onStop){
13138                 tasks[i].onStop();
13139             }
13140         }
13141         tasks = [];
13142         removeQueue = [];
13143     };
13144 };
13145
13146 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13147  * Based on:
13148  * Ext JS Library 1.1.1
13149  * Copyright(c) 2006-2007, Ext JS, LLC.
13150  *
13151  * Originally Released Under LGPL - original licence link has changed is not relivant.
13152  *
13153  * Fork - LGPL
13154  * <script type="text/javascript">
13155  */
13156
13157  
13158 /**
13159  * @class Roo.util.MixedCollection
13160  * @extends Roo.util.Observable
13161  * A Collection class that maintains both numeric indexes and keys and exposes events.
13162  * @constructor
13163  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13164  * collection (defaults to false)
13165  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13166  * and return the key value for that item.  This is used when available to look up the key on items that
13167  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
13168  * equivalent to providing an implementation for the {@link #getKey} method.
13169  */
13170 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13171     this.items = [];
13172     this.map = {};
13173     this.keys = [];
13174     this.length = 0;
13175     this.addEvents({
13176         /**
13177          * @event clear
13178          * Fires when the collection is cleared.
13179          */
13180         "clear" : true,
13181         /**
13182          * @event add
13183          * Fires when an item is added to the collection.
13184          * @param {Number} index The index at which the item was added.
13185          * @param {Object} o The item added.
13186          * @param {String} key The key associated with the added item.
13187          */
13188         "add" : true,
13189         /**
13190          * @event replace
13191          * Fires when an item is replaced in the collection.
13192          * @param {String} key he key associated with the new added.
13193          * @param {Object} old The item being replaced.
13194          * @param {Object} new The new item.
13195          */
13196         "replace" : true,
13197         /**
13198          * @event remove
13199          * Fires when an item is removed from the collection.
13200          * @param {Object} o The item being removed.
13201          * @param {String} key (optional) The key associated with the removed item.
13202          */
13203         "remove" : true,
13204         "sort" : true
13205     });
13206     this.allowFunctions = allowFunctions === true;
13207     if(keyFn){
13208         this.getKey = keyFn;
13209     }
13210     Roo.util.MixedCollection.superclass.constructor.call(this);
13211 };
13212
13213 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13214     allowFunctions : false,
13215     
13216 /**
13217  * Adds an item to the collection.
13218  * @param {String} key The key to associate with the item
13219  * @param {Object} o The item to add.
13220  * @return {Object} The item added.
13221  */
13222     add : function(key, o){
13223         if(arguments.length == 1){
13224             o = arguments[0];
13225             key = this.getKey(o);
13226         }
13227         if(typeof key == "undefined" || key === null){
13228             this.length++;
13229             this.items.push(o);
13230             this.keys.push(null);
13231         }else{
13232             var old = this.map[key];
13233             if(old){
13234                 return this.replace(key, o);
13235             }
13236             this.length++;
13237             this.items.push(o);
13238             this.map[key] = o;
13239             this.keys.push(key);
13240         }
13241         this.fireEvent("add", this.length-1, o, key);
13242         return o;
13243     },
13244        
13245 /**
13246   * MixedCollection has a generic way to fetch keys if you implement getKey.
13247 <pre><code>
13248 // normal way
13249 var mc = new Roo.util.MixedCollection();
13250 mc.add(someEl.dom.id, someEl);
13251 mc.add(otherEl.dom.id, otherEl);
13252 //and so on
13253
13254 // using getKey
13255 var mc = new Roo.util.MixedCollection();
13256 mc.getKey = function(el){
13257    return el.dom.id;
13258 };
13259 mc.add(someEl);
13260 mc.add(otherEl);
13261
13262 // or via the constructor
13263 var mc = new Roo.util.MixedCollection(false, function(el){
13264    return el.dom.id;
13265 });
13266 mc.add(someEl);
13267 mc.add(otherEl);
13268 </code></pre>
13269  * @param o {Object} The item for which to find the key.
13270  * @return {Object} The key for the passed item.
13271  */
13272     getKey : function(o){
13273          return o.id; 
13274     },
13275    
13276 /**
13277  * Replaces an item in the collection.
13278  * @param {String} key The key associated with the item to replace, or the item to replace.
13279  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13280  * @return {Object}  The new item.
13281  */
13282     replace : function(key, o){
13283         if(arguments.length == 1){
13284             o = arguments[0];
13285             key = this.getKey(o);
13286         }
13287         var old = this.item(key);
13288         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13289              return this.add(key, o);
13290         }
13291         var index = this.indexOfKey(key);
13292         this.items[index] = o;
13293         this.map[key] = o;
13294         this.fireEvent("replace", key, old, o);
13295         return o;
13296     },
13297    
13298 /**
13299  * Adds all elements of an Array or an Object to the collection.
13300  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13301  * an Array of values, each of which are added to the collection.
13302  */
13303     addAll : function(objs){
13304         if(arguments.length > 1 || objs instanceof Array){
13305             var args = arguments.length > 1 ? arguments : objs;
13306             for(var i = 0, len = args.length; i < len; i++){
13307                 this.add(args[i]);
13308             }
13309         }else{
13310             for(var key in objs){
13311                 if(this.allowFunctions || typeof objs[key] != "function"){
13312                     this.add(key, objs[key]);
13313                 }
13314             }
13315         }
13316     },
13317    
13318 /**
13319  * Executes the specified function once for every item in the collection, passing each
13320  * item as the first and only parameter. returning false from the function will stop the iteration.
13321  * @param {Function} fn The function to execute for each item.
13322  * @param {Object} scope (optional) The scope in which to execute the function.
13323  */
13324     each : function(fn, scope){
13325         var items = [].concat(this.items); // each safe for removal
13326         for(var i = 0, len = items.length; i < len; i++){
13327             if(fn.call(scope || items[i], items[i], i, len) === false){
13328                 break;
13329             }
13330         }
13331     },
13332    
13333 /**
13334  * Executes the specified function once for every key in the collection, passing each
13335  * key, and its associated item as the first two parameters.
13336  * @param {Function} fn The function to execute for each item.
13337  * @param {Object} scope (optional) The scope in which to execute the function.
13338  */
13339     eachKey : function(fn, scope){
13340         for(var i = 0, len = this.keys.length; i < len; i++){
13341             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13342         }
13343     },
13344    
13345 /**
13346  * Returns the first item in the collection which elicits a true return value from the
13347  * passed selection function.
13348  * @param {Function} fn The selection function to execute for each item.
13349  * @param {Object} scope (optional) The scope in which to execute the function.
13350  * @return {Object} The first item in the collection which returned true from the selection function.
13351  */
13352     find : function(fn, scope){
13353         for(var i = 0, len = this.items.length; i < len; i++){
13354             if(fn.call(scope || window, this.items[i], this.keys[i])){
13355                 return this.items[i];
13356             }
13357         }
13358         return null;
13359     },
13360    
13361 /**
13362  * Inserts an item at the specified index in the collection.
13363  * @param {Number} index The index to insert the item at.
13364  * @param {String} key The key to associate with the new item, or the item itself.
13365  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13366  * @return {Object} The item inserted.
13367  */
13368     insert : function(index, key, o){
13369         if(arguments.length == 2){
13370             o = arguments[1];
13371             key = this.getKey(o);
13372         }
13373         if(index >= this.length){
13374             return this.add(key, o);
13375         }
13376         this.length++;
13377         this.items.splice(index, 0, o);
13378         if(typeof key != "undefined" && key != null){
13379             this.map[key] = o;
13380         }
13381         this.keys.splice(index, 0, key);
13382         this.fireEvent("add", index, o, key);
13383         return o;
13384     },
13385    
13386 /**
13387  * Removed an item from the collection.
13388  * @param {Object} o The item to remove.
13389  * @return {Object} The item removed.
13390  */
13391     remove : function(o){
13392         return this.removeAt(this.indexOf(o));
13393     },
13394    
13395 /**
13396  * Remove an item from a specified index in the collection.
13397  * @param {Number} index The index within the collection of the item to remove.
13398  */
13399     removeAt : function(index){
13400         if(index < this.length && index >= 0){
13401             this.length--;
13402             var o = this.items[index];
13403             this.items.splice(index, 1);
13404             var key = this.keys[index];
13405             if(typeof key != "undefined"){
13406                 delete this.map[key];
13407             }
13408             this.keys.splice(index, 1);
13409             this.fireEvent("remove", o, key);
13410         }
13411     },
13412    
13413 /**
13414  * Removed an item associated with the passed key fom the collection.
13415  * @param {String} key The key of the item to remove.
13416  */
13417     removeKey : function(key){
13418         return this.removeAt(this.indexOfKey(key));
13419     },
13420    
13421 /**
13422  * Returns the number of items in the collection.
13423  * @return {Number} the number of items in the collection.
13424  */
13425     getCount : function(){
13426         return this.length; 
13427     },
13428    
13429 /**
13430  * Returns index within the collection of the passed Object.
13431  * @param {Object} o The item to find the index of.
13432  * @return {Number} index of the item.
13433  */
13434     indexOf : function(o){
13435         if(!this.items.indexOf){
13436             for(var i = 0, len = this.items.length; i < len; i++){
13437                 if(this.items[i] == o) {
13438                     return i;
13439                 }
13440             }
13441             return -1;
13442         }else{
13443             return this.items.indexOf(o);
13444         }
13445     },
13446    
13447 /**
13448  * Returns index within the collection of the passed key.
13449  * @param {String} key The key to find the index of.
13450  * @return {Number} index of the key.
13451  */
13452     indexOfKey : function(key){
13453         if(!this.keys.indexOf){
13454             for(var i = 0, len = this.keys.length; i < len; i++){
13455                 if(this.keys[i] == key) {
13456                     return i;
13457                 }
13458             }
13459             return -1;
13460         }else{
13461             return this.keys.indexOf(key);
13462         }
13463     },
13464    
13465 /**
13466  * Returns the item associated with the passed key OR index. Key has priority over index.
13467  * @param {String/Number} key The key or index of the item.
13468  * @return {Object} The item associated with the passed key.
13469  */
13470     item : function(key){
13471         if (key === 'length') {
13472             return null;
13473         }
13474         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13475         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13476     },
13477     
13478 /**
13479  * Returns the item at the specified index.
13480  * @param {Number} index The index of the item.
13481  * @return {Object}
13482  */
13483     itemAt : function(index){
13484         return this.items[index];
13485     },
13486     
13487 /**
13488  * Returns the item associated with the passed key.
13489  * @param {String/Number} key The key of the item.
13490  * @return {Object} The item associated with the passed key.
13491  */
13492     key : function(key){
13493         return this.map[key];
13494     },
13495    
13496 /**
13497  * Returns true if the collection contains the passed Object as an item.
13498  * @param {Object} o  The Object to look for in the collection.
13499  * @return {Boolean} True if the collection contains the Object as an item.
13500  */
13501     contains : function(o){
13502         return this.indexOf(o) != -1;
13503     },
13504    
13505 /**
13506  * Returns true if the collection contains the passed Object as a key.
13507  * @param {String} key The key to look for in the collection.
13508  * @return {Boolean} True if the collection contains the Object as a key.
13509  */
13510     containsKey : function(key){
13511         return typeof this.map[key] != "undefined";
13512     },
13513    
13514 /**
13515  * Removes all items from the collection.
13516  */
13517     clear : function(){
13518         this.length = 0;
13519         this.items = [];
13520         this.keys = [];
13521         this.map = {};
13522         this.fireEvent("clear");
13523     },
13524    
13525 /**
13526  * Returns the first item in the collection.
13527  * @return {Object} the first item in the collection..
13528  */
13529     first : function(){
13530         return this.items[0]; 
13531     },
13532    
13533 /**
13534  * Returns the last item in the collection.
13535  * @return {Object} the last item in the collection..
13536  */
13537     last : function(){
13538         return this.items[this.length-1];   
13539     },
13540     
13541     _sort : function(property, dir, fn){
13542         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13543         fn = fn || function(a, b){
13544             return a-b;
13545         };
13546         var c = [], k = this.keys, items = this.items;
13547         for(var i = 0, len = items.length; i < len; i++){
13548             c[c.length] = {key: k[i], value: items[i], index: i};
13549         }
13550         c.sort(function(a, b){
13551             var v = fn(a[property], b[property]) * dsc;
13552             if(v == 0){
13553                 v = (a.index < b.index ? -1 : 1);
13554             }
13555             return v;
13556         });
13557         for(var i = 0, len = c.length; i < len; i++){
13558             items[i] = c[i].value;
13559             k[i] = c[i].key;
13560         }
13561         this.fireEvent("sort", this);
13562     },
13563     
13564     /**
13565      * Sorts this collection with the passed comparison function
13566      * @param {String} direction (optional) "ASC" or "DESC"
13567      * @param {Function} fn (optional) comparison function
13568      */
13569     sort : function(dir, fn){
13570         this._sort("value", dir, fn);
13571     },
13572     
13573     /**
13574      * Sorts this collection by keys
13575      * @param {String} direction (optional) "ASC" or "DESC"
13576      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13577      */
13578     keySort : function(dir, fn){
13579         this._sort("key", dir, fn || function(a, b){
13580             return String(a).toUpperCase()-String(b).toUpperCase();
13581         });
13582     },
13583     
13584     /**
13585      * Returns a range of items in this collection
13586      * @param {Number} startIndex (optional) defaults to 0
13587      * @param {Number} endIndex (optional) default to the last item
13588      * @return {Array} An array of items
13589      */
13590     getRange : function(start, end){
13591         var items = this.items;
13592         if(items.length < 1){
13593             return [];
13594         }
13595         start = start || 0;
13596         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13597         var r = [];
13598         if(start <= end){
13599             for(var i = start; i <= end; i++) {
13600                     r[r.length] = items[i];
13601             }
13602         }else{
13603             for(var i = start; i >= end; i--) {
13604                     r[r.length] = items[i];
13605             }
13606         }
13607         return r;
13608     },
13609         
13610     /**
13611      * Filter the <i>objects</i> in this collection by a specific property. 
13612      * Returns a new collection that has been filtered.
13613      * @param {String} property A property on your objects
13614      * @param {String/RegExp} value Either string that the property values 
13615      * should start with or a RegExp to test against the property
13616      * @return {MixedCollection} The new filtered collection
13617      */
13618     filter : function(property, value){
13619         if(!value.exec){ // not a regex
13620             value = String(value);
13621             if(value.length == 0){
13622                 return this.clone();
13623             }
13624             value = new RegExp("^" + Roo.escapeRe(value), "i");
13625         }
13626         return this.filterBy(function(o){
13627             return o && value.test(o[property]);
13628         });
13629         },
13630     
13631     /**
13632      * Filter by a function. * Returns a new collection that has been filtered.
13633      * The passed function will be called with each 
13634      * object in the collection. If the function returns true, the value is included 
13635      * otherwise it is filtered.
13636      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13637      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13638      * @return {MixedCollection} The new filtered collection
13639      */
13640     filterBy : function(fn, scope){
13641         var r = new Roo.util.MixedCollection();
13642         r.getKey = this.getKey;
13643         var k = this.keys, it = this.items;
13644         for(var i = 0, len = it.length; i < len; i++){
13645             if(fn.call(scope||this, it[i], k[i])){
13646                                 r.add(k[i], it[i]);
13647                         }
13648         }
13649         return r;
13650     },
13651     
13652     /**
13653      * Creates a duplicate of this collection
13654      * @return {MixedCollection}
13655      */
13656     clone : function(){
13657         var r = new Roo.util.MixedCollection();
13658         var k = this.keys, it = this.items;
13659         for(var i = 0, len = it.length; i < len; i++){
13660             r.add(k[i], it[i]);
13661         }
13662         r.getKey = this.getKey;
13663         return r;
13664     }
13665 });
13666 /**
13667  * Returns the item associated with the passed key or index.
13668  * @method
13669  * @param {String/Number} key The key or index of the item.
13670  * @return {Object} The item associated with the passed key.
13671  */
13672 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13673  * Based on:
13674  * Ext JS Library 1.1.1
13675  * Copyright(c) 2006-2007, Ext JS, LLC.
13676  *
13677  * Originally Released Under LGPL - original licence link has changed is not relivant.
13678  *
13679  * Fork - LGPL
13680  * <script type="text/javascript">
13681  */
13682 /**
13683  * @class Roo.util.JSON
13684  * Modified version of Douglas Crockford"s json.js that doesn"t
13685  * mess with the Object prototype 
13686  * http://www.json.org/js.html
13687  * @singleton
13688  */
13689 Roo.util.JSON = new (function(){
13690     var useHasOwn = {}.hasOwnProperty ? true : false;
13691     
13692     // crashes Safari in some instances
13693     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13694     
13695     var pad = function(n) {
13696         return n < 10 ? "0" + n : n;
13697     };
13698     
13699     var m = {
13700         "\b": '\\b',
13701         "\t": '\\t',
13702         "\n": '\\n',
13703         "\f": '\\f',
13704         "\r": '\\r',
13705         '"' : '\\"',
13706         "\\": '\\\\'
13707     };
13708
13709     var encodeString = function(s){
13710         if (/["\\\x00-\x1f]/.test(s)) {
13711             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13712                 var c = m[b];
13713                 if(c){
13714                     return c;
13715                 }
13716                 c = b.charCodeAt();
13717                 return "\\u00" +
13718                     Math.floor(c / 16).toString(16) +
13719                     (c % 16).toString(16);
13720             }) + '"';
13721         }
13722         return '"' + s + '"';
13723     };
13724     
13725     var encodeArray = function(o){
13726         var a = ["["], b, i, l = o.length, v;
13727             for (i = 0; i < l; i += 1) {
13728                 v = o[i];
13729                 switch (typeof v) {
13730                     case "undefined":
13731                     case "function":
13732                     case "unknown":
13733                         break;
13734                     default:
13735                         if (b) {
13736                             a.push(',');
13737                         }
13738                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13739                         b = true;
13740                 }
13741             }
13742             a.push("]");
13743             return a.join("");
13744     };
13745     
13746     var encodeDate = function(o){
13747         return '"' + o.getFullYear() + "-" +
13748                 pad(o.getMonth() + 1) + "-" +
13749                 pad(o.getDate()) + "T" +
13750                 pad(o.getHours()) + ":" +
13751                 pad(o.getMinutes()) + ":" +
13752                 pad(o.getSeconds()) + '"';
13753     };
13754     
13755     /**
13756      * Encodes an Object, Array or other value
13757      * @param {Mixed} o The variable to encode
13758      * @return {String} The JSON string
13759      */
13760     this.encode = function(o)
13761     {
13762         // should this be extended to fully wrap stringify..
13763         
13764         if(typeof o == "undefined" || o === null){
13765             return "null";
13766         }else if(o instanceof Array){
13767             return encodeArray(o);
13768         }else if(o instanceof Date){
13769             return encodeDate(o);
13770         }else if(typeof o == "string"){
13771             return encodeString(o);
13772         }else if(typeof o == "number"){
13773             return isFinite(o) ? String(o) : "null";
13774         }else if(typeof o == "boolean"){
13775             return String(o);
13776         }else {
13777             var a = ["{"], b, i, v;
13778             for (i in o) {
13779                 if(!useHasOwn || o.hasOwnProperty(i)) {
13780                     v = o[i];
13781                     switch (typeof v) {
13782                     case "undefined":
13783                     case "function":
13784                     case "unknown":
13785                         break;
13786                     default:
13787                         if(b){
13788                             a.push(',');
13789                         }
13790                         a.push(this.encode(i), ":",
13791                                 v === null ? "null" : this.encode(v));
13792                         b = true;
13793                     }
13794                 }
13795             }
13796             a.push("}");
13797             return a.join("");
13798         }
13799     };
13800     
13801     /**
13802      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13803      * @param {String} json The JSON string
13804      * @return {Object} The resulting object
13805      */
13806     this.decode = function(json){
13807         
13808         return  /** eval:var:json */ eval("(" + json + ')');
13809     };
13810 })();
13811 /** 
13812  * Shorthand for {@link Roo.util.JSON#encode}
13813  * @member Roo encode 
13814  * @method */
13815 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13816 /** 
13817  * Shorthand for {@link Roo.util.JSON#decode}
13818  * @member Roo decode 
13819  * @method */
13820 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13821 /*
13822  * Based on:
13823  * Ext JS Library 1.1.1
13824  * Copyright(c) 2006-2007, Ext JS, LLC.
13825  *
13826  * Originally Released Under LGPL - original licence link has changed is not relivant.
13827  *
13828  * Fork - LGPL
13829  * <script type="text/javascript">
13830  */
13831  
13832 /**
13833  * @class Roo.util.Format
13834  * Reusable data formatting functions
13835  * @singleton
13836  */
13837 Roo.util.Format = function(){
13838     var trimRe = /^\s+|\s+$/g;
13839     return {
13840         /**
13841          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13842          * @param {String} value The string to truncate
13843          * @param {Number} length The maximum length to allow before truncating
13844          * @return {String} The converted text
13845          */
13846         ellipsis : function(value, len){
13847             if(value && value.length > len){
13848                 return value.substr(0, len-3)+"...";
13849             }
13850             return value;
13851         },
13852
13853         /**
13854          * Checks a reference and converts it to empty string if it is undefined
13855          * @param {Mixed} value Reference to check
13856          * @return {Mixed} Empty string if converted, otherwise the original value
13857          */
13858         undef : function(value){
13859             return typeof value != "undefined" ? value : "";
13860         },
13861
13862         /**
13863          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13864          * @param {String} value The string to encode
13865          * @return {String} The encoded text
13866          */
13867         htmlEncode : function(value){
13868             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13869         },
13870
13871         /**
13872          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13873          * @param {String} value The string to decode
13874          * @return {String} The decoded text
13875          */
13876         htmlDecode : function(value){
13877             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13878         },
13879
13880         /**
13881          * Trims any whitespace from either side of a string
13882          * @param {String} value The text to trim
13883          * @return {String} The trimmed text
13884          */
13885         trim : function(value){
13886             return String(value).replace(trimRe, "");
13887         },
13888
13889         /**
13890          * Returns a substring from within an original string
13891          * @param {String} value The original text
13892          * @param {Number} start The start index of the substring
13893          * @param {Number} length The length of the substring
13894          * @return {String} The substring
13895          */
13896         substr : function(value, start, length){
13897             return String(value).substr(start, length);
13898         },
13899
13900         /**
13901          * Converts a string to all lower case letters
13902          * @param {String} value The text to convert
13903          * @return {String} The converted text
13904          */
13905         lowercase : function(value){
13906             return String(value).toLowerCase();
13907         },
13908
13909         /**
13910          * Converts a string to all upper case letters
13911          * @param {String} value The text to convert
13912          * @return {String} The converted text
13913          */
13914         uppercase : function(value){
13915             return String(value).toUpperCase();
13916         },
13917
13918         /**
13919          * Converts the first character only of a string to upper case
13920          * @param {String} value The text to convert
13921          * @return {String} The converted text
13922          */
13923         capitalize : function(value){
13924             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13925         },
13926
13927         // private
13928         call : function(value, fn){
13929             if(arguments.length > 2){
13930                 var args = Array.prototype.slice.call(arguments, 2);
13931                 args.unshift(value);
13932                  
13933                 return /** eval:var:value */  eval(fn).apply(window, args);
13934             }else{
13935                 /** eval:var:value */
13936                 return /** eval:var:value */ eval(fn).call(window, value);
13937             }
13938         },
13939
13940        
13941         /**
13942          * safer version of Math.toFixed..??/
13943          * @param {Number/String} value The numeric value to format
13944          * @param {Number/String} value Decimal places 
13945          * @return {String} The formatted currency string
13946          */
13947         toFixed : function(v, n)
13948         {
13949             // why not use to fixed - precision is buggered???
13950             if (!n) {
13951                 return Math.round(v-0);
13952             }
13953             var fact = Math.pow(10,n+1);
13954             v = (Math.round((v-0)*fact))/fact;
13955             var z = (''+fact).substring(2);
13956             if (v == Math.floor(v)) {
13957                 return Math.floor(v) + '.' + z;
13958             }
13959             
13960             // now just padd decimals..
13961             var ps = String(v).split('.');
13962             var fd = (ps[1] + z);
13963             var r = fd.substring(0,n); 
13964             var rm = fd.substring(n); 
13965             if (rm < 5) {
13966                 return ps[0] + '.' + r;
13967             }
13968             r*=1; // turn it into a number;
13969             r++;
13970             if (String(r).length != n) {
13971                 ps[0]*=1;
13972                 ps[0]++;
13973                 r = String(r).substring(1); // chop the end off.
13974             }
13975             
13976             return ps[0] + '.' + r;
13977              
13978         },
13979         
13980         /**
13981          * Format a number as US currency
13982          * @param {Number/String} value The numeric value to format
13983          * @return {String} The formatted currency string
13984          */
13985         usMoney : function(v){
13986             return '$' + Roo.util.Format.number(v);
13987         },
13988         
13989         /**
13990          * Format a number
13991          * eventually this should probably emulate php's number_format
13992          * @param {Number/String} value The numeric value to format
13993          * @param {Number} decimals number of decimal places
13994          * @param {String} delimiter for thousands (default comma)
13995          * @return {String} The formatted currency string
13996          */
13997         number : function(v, decimals, thousandsDelimiter)
13998         {
13999             // multiply and round.
14000             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14001             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14002             
14003             var mul = Math.pow(10, decimals);
14004             var zero = String(mul).substring(1);
14005             v = (Math.round((v-0)*mul))/mul;
14006             
14007             // if it's '0' number.. then
14008             
14009             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14010             v = String(v);
14011             var ps = v.split('.');
14012             var whole = ps[0];
14013             
14014             var r = /(\d+)(\d{3})/;
14015             // add comma's
14016             
14017             if(thousandsDelimiter.length != 0) {
14018                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14019             } 
14020             
14021             var sub = ps[1] ?
14022                     // has decimals..
14023                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14024                     // does not have decimals
14025                     (decimals ? ('.' + zero) : '');
14026             
14027             
14028             return whole + sub ;
14029         },
14030         
14031         /**
14032          * Parse a value into a formatted date using the specified format pattern.
14033          * @param {Mixed} value The value to format
14034          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14035          * @return {String} The formatted date string
14036          */
14037         date : function(v, format){
14038             if(!v){
14039                 return "";
14040             }
14041             if(!(v instanceof Date)){
14042                 v = new Date(Date.parse(v));
14043             }
14044             return v.dateFormat(format || Roo.util.Format.defaults.date);
14045         },
14046
14047         /**
14048          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14049          * @param {String} format Any valid date format string
14050          * @return {Function} The date formatting function
14051          */
14052         dateRenderer : function(format){
14053             return function(v){
14054                 return Roo.util.Format.date(v, format);  
14055             };
14056         },
14057
14058         // private
14059         stripTagsRE : /<\/?[^>]+>/gi,
14060         
14061         /**
14062          * Strips all HTML tags
14063          * @param {Mixed} value The text from which to strip tags
14064          * @return {String} The stripped text
14065          */
14066         stripTags : function(v){
14067             return !v ? v : String(v).replace(this.stripTagsRE, "");
14068         },
14069         
14070         /**
14071          * Size in Mb,Gb etc.
14072          * @param {Number} value The number to be formated
14073          * @param {number} decimals how many decimal places
14074          * @return {String} the formated string
14075          */
14076         size : function(value, decimals)
14077         {
14078             var sizes = ['b', 'k', 'M', 'G', 'T'];
14079             if (value == 0) {
14080                 return 0;
14081             }
14082             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14083             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
14084         }
14085         
14086         
14087         
14088     };
14089 }();
14090 Roo.util.Format.defaults = {
14091     date : 'd/M/Y'
14092 };/*
14093  * Based on:
14094  * Ext JS Library 1.1.1
14095  * Copyright(c) 2006-2007, Ext JS, LLC.
14096  *
14097  * Originally Released Under LGPL - original licence link has changed is not relivant.
14098  *
14099  * Fork - LGPL
14100  * <script type="text/javascript">
14101  */
14102
14103
14104  
14105
14106 /**
14107  * @class Roo.MasterTemplate
14108  * @extends Roo.Template
14109  * Provides a template that can have child templates. The syntax is:
14110 <pre><code>
14111 var t = new Roo.MasterTemplate(
14112         '&lt;select name="{name}"&gt;',
14113                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
14114         '&lt;/select&gt;'
14115 );
14116 t.add('options', {value: 'foo', text: 'bar'});
14117 // or you can add multiple child elements in one shot
14118 t.addAll('options', [
14119     {value: 'foo', text: 'bar'},
14120     {value: 'foo2', text: 'bar2'},
14121     {value: 'foo3', text: 'bar3'}
14122 ]);
14123 // then append, applying the master template values
14124 t.append('my-form', {name: 'my-select'});
14125 </code></pre>
14126 * A name attribute for the child template is not required if you have only one child
14127 * template or you want to refer to them by index.
14128  */
14129 Roo.MasterTemplate = function(){
14130     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14131     this.originalHtml = this.html;
14132     var st = {};
14133     var m, re = this.subTemplateRe;
14134     re.lastIndex = 0;
14135     var subIndex = 0;
14136     while(m = re.exec(this.html)){
14137         var name = m[1], content = m[2];
14138         st[subIndex] = {
14139             name: name,
14140             index: subIndex,
14141             buffer: [],
14142             tpl : new Roo.Template(content)
14143         };
14144         if(name){
14145             st[name] = st[subIndex];
14146         }
14147         st[subIndex].tpl.compile();
14148         st[subIndex].tpl.call = this.call.createDelegate(this);
14149         subIndex++;
14150     }
14151     this.subCount = subIndex;
14152     this.subs = st;
14153 };
14154 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14155     /**
14156     * The regular expression used to match sub templates
14157     * @type RegExp
14158     * @property
14159     */
14160     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14161
14162     /**
14163      * Applies the passed values to a child template.
14164      * @param {String/Number} name (optional) The name or index of the child template
14165      * @param {Array/Object} values The values to be applied to the template
14166      * @return {MasterTemplate} this
14167      */
14168      add : function(name, values){
14169         if(arguments.length == 1){
14170             values = arguments[0];
14171             name = 0;
14172         }
14173         var s = this.subs[name];
14174         s.buffer[s.buffer.length] = s.tpl.apply(values);
14175         return this;
14176     },
14177
14178     /**
14179      * Applies all the passed values to a child template.
14180      * @param {String/Number} name (optional) The name or index of the child template
14181      * @param {Array} values The values to be applied to the template, this should be an array of objects.
14182      * @param {Boolean} reset (optional) True to reset the template first
14183      * @return {MasterTemplate} this
14184      */
14185     fill : function(name, values, reset){
14186         var a = arguments;
14187         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14188             values = a[0];
14189             name = 0;
14190             reset = a[1];
14191         }
14192         if(reset){
14193             this.reset();
14194         }
14195         for(var i = 0, len = values.length; i < len; i++){
14196             this.add(name, values[i]);
14197         }
14198         return this;
14199     },
14200
14201     /**
14202      * Resets the template for reuse
14203      * @return {MasterTemplate} this
14204      */
14205      reset : function(){
14206         var s = this.subs;
14207         for(var i = 0; i < this.subCount; i++){
14208             s[i].buffer = [];
14209         }
14210         return this;
14211     },
14212
14213     applyTemplate : function(values){
14214         var s = this.subs;
14215         var replaceIndex = -1;
14216         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14217             return s[++replaceIndex].buffer.join("");
14218         });
14219         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14220     },
14221
14222     apply : function(){
14223         return this.applyTemplate.apply(this, arguments);
14224     },
14225
14226     compile : function(){return this;}
14227 });
14228
14229 /**
14230  * Alias for fill().
14231  * @method
14232  */
14233 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14234  /**
14235  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14236  * var tpl = Roo.MasterTemplate.from('element-id');
14237  * @param {String/HTMLElement} el
14238  * @param {Object} config
14239  * @static
14240  */
14241 Roo.MasterTemplate.from = function(el, config){
14242     el = Roo.getDom(el);
14243     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14244 };/*
14245  * Based on:
14246  * Ext JS Library 1.1.1
14247  * Copyright(c) 2006-2007, Ext JS, LLC.
14248  *
14249  * Originally Released Under LGPL - original licence link has changed is not relivant.
14250  *
14251  * Fork - LGPL
14252  * <script type="text/javascript">
14253  */
14254
14255  
14256 /**
14257  * @class Roo.util.CSS
14258  * Utility class for manipulating CSS rules
14259  * @singleton
14260  */
14261 Roo.util.CSS = function(){
14262         var rules = null;
14263         var doc = document;
14264
14265     var camelRe = /(-[a-z])/gi;
14266     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14267
14268    return {
14269    /**
14270     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14271     * tag and appended to the HEAD of the document.
14272     * @param {String|Object} cssText The text containing the css rules
14273     * @param {String} id An id to add to the stylesheet for later removal
14274     * @return {StyleSheet}
14275     */
14276     createStyleSheet : function(cssText, id){
14277         var ss;
14278         var head = doc.getElementsByTagName("head")[0];
14279         var nrules = doc.createElement("style");
14280         nrules.setAttribute("type", "text/css");
14281         if(id){
14282             nrules.setAttribute("id", id);
14283         }
14284         if (typeof(cssText) != 'string') {
14285             // support object maps..
14286             // not sure if this a good idea.. 
14287             // perhaps it should be merged with the general css handling
14288             // and handle js style props.
14289             var cssTextNew = [];
14290             for(var n in cssText) {
14291                 var citems = [];
14292                 for(var k in cssText[n]) {
14293                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14294                 }
14295                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14296                 
14297             }
14298             cssText = cssTextNew.join("\n");
14299             
14300         }
14301        
14302        
14303        if(Roo.isIE){
14304            head.appendChild(nrules);
14305            ss = nrules.styleSheet;
14306            ss.cssText = cssText;
14307        }else{
14308            try{
14309                 nrules.appendChild(doc.createTextNode(cssText));
14310            }catch(e){
14311                nrules.cssText = cssText; 
14312            }
14313            head.appendChild(nrules);
14314            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14315        }
14316        this.cacheStyleSheet(ss);
14317        return ss;
14318    },
14319
14320    /**
14321     * Removes a style or link tag by id
14322     * @param {String} id The id of the tag
14323     */
14324    removeStyleSheet : function(id){
14325        var existing = doc.getElementById(id);
14326        if(existing){
14327            existing.parentNode.removeChild(existing);
14328        }
14329    },
14330
14331    /**
14332     * Dynamically swaps an existing stylesheet reference for a new one
14333     * @param {String} id The id of an existing link tag to remove
14334     * @param {String} url The href of the new stylesheet to include
14335     */
14336    swapStyleSheet : function(id, url){
14337        this.removeStyleSheet(id);
14338        var ss = doc.createElement("link");
14339        ss.setAttribute("rel", "stylesheet");
14340        ss.setAttribute("type", "text/css");
14341        ss.setAttribute("id", id);
14342        ss.setAttribute("href", url);
14343        doc.getElementsByTagName("head")[0].appendChild(ss);
14344    },
14345    
14346    /**
14347     * Refresh the rule cache if you have dynamically added stylesheets
14348     * @return {Object} An object (hash) of rules indexed by selector
14349     */
14350    refreshCache : function(){
14351        return this.getRules(true);
14352    },
14353
14354    // private
14355    cacheStyleSheet : function(stylesheet){
14356        if(!rules){
14357            rules = {};
14358        }
14359        try{// try catch for cross domain access issue
14360            var ssRules = stylesheet.cssRules || stylesheet.rules;
14361            for(var j = ssRules.length-1; j >= 0; --j){
14362                rules[ssRules[j].selectorText] = ssRules[j];
14363            }
14364        }catch(e){}
14365    },
14366    
14367    /**
14368     * Gets all css rules for the document
14369     * @param {Boolean} refreshCache true to refresh the internal cache
14370     * @return {Object} An object (hash) of rules indexed by selector
14371     */
14372    getRules : function(refreshCache){
14373                 if(rules == null || refreshCache){
14374                         rules = {};
14375                         var ds = doc.styleSheets;
14376                         for(var i =0, len = ds.length; i < len; i++){
14377                             try{
14378                         this.cacheStyleSheet(ds[i]);
14379                     }catch(e){} 
14380                 }
14381                 }
14382                 return rules;
14383         },
14384         
14385         /**
14386     * Gets an an individual CSS rule by selector(s)
14387     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14388     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14389     * @return {CSSRule} The CSS rule or null if one is not found
14390     */
14391    getRule : function(selector, refreshCache){
14392                 var rs = this.getRules(refreshCache);
14393                 if(!(selector instanceof Array)){
14394                     return rs[selector];
14395                 }
14396                 for(var i = 0; i < selector.length; i++){
14397                         if(rs[selector[i]]){
14398                                 return rs[selector[i]];
14399                         }
14400                 }
14401                 return null;
14402         },
14403         
14404         
14405         /**
14406     * Updates a rule property
14407     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14408     * @param {String} property The css property
14409     * @param {String} value The new value for the property
14410     * @return {Boolean} true If a rule was found and updated
14411     */
14412    updateRule : function(selector, property, value){
14413                 if(!(selector instanceof Array)){
14414                         var rule = this.getRule(selector);
14415                         if(rule){
14416                                 rule.style[property.replace(camelRe, camelFn)] = value;
14417                                 return true;
14418                         }
14419                 }else{
14420                         for(var i = 0; i < selector.length; i++){
14421                                 if(this.updateRule(selector[i], property, value)){
14422                                         return true;
14423                                 }
14424                         }
14425                 }
14426                 return false;
14427         }
14428    };   
14429 }();/*
14430  * Based on:
14431  * Ext JS Library 1.1.1
14432  * Copyright(c) 2006-2007, Ext JS, LLC.
14433  *
14434  * Originally Released Under LGPL - original licence link has changed is not relivant.
14435  *
14436  * Fork - LGPL
14437  * <script type="text/javascript">
14438  */
14439
14440  
14441
14442 /**
14443  * @class Roo.util.ClickRepeater
14444  * @extends Roo.util.Observable
14445  * 
14446  * A wrapper class which can be applied to any element. Fires a "click" event while the
14447  * mouse is pressed. The interval between firings may be specified in the config but
14448  * defaults to 10 milliseconds.
14449  * 
14450  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14451  * 
14452  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14453  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14454  * Similar to an autorepeat key delay.
14455  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14456  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14457  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14458  *           "interval" and "delay" are ignored. "immediate" is honored.
14459  * @cfg {Boolean} preventDefault True to prevent the default click event
14460  * @cfg {Boolean} stopDefault True to stop the default click event
14461  * 
14462  * @history
14463  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14464  *     2007-02-02 jvs Renamed to ClickRepeater
14465  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14466  *
14467  *  @constructor
14468  * @param {String/HTMLElement/Element} el The element to listen on
14469  * @param {Object} config
14470  **/
14471 Roo.util.ClickRepeater = function(el, config)
14472 {
14473     this.el = Roo.get(el);
14474     this.el.unselectable();
14475
14476     Roo.apply(this, config);
14477
14478     this.addEvents({
14479     /**
14480      * @event mousedown
14481      * Fires when the mouse button is depressed.
14482      * @param {Roo.util.ClickRepeater} this
14483      */
14484         "mousedown" : true,
14485     /**
14486      * @event click
14487      * Fires on a specified interval during the time the element is pressed.
14488      * @param {Roo.util.ClickRepeater} this
14489      */
14490         "click" : true,
14491     /**
14492      * @event mouseup
14493      * Fires when the mouse key is released.
14494      * @param {Roo.util.ClickRepeater} this
14495      */
14496         "mouseup" : true
14497     });
14498
14499     this.el.on("mousedown", this.handleMouseDown, this);
14500     if(this.preventDefault || this.stopDefault){
14501         this.el.on("click", function(e){
14502             if(this.preventDefault){
14503                 e.preventDefault();
14504             }
14505             if(this.stopDefault){
14506                 e.stopEvent();
14507             }
14508         }, this);
14509     }
14510
14511     // allow inline handler
14512     if(this.handler){
14513         this.on("click", this.handler,  this.scope || this);
14514     }
14515
14516     Roo.util.ClickRepeater.superclass.constructor.call(this);
14517 };
14518
14519 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14520     interval : 20,
14521     delay: 250,
14522     preventDefault : true,
14523     stopDefault : false,
14524     timer : 0,
14525
14526     // private
14527     handleMouseDown : function(){
14528         clearTimeout(this.timer);
14529         this.el.blur();
14530         if(this.pressClass){
14531             this.el.addClass(this.pressClass);
14532         }
14533         this.mousedownTime = new Date();
14534
14535         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14536         this.el.on("mouseout", this.handleMouseOut, this);
14537
14538         this.fireEvent("mousedown", this);
14539         this.fireEvent("click", this);
14540         
14541         this.timer = this.click.defer(this.delay || this.interval, this);
14542     },
14543
14544     // private
14545     click : function(){
14546         this.fireEvent("click", this);
14547         this.timer = this.click.defer(this.getInterval(), this);
14548     },
14549
14550     // private
14551     getInterval: function(){
14552         if(!this.accelerate){
14553             return this.interval;
14554         }
14555         var pressTime = this.mousedownTime.getElapsed();
14556         if(pressTime < 500){
14557             return 400;
14558         }else if(pressTime < 1700){
14559             return 320;
14560         }else if(pressTime < 2600){
14561             return 250;
14562         }else if(pressTime < 3500){
14563             return 180;
14564         }else if(pressTime < 4400){
14565             return 140;
14566         }else if(pressTime < 5300){
14567             return 80;
14568         }else if(pressTime < 6200){
14569             return 50;
14570         }else{
14571             return 10;
14572         }
14573     },
14574
14575     // private
14576     handleMouseOut : function(){
14577         clearTimeout(this.timer);
14578         if(this.pressClass){
14579             this.el.removeClass(this.pressClass);
14580         }
14581         this.el.on("mouseover", this.handleMouseReturn, this);
14582     },
14583
14584     // private
14585     handleMouseReturn : function(){
14586         this.el.un("mouseover", this.handleMouseReturn);
14587         if(this.pressClass){
14588             this.el.addClass(this.pressClass);
14589         }
14590         this.click();
14591     },
14592
14593     // private
14594     handleMouseUp : function(){
14595         clearTimeout(this.timer);
14596         this.el.un("mouseover", this.handleMouseReturn);
14597         this.el.un("mouseout", this.handleMouseOut);
14598         Roo.get(document).un("mouseup", this.handleMouseUp);
14599         this.el.removeClass(this.pressClass);
14600         this.fireEvent("mouseup", this);
14601     }
14602 });/**
14603  * @class Roo.util.Clipboard
14604  * @static
14605  * 
14606  * Clipboard UTILS
14607  * 
14608  **/
14609 Roo.util.Clipboard = {
14610     /**
14611      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
14612      * @param {String} text to copy to clipboard
14613      */
14614     write : function(text) {
14615         // navigator clipboard api needs a secure context (https)
14616         if (navigator.clipboard && window.isSecureContext) {
14617             // navigator clipboard api method'
14618             navigator.clipboard.writeText(text);
14619             return ;
14620         } 
14621         // text area method
14622         var ta = document.createElement("textarea");
14623         ta.value = text;
14624         // make the textarea out of viewport
14625         ta.style.position = "fixed";
14626         ta.style.left = "-999999px";
14627         ta.style.top = "-999999px";
14628         document.body.appendChild(ta);
14629         ta.focus();
14630         ta.select();
14631         document.execCommand('copy');
14632         (function() {
14633             ta.remove();
14634         }).defer(100);
14635         
14636     }
14637         
14638 }
14639     /*
14640  * Based on:
14641  * Ext JS Library 1.1.1
14642  * Copyright(c) 2006-2007, Ext JS, LLC.
14643  *
14644  * Originally Released Under LGPL - original licence link has changed is not relivant.
14645  *
14646  * Fork - LGPL
14647  * <script type="text/javascript">
14648  */
14649
14650  
14651 /**
14652  * @class Roo.KeyNav
14653  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14654  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14655  * way to implement custom navigation schemes for any UI component.</p>
14656  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14657  * pageUp, pageDown, del, home, end.  Usage:</p>
14658  <pre><code>
14659 var nav = new Roo.KeyNav("my-element", {
14660     "left" : function(e){
14661         this.moveLeft(e.ctrlKey);
14662     },
14663     "right" : function(e){
14664         this.moveRight(e.ctrlKey);
14665     },
14666     "enter" : function(e){
14667         this.save();
14668     },
14669     scope : this
14670 });
14671 </code></pre>
14672  * @constructor
14673  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14674  * @param {Object} config The config
14675  */
14676 Roo.KeyNav = function(el, config){
14677     this.el = Roo.get(el);
14678     Roo.apply(this, config);
14679     if(!this.disabled){
14680         this.disabled = true;
14681         this.enable();
14682     }
14683 };
14684
14685 Roo.KeyNav.prototype = {
14686     /**
14687      * @cfg {Boolean} disabled
14688      * True to disable this KeyNav instance (defaults to false)
14689      */
14690     disabled : false,
14691     /**
14692      * @cfg {String} defaultEventAction
14693      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14694      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14695      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14696      */
14697     defaultEventAction: "stopEvent",
14698     /**
14699      * @cfg {Boolean} forceKeyDown
14700      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14701      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14702      * handle keydown instead of keypress.
14703      */
14704     forceKeyDown : false,
14705
14706     // private
14707     prepareEvent : function(e){
14708         var k = e.getKey();
14709         var h = this.keyToHandler[k];
14710         //if(h && this[h]){
14711         //    e.stopPropagation();
14712         //}
14713         if(Roo.isSafari && h && k >= 37 && k <= 40){
14714             e.stopEvent();
14715         }
14716     },
14717
14718     // private
14719     relay : function(e){
14720         var k = e.getKey();
14721         var h = this.keyToHandler[k];
14722         if(h && this[h]){
14723             if(this.doRelay(e, this[h], h) !== true){
14724                 e[this.defaultEventAction]();
14725             }
14726         }
14727     },
14728
14729     // private
14730     doRelay : function(e, h, hname){
14731         return h.call(this.scope || this, e);
14732     },
14733
14734     // possible handlers
14735     enter : false,
14736     left : false,
14737     right : false,
14738     up : false,
14739     down : false,
14740     tab : false,
14741     esc : false,
14742     pageUp : false,
14743     pageDown : false,
14744     del : false,
14745     home : false,
14746     end : false,
14747
14748     // quick lookup hash
14749     keyToHandler : {
14750         37 : "left",
14751         39 : "right",
14752         38 : "up",
14753         40 : "down",
14754         33 : "pageUp",
14755         34 : "pageDown",
14756         46 : "del",
14757         36 : "home",
14758         35 : "end",
14759         13 : "enter",
14760         27 : "esc",
14761         9  : "tab"
14762     },
14763
14764         /**
14765          * Enable this KeyNav
14766          */
14767         enable: function(){
14768                 if(this.disabled){
14769             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14770             // the EventObject will normalize Safari automatically
14771             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14772                 this.el.on("keydown", this.relay,  this);
14773             }else{
14774                 this.el.on("keydown", this.prepareEvent,  this);
14775                 this.el.on("keypress", this.relay,  this);
14776             }
14777                     this.disabled = false;
14778                 }
14779         },
14780
14781         /**
14782          * Disable this KeyNav
14783          */
14784         disable: function(){
14785                 if(!this.disabled){
14786                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14787                 this.el.un("keydown", this.relay);
14788             }else{
14789                 this.el.un("keydown", this.prepareEvent);
14790                 this.el.un("keypress", this.relay);
14791             }
14792                     this.disabled = true;
14793                 }
14794         }
14795 };/*
14796  * Based on:
14797  * Ext JS Library 1.1.1
14798  * Copyright(c) 2006-2007, Ext JS, LLC.
14799  *
14800  * Originally Released Under LGPL - original licence link has changed is not relivant.
14801  *
14802  * Fork - LGPL
14803  * <script type="text/javascript">
14804  */
14805
14806  
14807 /**
14808  * @class Roo.KeyMap
14809  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14810  * The constructor accepts the same config object as defined by {@link #addBinding}.
14811  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14812  * combination it will call the function with this signature (if the match is a multi-key
14813  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14814  * A KeyMap can also handle a string representation of keys.<br />
14815  * Usage:
14816  <pre><code>
14817 // map one key by key code
14818 var map = new Roo.KeyMap("my-element", {
14819     key: 13, // or Roo.EventObject.ENTER
14820     fn: myHandler,
14821     scope: myObject
14822 });
14823
14824 // map multiple keys to one action by string
14825 var map = new Roo.KeyMap("my-element", {
14826     key: "a\r\n\t",
14827     fn: myHandler,
14828     scope: myObject
14829 });
14830
14831 // map multiple keys to multiple actions by strings and array of codes
14832 var map = new Roo.KeyMap("my-element", [
14833     {
14834         key: [10,13],
14835         fn: function(){ alert("Return was pressed"); }
14836     }, {
14837         key: "abc",
14838         fn: function(){ alert('a, b or c was pressed'); }
14839     }, {
14840         key: "\t",
14841         ctrl:true,
14842         shift:true,
14843         fn: function(){ alert('Control + shift + tab was pressed.'); }
14844     }
14845 ]);
14846 </code></pre>
14847  * <b>Note: A KeyMap starts enabled</b>
14848  * @constructor
14849  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14850  * @param {Object} config The config (see {@link #addBinding})
14851  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14852  */
14853 Roo.KeyMap = function(el, config, eventName){
14854     this.el  = Roo.get(el);
14855     this.eventName = eventName || "keydown";
14856     this.bindings = [];
14857     if(config){
14858         this.addBinding(config);
14859     }
14860     this.enable();
14861 };
14862
14863 Roo.KeyMap.prototype = {
14864     /**
14865      * True to stop the event from bubbling and prevent the default browser action if the
14866      * key was handled by the KeyMap (defaults to false)
14867      * @type Boolean
14868      */
14869     stopEvent : false,
14870
14871     /**
14872      * Add a new binding to this KeyMap. The following config object properties are supported:
14873      * <pre>
14874 Property    Type             Description
14875 ----------  ---------------  ----------------------------------------------------------------------
14876 key         String/Array     A single keycode or an array of keycodes to handle
14877 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14878 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14879 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14880 fn          Function         The function to call when KeyMap finds the expected key combination
14881 scope       Object           The scope of the callback function
14882 </pre>
14883      *
14884      * Usage:
14885      * <pre><code>
14886 // Create a KeyMap
14887 var map = new Roo.KeyMap(document, {
14888     key: Roo.EventObject.ENTER,
14889     fn: handleKey,
14890     scope: this
14891 });
14892
14893 //Add a new binding to the existing KeyMap later
14894 map.addBinding({
14895     key: 'abc',
14896     shift: true,
14897     fn: handleKey,
14898     scope: this
14899 });
14900 </code></pre>
14901      * @param {Object/Array} config A single KeyMap config or an array of configs
14902      */
14903         addBinding : function(config){
14904         if(config instanceof Array){
14905             for(var i = 0, len = config.length; i < len; i++){
14906                 this.addBinding(config[i]);
14907             }
14908             return;
14909         }
14910         var keyCode = config.key,
14911             shift = config.shift, 
14912             ctrl = config.ctrl, 
14913             alt = config.alt,
14914             fn = config.fn,
14915             scope = config.scope;
14916         if(typeof keyCode == "string"){
14917             var ks = [];
14918             var keyString = keyCode.toUpperCase();
14919             for(var j = 0, len = keyString.length; j < len; j++){
14920                 ks.push(keyString.charCodeAt(j));
14921             }
14922             keyCode = ks;
14923         }
14924         var keyArray = keyCode instanceof Array;
14925         var handler = function(e){
14926             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14927                 var k = e.getKey();
14928                 if(keyArray){
14929                     for(var i = 0, len = keyCode.length; i < len; i++){
14930                         if(keyCode[i] == k){
14931                           if(this.stopEvent){
14932                               e.stopEvent();
14933                           }
14934                           fn.call(scope || window, k, e);
14935                           return;
14936                         }
14937                     }
14938                 }else{
14939                     if(k == keyCode){
14940                         if(this.stopEvent){
14941                            e.stopEvent();
14942                         }
14943                         fn.call(scope || window, k, e);
14944                     }
14945                 }
14946             }
14947         };
14948         this.bindings.push(handler);  
14949         },
14950
14951     /**
14952      * Shorthand for adding a single key listener
14953      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14954      * following options:
14955      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14956      * @param {Function} fn The function to call
14957      * @param {Object} scope (optional) The scope of the function
14958      */
14959     on : function(key, fn, scope){
14960         var keyCode, shift, ctrl, alt;
14961         if(typeof key == "object" && !(key instanceof Array)){
14962             keyCode = key.key;
14963             shift = key.shift;
14964             ctrl = key.ctrl;
14965             alt = key.alt;
14966         }else{
14967             keyCode = key;
14968         }
14969         this.addBinding({
14970             key: keyCode,
14971             shift: shift,
14972             ctrl: ctrl,
14973             alt: alt,
14974             fn: fn,
14975             scope: scope
14976         })
14977     },
14978
14979     // private
14980     handleKeyDown : function(e){
14981             if(this.enabled){ //just in case
14982             var b = this.bindings;
14983             for(var i = 0, len = b.length; i < len; i++){
14984                 b[i].call(this, e);
14985             }
14986             }
14987         },
14988         
14989         /**
14990          * Returns true if this KeyMap is enabled
14991          * @return {Boolean} 
14992          */
14993         isEnabled : function(){
14994             return this.enabled;  
14995         },
14996         
14997         /**
14998          * Enables this KeyMap
14999          */
15000         enable: function(){
15001                 if(!this.enabled){
15002                     this.el.on(this.eventName, this.handleKeyDown, this);
15003                     this.enabled = true;
15004                 }
15005         },
15006
15007         /**
15008          * Disable this KeyMap
15009          */
15010         disable: function(){
15011                 if(this.enabled){
15012                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
15013                     this.enabled = false;
15014                 }
15015         }
15016 };/*
15017  * Based on:
15018  * Ext JS Library 1.1.1
15019  * Copyright(c) 2006-2007, Ext JS, LLC.
15020  *
15021  * Originally Released Under LGPL - original licence link has changed is not relivant.
15022  *
15023  * Fork - LGPL
15024  * <script type="text/javascript">
15025  */
15026
15027  
15028 /**
15029  * @class Roo.util.TextMetrics
15030  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15031  * wide, in pixels, a given block of text will be.
15032  * @singleton
15033  */
15034 Roo.util.TextMetrics = function(){
15035     var shared;
15036     return {
15037         /**
15038          * Measures the size of the specified text
15039          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15040          * that can affect the size of the rendered text
15041          * @param {String} text The text to measure
15042          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15043          * in order to accurately measure the text height
15044          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15045          */
15046         measure : function(el, text, fixedWidth){
15047             if(!shared){
15048                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15049             }
15050             shared.bind(el);
15051             shared.setFixedWidth(fixedWidth || 'auto');
15052             return shared.getSize(text);
15053         },
15054
15055         /**
15056          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
15057          * the overhead of multiple calls to initialize the style properties on each measurement.
15058          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15059          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15060          * in order to accurately measure the text height
15061          * @return {Roo.util.TextMetrics.Instance} instance The new instance
15062          */
15063         createInstance : function(el, fixedWidth){
15064             return Roo.util.TextMetrics.Instance(el, fixedWidth);
15065         }
15066     };
15067 }();
15068
15069  
15070
15071 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
15072     var ml = new Roo.Element(document.createElement('div'));
15073     document.body.appendChild(ml.dom);
15074     ml.position('absolute');
15075     ml.setLeftTop(-1000, -1000);
15076     ml.hide();
15077
15078     if(fixedWidth){
15079         ml.setWidth(fixedWidth);
15080     }
15081      
15082     var instance = {
15083         /**
15084          * Returns the size of the specified text based on the internal element's style and width properties
15085          * @memberOf Roo.util.TextMetrics.Instance#
15086          * @param {String} text The text to measure
15087          * @return {Object} An object containing the text's size {width: (width), height: (height)}
15088          */
15089         getSize : function(text){
15090             ml.update(text);
15091             var s = ml.getSize();
15092             ml.update('');
15093             return s;
15094         },
15095
15096         /**
15097          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15098          * that can affect the size of the rendered text
15099          * @memberOf Roo.util.TextMetrics.Instance#
15100          * @param {String/HTMLElement} el The element, dom node or id
15101          */
15102         bind : function(el){
15103             ml.setStyle(
15104                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15105             );
15106         },
15107
15108         /**
15109          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
15110          * to set a fixed width in order to accurately measure the text height.
15111          * @memberOf Roo.util.TextMetrics.Instance#
15112          * @param {Number} width The width to set on the element
15113          */
15114         setFixedWidth : function(width){
15115             ml.setWidth(width);
15116         },
15117
15118         /**
15119          * Returns the measured width of the specified text
15120          * @memberOf Roo.util.TextMetrics.Instance#
15121          * @param {String} text The text to measure
15122          * @return {Number} width The width in pixels
15123          */
15124         getWidth : function(text){
15125             ml.dom.style.width = 'auto';
15126             return this.getSize(text).width;
15127         },
15128
15129         /**
15130          * Returns the measured height of the specified text.  For multiline text, be sure to call
15131          * {@link #setFixedWidth} if necessary.
15132          * @memberOf Roo.util.TextMetrics.Instance#
15133          * @param {String} text The text to measure
15134          * @return {Number} height The height in pixels
15135          */
15136         getHeight : function(text){
15137             return this.getSize(text).height;
15138         }
15139     };
15140
15141     instance.bind(bindTo);
15142
15143     return instance;
15144 };
15145
15146 // backwards compat
15147 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15148  * Based on:
15149  * Ext JS Library 1.1.1
15150  * Copyright(c) 2006-2007, Ext JS, LLC.
15151  *
15152  * Originally Released Under LGPL - original licence link has changed is not relivant.
15153  *
15154  * Fork - LGPL
15155  * <script type="text/javascript">
15156  */
15157
15158 /**
15159  * @class Roo.state.Provider
15160  * Abstract base class for state provider implementations. This class provides methods
15161  * for encoding and decoding <b>typed</b> variables including dates and defines the 
15162  * Provider interface.
15163  */
15164 Roo.state.Provider = function(){
15165     /**
15166      * @event statechange
15167      * Fires when a state change occurs.
15168      * @param {Provider} this This state provider
15169      * @param {String} key The state key which was changed
15170      * @param {String} value The encoded value for the state
15171      */
15172     this.addEvents({
15173         "statechange": true
15174     });
15175     this.state = {};
15176     Roo.state.Provider.superclass.constructor.call(this);
15177 };
15178 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15179     /**
15180      * Returns the current value for a key
15181      * @param {String} name The key name
15182      * @param {Mixed} defaultValue A default value to return if the key's value is not found
15183      * @return {Mixed} The state data
15184      */
15185     get : function(name, defaultValue){
15186         return typeof this.state[name] == "undefined" ?
15187             defaultValue : this.state[name];
15188     },
15189     
15190     /**
15191      * Clears a value from the state
15192      * @param {String} name The key name
15193      */
15194     clear : function(name){
15195         delete this.state[name];
15196         this.fireEvent("statechange", this, name, null);
15197     },
15198     
15199     /**
15200      * Sets the value for a key
15201      * @param {String} name The key name
15202      * @param {Mixed} value The value to set
15203      */
15204     set : function(name, value){
15205         this.state[name] = value;
15206         this.fireEvent("statechange", this, name, value);
15207     },
15208     
15209     /**
15210      * Decodes a string previously encoded with {@link #encodeValue}.
15211      * @param {String} value The value to decode
15212      * @return {Mixed} The decoded value
15213      */
15214     decodeValue : function(cookie){
15215         var re = /^(a|n|d|b|s|o)\:(.*)$/;
15216         var matches = re.exec(unescape(cookie));
15217         if(!matches || !matches[1]) {
15218             return; // non state cookie
15219         }
15220         var type = matches[1];
15221         var v = matches[2];
15222         switch(type){
15223             case "n":
15224                 return parseFloat(v);
15225             case "d":
15226                 return new Date(Date.parse(v));
15227             case "b":
15228                 return (v == "1");
15229             case "a":
15230                 var all = [];
15231                 var values = v.split("^");
15232                 for(var i = 0, len = values.length; i < len; i++){
15233                     all.push(this.decodeValue(values[i]));
15234                 }
15235                 return all;
15236            case "o":
15237                 var all = {};
15238                 var values = v.split("^");
15239                 for(var i = 0, len = values.length; i < len; i++){
15240                     var kv = values[i].split("=");
15241                     all[kv[0]] = this.decodeValue(kv[1]);
15242                 }
15243                 return all;
15244            default:
15245                 return v;
15246         }
15247     },
15248     
15249     /**
15250      * Encodes a value including type information.  Decode with {@link #decodeValue}.
15251      * @param {Mixed} value The value to encode
15252      * @return {String} The encoded value
15253      */
15254     encodeValue : function(v){
15255         var enc;
15256         if(typeof v == "number"){
15257             enc = "n:" + v;
15258         }else if(typeof v == "boolean"){
15259             enc = "b:" + (v ? "1" : "0");
15260         }else if(v instanceof Date){
15261             enc = "d:" + v.toGMTString();
15262         }else if(v instanceof Array){
15263             var flat = "";
15264             for(var i = 0, len = v.length; i < len; i++){
15265                 flat += this.encodeValue(v[i]);
15266                 if(i != len-1) {
15267                     flat += "^";
15268                 }
15269             }
15270             enc = "a:" + flat;
15271         }else if(typeof v == "object"){
15272             var flat = "";
15273             for(var key in v){
15274                 if(typeof v[key] != "function"){
15275                     flat += key + "=" + this.encodeValue(v[key]) + "^";
15276                 }
15277             }
15278             enc = "o:" + flat.substring(0, flat.length-1);
15279         }else{
15280             enc = "s:" + v;
15281         }
15282         return escape(enc);        
15283     }
15284 });
15285
15286 /*
15287  * Based on:
15288  * Ext JS Library 1.1.1
15289  * Copyright(c) 2006-2007, Ext JS, LLC.
15290  *
15291  * Originally Released Under LGPL - original licence link has changed is not relivant.
15292  *
15293  * Fork - LGPL
15294  * <script type="text/javascript">
15295  */
15296 /**
15297  * @class Roo.state.Manager
15298  * This is the global state manager. By default all components that are "state aware" check this class
15299  * for state information if you don't pass them a custom state provider. In order for this class
15300  * to be useful, it must be initialized with a provider when your application initializes.
15301  <pre><code>
15302 // in your initialization function
15303 init : function(){
15304    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15305    ...
15306    // supposed you have a {@link Roo.BorderLayout}
15307    var layout = new Roo.BorderLayout(...);
15308    layout.restoreState();
15309    // or a {Roo.BasicDialog}
15310    var dialog = new Roo.BasicDialog(...);
15311    dialog.restoreState();
15312  </code></pre>
15313  * @singleton
15314  */
15315 Roo.state.Manager = function(){
15316     var provider = new Roo.state.Provider();
15317     
15318     return {
15319         /**
15320          * Configures the default state provider for your application
15321          * @param {Provider} stateProvider The state provider to set
15322          */
15323         setProvider : function(stateProvider){
15324             provider = stateProvider;
15325         },
15326         
15327         /**
15328          * Returns the current value for a key
15329          * @param {String} name The key name
15330          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15331          * @return {Mixed} The state data
15332          */
15333         get : function(key, defaultValue){
15334             return provider.get(key, defaultValue);
15335         },
15336         
15337         /**
15338          * Sets the value for a key
15339          * @param {String} name The key name
15340          * @param {Mixed} value The state data
15341          */
15342          set : function(key, value){
15343             provider.set(key, value);
15344         },
15345         
15346         /**
15347          * Clears a value from the state
15348          * @param {String} name The key name
15349          */
15350         clear : function(key){
15351             provider.clear(key);
15352         },
15353         
15354         /**
15355          * Gets the currently configured state provider
15356          * @return {Provider} The state provider
15357          */
15358         getProvider : function(){
15359             return provider;
15360         }
15361     };
15362 }();
15363 /*
15364  * Based on:
15365  * Ext JS Library 1.1.1
15366  * Copyright(c) 2006-2007, Ext JS, LLC.
15367  *
15368  * Originally Released Under LGPL - original licence link has changed is not relivant.
15369  *
15370  * Fork - LGPL
15371  * <script type="text/javascript">
15372  */
15373 /**
15374  * @class Roo.state.CookieProvider
15375  * @extends Roo.state.Provider
15376  * The default Provider implementation which saves state via cookies.
15377  * <br />Usage:
15378  <pre><code>
15379    var cp = new Roo.state.CookieProvider({
15380        path: "/cgi-bin/",
15381        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15382        domain: "roojs.com"
15383    })
15384    Roo.state.Manager.setProvider(cp);
15385  </code></pre>
15386  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15387  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15388  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15389  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15390  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15391  * domain the page is running on including the 'www' like 'www.roojs.com')
15392  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15393  * @constructor
15394  * Create a new CookieProvider
15395  * @param {Object} config The configuration object
15396  */
15397 Roo.state.CookieProvider = function(config){
15398     Roo.state.CookieProvider.superclass.constructor.call(this);
15399     this.path = "/";
15400     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15401     this.domain = null;
15402     this.secure = false;
15403     Roo.apply(this, config);
15404     this.state = this.readCookies();
15405 };
15406
15407 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15408     // private
15409     set : function(name, value){
15410         if(typeof value == "undefined" || value === null){
15411             this.clear(name);
15412             return;
15413         }
15414         this.setCookie(name, value);
15415         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15416     },
15417
15418     // private
15419     clear : function(name){
15420         this.clearCookie(name);
15421         Roo.state.CookieProvider.superclass.clear.call(this, name);
15422     },
15423
15424     // private
15425     readCookies : function(){
15426         var cookies = {};
15427         var c = document.cookie + ";";
15428         var re = /\s?(.*?)=(.*?);/g;
15429         var matches;
15430         while((matches = re.exec(c)) != null){
15431             var name = matches[1];
15432             var value = matches[2];
15433             if(name && name.substring(0,3) == "ys-"){
15434                 cookies[name.substr(3)] = this.decodeValue(value);
15435             }
15436         }
15437         return cookies;
15438     },
15439
15440     // private
15441     setCookie : function(name, value){
15442         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15443            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15444            ((this.path == null) ? "" : ("; path=" + this.path)) +
15445            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15446            ((this.secure == true) ? "; secure" : "");
15447     },
15448
15449     // private
15450     clearCookie : function(name){
15451         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15452            ((this.path == null) ? "" : ("; path=" + this.path)) +
15453            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15454            ((this.secure == true) ? "; secure" : "");
15455     }
15456 });/*
15457  * Based on:
15458  * Ext JS Library 1.1.1
15459  * Copyright(c) 2006-2007, Ext JS, LLC.
15460  *
15461  * Originally Released Under LGPL - original licence link has changed is not relivant.
15462  *
15463  * Fork - LGPL
15464  * <script type="text/javascript">
15465  */
15466  
15467
15468 /**
15469  * @class Roo.ComponentMgr
15470  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15471  * @singleton
15472  */
15473 Roo.ComponentMgr = function(){
15474     var all = new Roo.util.MixedCollection();
15475
15476     return {
15477         /**
15478          * Registers a component.
15479          * @param {Roo.Component} c The component
15480          */
15481         register : function(c){
15482             all.add(c);
15483         },
15484
15485         /**
15486          * Unregisters a component.
15487          * @param {Roo.Component} c The component
15488          */
15489         unregister : function(c){
15490             all.remove(c);
15491         },
15492
15493         /**
15494          * Returns a component by id
15495          * @param {String} id The component id
15496          */
15497         get : function(id){
15498             return all.get(id);
15499         },
15500
15501         /**
15502          * Registers a function that will be called when a specified component is added to ComponentMgr
15503          * @param {String} id The component id
15504          * @param {Funtction} fn The callback function
15505          * @param {Object} scope The scope of the callback
15506          */
15507         onAvailable : function(id, fn, scope){
15508             all.on("add", function(index, o){
15509                 if(o.id == id){
15510                     fn.call(scope || o, o);
15511                     all.un("add", fn, scope);
15512                 }
15513             });
15514         }
15515     };
15516 }();/*
15517  * Based on:
15518  * Ext JS Library 1.1.1
15519  * Copyright(c) 2006-2007, Ext JS, LLC.
15520  *
15521  * Originally Released Under LGPL - original licence link has changed is not relivant.
15522  *
15523  * Fork - LGPL
15524  * <script type="text/javascript">
15525  */
15526  
15527 /**
15528  * @class Roo.Component
15529  * @extends Roo.util.Observable
15530  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15531  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15532  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15533  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15534  * All visual components (widgets) that require rendering into a layout should subclass Component.
15535  * @constructor
15536  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15537  * 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
15538  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15539  */
15540 Roo.Component = function(config){
15541     config = config || {};
15542     if(config.tagName || config.dom || typeof config == "string"){ // element object
15543         config = {el: config, id: config.id || config};
15544     }
15545     this.initialConfig = config;
15546
15547     Roo.apply(this, config);
15548     this.addEvents({
15549         /**
15550          * @event disable
15551          * Fires after the component is disabled.
15552              * @param {Roo.Component} this
15553              */
15554         disable : true,
15555         /**
15556          * @event enable
15557          * Fires after the component is enabled.
15558              * @param {Roo.Component} this
15559              */
15560         enable : true,
15561         /**
15562          * @event beforeshow
15563          * Fires before the component is shown.  Return false to stop the show.
15564              * @param {Roo.Component} this
15565              */
15566         beforeshow : true,
15567         /**
15568          * @event show
15569          * Fires after the component is shown.
15570              * @param {Roo.Component} this
15571              */
15572         show : true,
15573         /**
15574          * @event beforehide
15575          * Fires before the component is hidden. Return false to stop the hide.
15576              * @param {Roo.Component} this
15577              */
15578         beforehide : true,
15579         /**
15580          * @event hide
15581          * Fires after the component is hidden.
15582              * @param {Roo.Component} this
15583              */
15584         hide : true,
15585         /**
15586          * @event beforerender
15587          * Fires before the component is rendered. Return false to stop the render.
15588              * @param {Roo.Component} this
15589              */
15590         beforerender : true,
15591         /**
15592          * @event render
15593          * Fires after the component is rendered.
15594              * @param {Roo.Component} this
15595              */
15596         render : true,
15597         /**
15598          * @event beforedestroy
15599          * Fires before the component is destroyed. Return false to stop the destroy.
15600              * @param {Roo.Component} this
15601              */
15602         beforedestroy : true,
15603         /**
15604          * @event destroy
15605          * Fires after the component is destroyed.
15606              * @param {Roo.Component} this
15607              */
15608         destroy : true
15609     });
15610     if(!this.id){
15611         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15612     }
15613     Roo.ComponentMgr.register(this);
15614     Roo.Component.superclass.constructor.call(this);
15615     this.initComponent();
15616     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15617         this.render(this.renderTo);
15618         delete this.renderTo;
15619     }
15620 };
15621
15622 /** @private */
15623 Roo.Component.AUTO_ID = 1000;
15624
15625 Roo.extend(Roo.Component, Roo.util.Observable, {
15626     /**
15627      * @scope Roo.Component.prototype
15628      * @type {Boolean}
15629      * true if this component is hidden. Read-only.
15630      */
15631     hidden : false,
15632     /**
15633      * @type {Boolean}
15634      * true if this component is disabled. Read-only.
15635      */
15636     disabled : false,
15637     /**
15638      * @type {Boolean}
15639      * true if this component has been rendered. Read-only.
15640      */
15641     rendered : false,
15642     
15643     /** @cfg {String} disableClass
15644      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15645      */
15646     disabledClass : "x-item-disabled",
15647         /** @cfg {Boolean} allowDomMove
15648          * Whether the component can move the Dom node when rendering (defaults to true).
15649          */
15650     allowDomMove : true,
15651     /** @cfg {String} hideMode (display|visibility)
15652      * How this component should hidden. Supported values are
15653      * "visibility" (css visibility), "offsets" (negative offset position) and
15654      * "display" (css display) - defaults to "display".
15655      */
15656     hideMode: 'display',
15657
15658     /** @private */
15659     ctype : "Roo.Component",
15660
15661     /**
15662      * @cfg {String} actionMode 
15663      * which property holds the element that used for  hide() / show() / disable() / enable()
15664      * default is 'el' for forms you probably want to set this to fieldEl 
15665      */
15666     actionMode : "el",
15667
15668     /** @private */
15669     getActionEl : function(){
15670         return this[this.actionMode];
15671     },
15672
15673     initComponent : Roo.emptyFn,
15674     /**
15675      * If this is a lazy rendering component, render it to its container element.
15676      * @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.
15677      */
15678     render : function(container, position){
15679         
15680         if(this.rendered){
15681             return this;
15682         }
15683         
15684         if(this.fireEvent("beforerender", this) === false){
15685             return false;
15686         }
15687         
15688         if(!container && this.el){
15689             this.el = Roo.get(this.el);
15690             container = this.el.dom.parentNode;
15691             this.allowDomMove = false;
15692         }
15693         this.container = Roo.get(container);
15694         this.rendered = true;
15695         if(position !== undefined){
15696             if(typeof position == 'number'){
15697                 position = this.container.dom.childNodes[position];
15698             }else{
15699                 position = Roo.getDom(position);
15700             }
15701         }
15702         this.onRender(this.container, position || null);
15703         if(this.cls){
15704             this.el.addClass(this.cls);
15705             delete this.cls;
15706         }
15707         if(this.style){
15708             this.el.applyStyles(this.style);
15709             delete this.style;
15710         }
15711         this.fireEvent("render", this);
15712         this.afterRender(this.container);
15713         if(this.hidden){
15714             this.hide();
15715         }
15716         if(this.disabled){
15717             this.disable();
15718         }
15719
15720         return this;
15721         
15722     },
15723
15724     /** @private */
15725     // default function is not really useful
15726     onRender : function(ct, position){
15727         if(this.el){
15728             this.el = Roo.get(this.el);
15729             if(this.allowDomMove !== false){
15730                 ct.dom.insertBefore(this.el.dom, position);
15731             }
15732         }
15733     },
15734
15735     /** @private */
15736     getAutoCreate : function(){
15737         var cfg = typeof this.autoCreate == "object" ?
15738                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15739         if(this.id && !cfg.id){
15740             cfg.id = this.id;
15741         }
15742         return cfg;
15743     },
15744
15745     /** @private */
15746     afterRender : Roo.emptyFn,
15747
15748     /**
15749      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15750      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15751      */
15752     destroy : function(){
15753         if(this.fireEvent("beforedestroy", this) !== false){
15754             this.purgeListeners();
15755             this.beforeDestroy();
15756             if(this.rendered){
15757                 this.el.removeAllListeners();
15758                 this.el.remove();
15759                 if(this.actionMode == "container"){
15760                     this.container.remove();
15761                 }
15762             }
15763             this.onDestroy();
15764             Roo.ComponentMgr.unregister(this);
15765             this.fireEvent("destroy", this);
15766         }
15767     },
15768
15769         /** @private */
15770     beforeDestroy : function(){
15771
15772     },
15773
15774         /** @private */
15775         onDestroy : function(){
15776
15777     },
15778
15779     /**
15780      * Returns the underlying {@link Roo.Element}.
15781      * @return {Roo.Element} The element
15782      */
15783     getEl : function(){
15784         return this.el;
15785     },
15786
15787     /**
15788      * Returns the id of this component.
15789      * @return {String}
15790      */
15791     getId : function(){
15792         return this.id;
15793     },
15794
15795     /**
15796      * Try to focus this component.
15797      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15798      * @return {Roo.Component} this
15799      */
15800     focus : function(selectText){
15801         if(this.rendered){
15802             this.el.focus();
15803             if(selectText === true){
15804                 this.el.dom.select();
15805             }
15806         }
15807         return this;
15808     },
15809
15810     /** @private */
15811     blur : function(){
15812         if(this.rendered){
15813             this.el.blur();
15814         }
15815         return this;
15816     },
15817
15818     /**
15819      * Disable this component.
15820      * @return {Roo.Component} this
15821      */
15822     disable : function(){
15823         if(this.rendered){
15824             this.onDisable();
15825         }
15826         this.disabled = true;
15827         this.fireEvent("disable", this);
15828         return this;
15829     },
15830
15831         // private
15832     onDisable : function(){
15833         this.getActionEl().addClass(this.disabledClass);
15834         this.el.dom.disabled = true;
15835     },
15836
15837     /**
15838      * Enable this component.
15839      * @return {Roo.Component} this
15840      */
15841     enable : function(){
15842         if(this.rendered){
15843             this.onEnable();
15844         }
15845         this.disabled = false;
15846         this.fireEvent("enable", this);
15847         return this;
15848     },
15849
15850         // private
15851     onEnable : function(){
15852         this.getActionEl().removeClass(this.disabledClass);
15853         this.el.dom.disabled = false;
15854     },
15855
15856     /**
15857      * Convenience function for setting disabled/enabled by boolean.
15858      * @param {Boolean} disabled
15859      */
15860     setDisabled : function(disabled){
15861         this[disabled ? "disable" : "enable"]();
15862     },
15863
15864     /**
15865      * Show this component.
15866      * @return {Roo.Component} this
15867      */
15868     show: function(){
15869         if(this.fireEvent("beforeshow", this) !== false){
15870             this.hidden = false;
15871             if(this.rendered){
15872                 this.onShow();
15873             }
15874             this.fireEvent("show", this);
15875         }
15876         return this;
15877     },
15878
15879     // private
15880     onShow : function(){
15881         var ae = this.getActionEl();
15882         if(this.hideMode == 'visibility'){
15883             ae.dom.style.visibility = "visible";
15884         }else if(this.hideMode == 'offsets'){
15885             ae.removeClass('x-hidden');
15886         }else{
15887             ae.dom.style.display = "";
15888         }
15889     },
15890
15891     /**
15892      * Hide this component.
15893      * @return {Roo.Component} this
15894      */
15895     hide: function(){
15896         if(this.fireEvent("beforehide", this) !== false){
15897             this.hidden = true;
15898             if(this.rendered){
15899                 this.onHide();
15900             }
15901             this.fireEvent("hide", this);
15902         }
15903         return this;
15904     },
15905
15906     // private
15907     onHide : function(){
15908         var ae = this.getActionEl();
15909         if(this.hideMode == 'visibility'){
15910             ae.dom.style.visibility = "hidden";
15911         }else if(this.hideMode == 'offsets'){
15912             ae.addClass('x-hidden');
15913         }else{
15914             ae.dom.style.display = "none";
15915         }
15916     },
15917
15918     /**
15919      * Convenience function to hide or show this component by boolean.
15920      * @param {Boolean} visible True to show, false to hide
15921      * @return {Roo.Component} this
15922      */
15923     setVisible: function(visible){
15924         if(visible) {
15925             this.show();
15926         }else{
15927             this.hide();
15928         }
15929         return this;
15930     },
15931
15932     /**
15933      * Returns true if this component is visible.
15934      */
15935     isVisible : function(){
15936         return this.getActionEl().isVisible();
15937     },
15938
15939     cloneConfig : function(overrides){
15940         overrides = overrides || {};
15941         var id = overrides.id || Roo.id();
15942         var cfg = Roo.applyIf(overrides, this.initialConfig);
15943         cfg.id = id; // prevent dup id
15944         return new this.constructor(cfg);
15945     }
15946 });/*
15947  * Based on:
15948  * Ext JS Library 1.1.1
15949  * Copyright(c) 2006-2007, Ext JS, LLC.
15950  *
15951  * Originally Released Under LGPL - original licence link has changed is not relivant.
15952  *
15953  * Fork - LGPL
15954  * <script type="text/javascript">
15955  */
15956
15957 /**
15958  * @class Roo.BoxComponent
15959  * @extends Roo.Component
15960  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15961  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15962  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
15963  * layout containers.
15964  * @constructor
15965  * @param {Roo.Element/String/Object} config The configuration options.
15966  */
15967 Roo.BoxComponent = function(config){
15968     Roo.Component.call(this, config);
15969     this.addEvents({
15970         /**
15971          * @event resize
15972          * Fires after the component is resized.
15973              * @param {Roo.Component} this
15974              * @param {Number} adjWidth The box-adjusted width that was set
15975              * @param {Number} adjHeight The box-adjusted height that was set
15976              * @param {Number} rawWidth The width that was originally specified
15977              * @param {Number} rawHeight The height that was originally specified
15978              */
15979         resize : true,
15980         /**
15981          * @event move
15982          * Fires after the component is moved.
15983              * @param {Roo.Component} this
15984              * @param {Number} x The new x position
15985              * @param {Number} y The new y position
15986              */
15987         move : true
15988     });
15989 };
15990
15991 Roo.extend(Roo.BoxComponent, Roo.Component, {
15992     // private, set in afterRender to signify that the component has been rendered
15993     boxReady : false,
15994     // private, used to defer height settings to subclasses
15995     deferHeight: false,
15996     /** @cfg {Number} width
15997      * width (optional) size of component
15998      */
15999      /** @cfg {Number} height
16000      * height (optional) size of component
16001      */
16002      
16003     /**
16004      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
16005      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16006      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16007      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16008      * @return {Roo.BoxComponent} this
16009      */
16010     setSize : function(w, h){
16011         // support for standard size objects
16012         if(typeof w == 'object'){
16013             h = w.height;
16014             w = w.width;
16015         }
16016         // not rendered
16017         if(!this.boxReady){
16018             this.width = w;
16019             this.height = h;
16020             return this;
16021         }
16022
16023         // prevent recalcs when not needed
16024         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16025             return this;
16026         }
16027         this.lastSize = {width: w, height: h};
16028
16029         var adj = this.adjustSize(w, h);
16030         var aw = adj.width, ah = adj.height;
16031         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16032             var rz = this.getResizeEl();
16033             if(!this.deferHeight && aw !== undefined && ah !== undefined){
16034                 rz.setSize(aw, ah);
16035             }else if(!this.deferHeight && ah !== undefined){
16036                 rz.setHeight(ah);
16037             }else if(aw !== undefined){
16038                 rz.setWidth(aw);
16039             }
16040             this.onResize(aw, ah, w, h);
16041             this.fireEvent('resize', this, aw, ah, w, h);
16042         }
16043         return this;
16044     },
16045
16046     /**
16047      * Gets the current size of the component's underlying element.
16048      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16049      */
16050     getSize : function(){
16051         return this.el.getSize();
16052     },
16053
16054     /**
16055      * Gets the current XY position of the component's underlying element.
16056      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16057      * @return {Array} The XY position of the element (e.g., [100, 200])
16058      */
16059     getPosition : function(local){
16060         if(local === true){
16061             return [this.el.getLeft(true), this.el.getTop(true)];
16062         }
16063         return this.xy || this.el.getXY();
16064     },
16065
16066     /**
16067      * Gets the current box measurements of the component's underlying element.
16068      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16069      * @returns {Object} box An object in the format {x, y, width, height}
16070      */
16071     getBox : function(local){
16072         var s = this.el.getSize();
16073         if(local){
16074             s.x = this.el.getLeft(true);
16075             s.y = this.el.getTop(true);
16076         }else{
16077             var xy = this.xy || this.el.getXY();
16078             s.x = xy[0];
16079             s.y = xy[1];
16080         }
16081         return s;
16082     },
16083
16084     /**
16085      * Sets the current box measurements of the component's underlying element.
16086      * @param {Object} box An object in the format {x, y, width, height}
16087      * @returns {Roo.BoxComponent} this
16088      */
16089     updateBox : function(box){
16090         this.setSize(box.width, box.height);
16091         this.setPagePosition(box.x, box.y);
16092         return this;
16093     },
16094
16095     // protected
16096     getResizeEl : function(){
16097         return this.resizeEl || this.el;
16098     },
16099
16100     // protected
16101     getPositionEl : function(){
16102         return this.positionEl || this.el;
16103     },
16104
16105     /**
16106      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
16107      * This method fires the move event.
16108      * @param {Number} left The new left
16109      * @param {Number} top The new top
16110      * @returns {Roo.BoxComponent} this
16111      */
16112     setPosition : function(x, y){
16113         this.x = x;
16114         this.y = y;
16115         if(!this.boxReady){
16116             return this;
16117         }
16118         var adj = this.adjustPosition(x, y);
16119         var ax = adj.x, ay = adj.y;
16120
16121         var el = this.getPositionEl();
16122         if(ax !== undefined || ay !== undefined){
16123             if(ax !== undefined && ay !== undefined){
16124                 el.setLeftTop(ax, ay);
16125             }else if(ax !== undefined){
16126                 el.setLeft(ax);
16127             }else if(ay !== undefined){
16128                 el.setTop(ay);
16129             }
16130             this.onPosition(ax, ay);
16131             this.fireEvent('move', this, ax, ay);
16132         }
16133         return this;
16134     },
16135
16136     /**
16137      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
16138      * This method fires the move event.
16139      * @param {Number} x The new x position
16140      * @param {Number} y The new y position
16141      * @returns {Roo.BoxComponent} this
16142      */
16143     setPagePosition : function(x, y){
16144         this.pageX = x;
16145         this.pageY = y;
16146         if(!this.boxReady){
16147             return;
16148         }
16149         if(x === undefined || y === undefined){ // cannot translate undefined points
16150             return;
16151         }
16152         var p = this.el.translatePoints(x, y);
16153         this.setPosition(p.left, p.top);
16154         return this;
16155     },
16156
16157     // private
16158     onRender : function(ct, position){
16159         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16160         if(this.resizeEl){
16161             this.resizeEl = Roo.get(this.resizeEl);
16162         }
16163         if(this.positionEl){
16164             this.positionEl = Roo.get(this.positionEl);
16165         }
16166     },
16167
16168     // private
16169     afterRender : function(){
16170         Roo.BoxComponent.superclass.afterRender.call(this);
16171         this.boxReady = true;
16172         this.setSize(this.width, this.height);
16173         if(this.x || this.y){
16174             this.setPosition(this.x, this.y);
16175         }
16176         if(this.pageX || this.pageY){
16177             this.setPagePosition(this.pageX, this.pageY);
16178         }
16179     },
16180
16181     /**
16182      * Force the component's size to recalculate based on the underlying element's current height and width.
16183      * @returns {Roo.BoxComponent} this
16184      */
16185     syncSize : function(){
16186         delete this.lastSize;
16187         this.setSize(this.el.getWidth(), this.el.getHeight());
16188         return this;
16189     },
16190
16191     /**
16192      * Called after the component is resized, this method is empty by default but can be implemented by any
16193      * subclass that needs to perform custom logic after a resize occurs.
16194      * @param {Number} adjWidth The box-adjusted width that was set
16195      * @param {Number} adjHeight The box-adjusted height that was set
16196      * @param {Number} rawWidth The width that was originally specified
16197      * @param {Number} rawHeight The height that was originally specified
16198      */
16199     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16200
16201     },
16202
16203     /**
16204      * Called after the component is moved, this method is empty by default but can be implemented by any
16205      * subclass that needs to perform custom logic after a move occurs.
16206      * @param {Number} x The new x position
16207      * @param {Number} y The new y position
16208      */
16209     onPosition : function(x, y){
16210
16211     },
16212
16213     // private
16214     adjustSize : function(w, h){
16215         if(this.autoWidth){
16216             w = 'auto';
16217         }
16218         if(this.autoHeight){
16219             h = 'auto';
16220         }
16221         return {width : w, height: h};
16222     },
16223
16224     // private
16225     adjustPosition : function(x, y){
16226         return {x : x, y: y};
16227     }
16228 });/*
16229  * Based on:
16230  * Ext JS Library 1.1.1
16231  * Copyright(c) 2006-2007, Ext JS, LLC.
16232  *
16233  * Originally Released Under LGPL - original licence link has changed is not relivant.
16234  *
16235  * Fork - LGPL
16236  * <script type="text/javascript">
16237  */
16238  (function(){ 
16239 /**
16240  * @class Roo.Layer
16241  * @extends Roo.Element
16242  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16243  * automatic maintaining of shadow/shim positions.
16244  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16245  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16246  * you can pass a string with a CSS class name. False turns off the shadow.
16247  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16248  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16249  * @cfg {String} cls CSS class to add to the element
16250  * @cfg {Number} zindex Starting z-index (defaults to 11000)
16251  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16252  * @constructor
16253  * @param {Object} config An object with config options.
16254  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16255  */
16256
16257 Roo.Layer = function(config, existingEl){
16258     config = config || {};
16259     var dh = Roo.DomHelper;
16260     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16261     if(existingEl){
16262         this.dom = Roo.getDom(existingEl);
16263     }
16264     if(!this.dom){
16265         var o = config.dh || {tag: "div", cls: "x-layer"};
16266         this.dom = dh.append(pel, o);
16267     }
16268     if(config.cls){
16269         this.addClass(config.cls);
16270     }
16271     this.constrain = config.constrain !== false;
16272     this.visibilityMode = Roo.Element.VISIBILITY;
16273     if(config.id){
16274         this.id = this.dom.id = config.id;
16275     }else{
16276         this.id = Roo.id(this.dom);
16277     }
16278     this.zindex = config.zindex || this.getZIndex();
16279     this.position("absolute", this.zindex);
16280     if(config.shadow){
16281         this.shadowOffset = config.shadowOffset || 4;
16282         this.shadow = new Roo.Shadow({
16283             offset : this.shadowOffset,
16284             mode : config.shadow
16285         });
16286     }else{
16287         this.shadowOffset = 0;
16288     }
16289     this.useShim = config.shim !== false && Roo.useShims;
16290     this.useDisplay = config.useDisplay;
16291     this.hide();
16292 };
16293
16294 var supr = Roo.Element.prototype;
16295
16296 // shims are shared among layer to keep from having 100 iframes
16297 var shims = [];
16298
16299 Roo.extend(Roo.Layer, Roo.Element, {
16300
16301     getZIndex : function(){
16302         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16303     },
16304
16305     getShim : function(){
16306         if(!this.useShim){
16307             return null;
16308         }
16309         if(this.shim){
16310             return this.shim;
16311         }
16312         var shim = shims.shift();
16313         if(!shim){
16314             shim = this.createShim();
16315             shim.enableDisplayMode('block');
16316             shim.dom.style.display = 'none';
16317             shim.dom.style.visibility = 'visible';
16318         }
16319         var pn = this.dom.parentNode;
16320         if(shim.dom.parentNode != pn){
16321             pn.insertBefore(shim.dom, this.dom);
16322         }
16323         shim.setStyle('z-index', this.getZIndex()-2);
16324         this.shim = shim;
16325         return shim;
16326     },
16327
16328     hideShim : function(){
16329         if(this.shim){
16330             this.shim.setDisplayed(false);
16331             shims.push(this.shim);
16332             delete this.shim;
16333         }
16334     },
16335
16336     disableShadow : function(){
16337         if(this.shadow){
16338             this.shadowDisabled = true;
16339             this.shadow.hide();
16340             this.lastShadowOffset = this.shadowOffset;
16341             this.shadowOffset = 0;
16342         }
16343     },
16344
16345     enableShadow : function(show){
16346         if(this.shadow){
16347             this.shadowDisabled = false;
16348             this.shadowOffset = this.lastShadowOffset;
16349             delete this.lastShadowOffset;
16350             if(show){
16351                 this.sync(true);
16352             }
16353         }
16354     },
16355
16356     // private
16357     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16358     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16359     sync : function(doShow){
16360         var sw = this.shadow;
16361         if(!this.updating && this.isVisible() && (sw || this.useShim)){
16362             var sh = this.getShim();
16363
16364             var w = this.getWidth(),
16365                 h = this.getHeight();
16366
16367             var l = this.getLeft(true),
16368                 t = this.getTop(true);
16369
16370             if(sw && !this.shadowDisabled){
16371                 if(doShow && !sw.isVisible()){
16372                     sw.show(this);
16373                 }else{
16374                     sw.realign(l, t, w, h);
16375                 }
16376                 if(sh){
16377                     if(doShow){
16378                        sh.show();
16379                     }
16380                     // fit the shim behind the shadow, so it is shimmed too
16381                     var a = sw.adjusts, s = sh.dom.style;
16382                     s.left = (Math.min(l, l+a.l))+"px";
16383                     s.top = (Math.min(t, t+a.t))+"px";
16384                     s.width = (w+a.w)+"px";
16385                     s.height = (h+a.h)+"px";
16386                 }
16387             }else if(sh){
16388                 if(doShow){
16389                    sh.show();
16390                 }
16391                 sh.setSize(w, h);
16392                 sh.setLeftTop(l, t);
16393             }
16394             
16395         }
16396     },
16397
16398     // private
16399     destroy : function(){
16400         this.hideShim();
16401         if(this.shadow){
16402             this.shadow.hide();
16403         }
16404         this.removeAllListeners();
16405         var pn = this.dom.parentNode;
16406         if(pn){
16407             pn.removeChild(this.dom);
16408         }
16409         Roo.Element.uncache(this.id);
16410     },
16411
16412     remove : function(){
16413         this.destroy();
16414     },
16415
16416     // private
16417     beginUpdate : function(){
16418         this.updating = true;
16419     },
16420
16421     // private
16422     endUpdate : function(){
16423         this.updating = false;
16424         this.sync(true);
16425     },
16426
16427     // private
16428     hideUnders : function(negOffset){
16429         if(this.shadow){
16430             this.shadow.hide();
16431         }
16432         this.hideShim();
16433     },
16434
16435     // private
16436     constrainXY : function(){
16437         if(this.constrain){
16438             var vw = Roo.lib.Dom.getViewWidth(),
16439                 vh = Roo.lib.Dom.getViewHeight();
16440             var s = Roo.get(document).getScroll();
16441
16442             var xy = this.getXY();
16443             var x = xy[0], y = xy[1];   
16444             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16445             // only move it if it needs it
16446             var moved = false;
16447             // first validate right/bottom
16448             if((x + w) > vw+s.left){
16449                 x = vw - w - this.shadowOffset;
16450                 moved = true;
16451             }
16452             if((y + h) > vh+s.top){
16453                 y = vh - h - this.shadowOffset;
16454                 moved = true;
16455             }
16456             // then make sure top/left isn't negative
16457             if(x < s.left){
16458                 x = s.left;
16459                 moved = true;
16460             }
16461             if(y < s.top){
16462                 y = s.top;
16463                 moved = true;
16464             }
16465             if(moved){
16466                 if(this.avoidY){
16467                     var ay = this.avoidY;
16468                     if(y <= ay && (y+h) >= ay){
16469                         y = ay-h-5;   
16470                     }
16471                 }
16472                 xy = [x, y];
16473                 this.storeXY(xy);
16474                 supr.setXY.call(this, xy);
16475                 this.sync();
16476             }
16477         }
16478     },
16479
16480     isVisible : function(){
16481         return this.visible;    
16482     },
16483
16484     // private
16485     showAction : function(){
16486         this.visible = true; // track visibility to prevent getStyle calls
16487         if(this.useDisplay === true){
16488             this.setDisplayed("");
16489         }else if(this.lastXY){
16490             supr.setXY.call(this, this.lastXY);
16491         }else if(this.lastLT){
16492             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16493         }
16494     },
16495
16496     // private
16497     hideAction : function(){
16498         this.visible = false;
16499         if(this.useDisplay === true){
16500             this.setDisplayed(false);
16501         }else{
16502             this.setLeftTop(-10000,-10000);
16503         }
16504     },
16505
16506     // overridden Element method
16507     setVisible : function(v, a, d, c, e){
16508         if(v){
16509             this.showAction();
16510         }
16511         if(a && v){
16512             var cb = function(){
16513                 this.sync(true);
16514                 if(c){
16515                     c();
16516                 }
16517             }.createDelegate(this);
16518             supr.setVisible.call(this, true, true, d, cb, e);
16519         }else{
16520             if(!v){
16521                 this.hideUnders(true);
16522             }
16523             var cb = c;
16524             if(a){
16525                 cb = function(){
16526                     this.hideAction();
16527                     if(c){
16528                         c();
16529                     }
16530                 }.createDelegate(this);
16531             }
16532             supr.setVisible.call(this, v, a, d, cb, e);
16533             if(v){
16534                 this.sync(true);
16535             }else if(!a){
16536                 this.hideAction();
16537             }
16538         }
16539     },
16540
16541     storeXY : function(xy){
16542         delete this.lastLT;
16543         this.lastXY = xy;
16544     },
16545
16546     storeLeftTop : function(left, top){
16547         delete this.lastXY;
16548         this.lastLT = [left, top];
16549     },
16550
16551     // private
16552     beforeFx : function(){
16553         this.beforeAction();
16554         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16555     },
16556
16557     // private
16558     afterFx : function(){
16559         Roo.Layer.superclass.afterFx.apply(this, arguments);
16560         this.sync(this.isVisible());
16561     },
16562
16563     // private
16564     beforeAction : function(){
16565         if(!this.updating && this.shadow){
16566             this.shadow.hide();
16567         }
16568     },
16569
16570     // overridden Element method
16571     setLeft : function(left){
16572         this.storeLeftTop(left, this.getTop(true));
16573         supr.setLeft.apply(this, arguments);
16574         this.sync();
16575     },
16576
16577     setTop : function(top){
16578         this.storeLeftTop(this.getLeft(true), top);
16579         supr.setTop.apply(this, arguments);
16580         this.sync();
16581     },
16582
16583     setLeftTop : function(left, top){
16584         this.storeLeftTop(left, top);
16585         supr.setLeftTop.apply(this, arguments);
16586         this.sync();
16587     },
16588
16589     setXY : function(xy, a, d, c, e){
16590         this.fixDisplay();
16591         this.beforeAction();
16592         this.storeXY(xy);
16593         var cb = this.createCB(c);
16594         supr.setXY.call(this, xy, a, d, cb, e);
16595         if(!a){
16596             cb();
16597         }
16598     },
16599
16600     // private
16601     createCB : function(c){
16602         var el = this;
16603         return function(){
16604             el.constrainXY();
16605             el.sync(true);
16606             if(c){
16607                 c();
16608             }
16609         };
16610     },
16611
16612     // overridden Element method
16613     setX : function(x, a, d, c, e){
16614         this.setXY([x, this.getY()], a, d, c, e);
16615     },
16616
16617     // overridden Element method
16618     setY : function(y, a, d, c, e){
16619         this.setXY([this.getX(), y], a, d, c, e);
16620     },
16621
16622     // overridden Element method
16623     setSize : function(w, h, a, d, c, e){
16624         this.beforeAction();
16625         var cb = this.createCB(c);
16626         supr.setSize.call(this, w, h, a, d, cb, e);
16627         if(!a){
16628             cb();
16629         }
16630     },
16631
16632     // overridden Element method
16633     setWidth : function(w, a, d, c, e){
16634         this.beforeAction();
16635         var cb = this.createCB(c);
16636         supr.setWidth.call(this, w, a, d, cb, e);
16637         if(!a){
16638             cb();
16639         }
16640     },
16641
16642     // overridden Element method
16643     setHeight : function(h, a, d, c, e){
16644         this.beforeAction();
16645         var cb = this.createCB(c);
16646         supr.setHeight.call(this, h, a, d, cb, e);
16647         if(!a){
16648             cb();
16649         }
16650     },
16651
16652     // overridden Element method
16653     setBounds : function(x, y, w, h, a, d, c, e){
16654         this.beforeAction();
16655         var cb = this.createCB(c);
16656         if(!a){
16657             this.storeXY([x, y]);
16658             supr.setXY.call(this, [x, y]);
16659             supr.setSize.call(this, w, h, a, d, cb, e);
16660             cb();
16661         }else{
16662             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16663         }
16664         return this;
16665     },
16666     
16667     /**
16668      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16669      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16670      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16671      * @param {Number} zindex The new z-index to set
16672      * @return {this} The Layer
16673      */
16674     setZIndex : function(zindex){
16675         this.zindex = zindex;
16676         this.setStyle("z-index", zindex + 2);
16677         if(this.shadow){
16678             this.shadow.setZIndex(zindex + 1);
16679         }
16680         if(this.shim){
16681             this.shim.setStyle("z-index", zindex);
16682         }
16683     }
16684 });
16685 })();/*
16686  * Original code for Roojs - LGPL
16687  * <script type="text/javascript">
16688  */
16689  
16690 /**
16691  * @class Roo.XComponent
16692  * A delayed Element creator...
16693  * Or a way to group chunks of interface together.
16694  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16695  *  used in conjunction with XComponent.build() it will create an instance of each element,
16696  *  then call addxtype() to build the User interface.
16697  * 
16698  * Mypart.xyx = new Roo.XComponent({
16699
16700     parent : 'Mypart.xyz', // empty == document.element.!!
16701     order : '001',
16702     name : 'xxxx'
16703     region : 'xxxx'
16704     disabled : function() {} 
16705      
16706     tree : function() { // return an tree of xtype declared components
16707         var MODULE = this;
16708         return 
16709         {
16710             xtype : 'NestedLayoutPanel',
16711             // technicall
16712         }
16713      ]
16714  *})
16715  *
16716  *
16717  * It can be used to build a big heiracy, with parent etc.
16718  * or you can just use this to render a single compoent to a dom element
16719  * MYPART.render(Roo.Element | String(id) | dom_element )
16720  *
16721  *
16722  * Usage patterns.
16723  *
16724  * Classic Roo
16725  *
16726  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16727  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16728  *
16729  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16730  *
16731  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16732  * - if mulitple topModules exist, the last one is defined as the top module.
16733  *
16734  * Embeded Roo
16735  * 
16736  * When the top level or multiple modules are to embedded into a existing HTML page,
16737  * the parent element can container '#id' of the element where the module will be drawn.
16738  *
16739  * Bootstrap Roo
16740  *
16741  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16742  * it relies more on a include mechanism, where sub modules are included into an outer page.
16743  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16744  * 
16745  * Bootstrap Roo Included elements
16746  *
16747  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16748  * hence confusing the component builder as it thinks there are multiple top level elements. 
16749  *
16750  * String Over-ride & Translations
16751  *
16752  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16753  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16754  * are needed. @see Roo.XComponent.overlayString  
16755  * 
16756  * 
16757  * 
16758  * @extends Roo.util.Observable
16759  * @constructor
16760  * @param cfg {Object} configuration of component
16761  * 
16762  */
16763 Roo.XComponent = function(cfg) {
16764     Roo.apply(this, cfg);
16765     this.addEvents({ 
16766         /**
16767              * @event built
16768              * Fires when this the componnt is built
16769              * @param {Roo.XComponent} c the component
16770              */
16771         'built' : true
16772         
16773     });
16774     this.region = this.region || 'center'; // default..
16775     Roo.XComponent.register(this);
16776     this.modules = false;
16777     this.el = false; // where the layout goes..
16778     
16779     
16780 }
16781 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16782     /**
16783      * @property el
16784      * The created element (with Roo.factory())
16785      * @type {Roo.Layout}
16786      */
16787     el  : false,
16788     
16789     /**
16790      * @property el
16791      * for BC  - use el in new code
16792      * @type {Roo.Layout}
16793      */
16794     panel : false,
16795     
16796     /**
16797      * @property layout
16798      * for BC  - use el in new code
16799      * @type {Roo.Layout}
16800      */
16801     layout : false,
16802     
16803      /**
16804      * @cfg {Function|boolean} disabled
16805      * If this module is disabled by some rule, return true from the funtion
16806      */
16807     disabled : false,
16808     
16809     /**
16810      * @cfg {String} parent 
16811      * Name of parent element which it get xtype added to..
16812      */
16813     parent: false,
16814     
16815     /**
16816      * @cfg {String} order
16817      * Used to set the order in which elements are created (usefull for multiple tabs)
16818      */
16819     
16820     order : false,
16821     /**
16822      * @cfg {String} name
16823      * String to display while loading.
16824      */
16825     name : false,
16826     /**
16827      * @cfg {String} region
16828      * Region to render component to (defaults to center)
16829      */
16830     region : 'center',
16831     
16832     /**
16833      * @cfg {Array} items
16834      * A single item array - the first element is the root of the tree..
16835      * It's done this way to stay compatible with the Xtype system...
16836      */
16837     items : false,
16838     
16839     /**
16840      * @property _tree
16841      * The method that retuns the tree of parts that make up this compoennt 
16842      * @type {function}
16843      */
16844     _tree  : false,
16845     
16846      /**
16847      * render
16848      * render element to dom or tree
16849      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16850      */
16851     
16852     render : function(el)
16853     {
16854         
16855         el = el || false;
16856         var hp = this.parent ? 1 : 0;
16857         Roo.debug &&  Roo.log(this);
16858         
16859         var tree = this._tree ? this._tree() : this.tree();
16860
16861         
16862         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16863             // if parent is a '#.....' string, then let's use that..
16864             var ename = this.parent.substr(1);
16865             this.parent = false;
16866             Roo.debug && Roo.log(ename);
16867             switch (ename) {
16868                 case 'bootstrap-body':
16869                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16870                         // this is the BorderLayout standard?
16871                        this.parent = { el : true };
16872                        break;
16873                     }
16874                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16875                         // need to insert stuff...
16876                         this.parent =  {
16877                              el : new Roo.bootstrap.layout.Border({
16878                                  el : document.body, 
16879                      
16880                                  center: {
16881                                     titlebar: false,
16882                                     autoScroll:false,
16883                                     closeOnTab: true,
16884                                     tabPosition: 'top',
16885                                       //resizeTabs: true,
16886                                     alwaysShowTabs: true,
16887                                     hideTabs: false
16888                                      //minTabWidth: 140
16889                                  }
16890                              })
16891                         
16892                          };
16893                          break;
16894                     }
16895                          
16896                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16897                         this.parent = { el :  new  Roo.bootstrap.Body() };
16898                         Roo.debug && Roo.log("setting el to doc body");
16899                          
16900                     } else {
16901                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16902                     }
16903                     break;
16904                 case 'bootstrap':
16905                     this.parent = { el : true};
16906                     // fall through
16907                 default:
16908                     el = Roo.get(ename);
16909                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16910                         this.parent = { el : true};
16911                     }
16912                     
16913                     break;
16914             }
16915                 
16916             
16917             if (!el && !this.parent) {
16918                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16919                 return;
16920             }
16921         }
16922         
16923         Roo.debug && Roo.log("EL:");
16924         Roo.debug && Roo.log(el);
16925         Roo.debug && Roo.log("this.parent.el:");
16926         Roo.debug && Roo.log(this.parent.el);
16927         
16928
16929         // altertive root elements ??? - we need a better way to indicate these.
16930         var is_alt = Roo.XComponent.is_alt ||
16931                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16932                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16933                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16934         
16935         
16936         
16937         if (!this.parent && is_alt) {
16938             //el = Roo.get(document.body);
16939             this.parent = { el : true };
16940         }
16941             
16942             
16943         
16944         if (!this.parent) {
16945             
16946             Roo.debug && Roo.log("no parent - creating one");
16947             
16948             el = el ? Roo.get(el) : false;      
16949             
16950             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16951                 
16952                 this.parent =  {
16953                     el : new Roo.bootstrap.layout.Border({
16954                         el: el || document.body,
16955                     
16956                         center: {
16957                             titlebar: false,
16958                             autoScroll:false,
16959                             closeOnTab: true,
16960                             tabPosition: 'top',
16961                              //resizeTabs: true,
16962                             alwaysShowTabs: false,
16963                             hideTabs: true,
16964                             minTabWidth: 140,
16965                             overflow: 'visible'
16966                          }
16967                      })
16968                 };
16969             } else {
16970             
16971                 // it's a top level one..
16972                 this.parent =  {
16973                     el : new Roo.BorderLayout(el || document.body, {
16974                         center: {
16975                             titlebar: false,
16976                             autoScroll:false,
16977                             closeOnTab: true,
16978                             tabPosition: 'top',
16979                              //resizeTabs: true,
16980                             alwaysShowTabs: el && hp? false :  true,
16981                             hideTabs: el || !hp ? true :  false,
16982                             minTabWidth: 140
16983                          }
16984                     })
16985                 };
16986             }
16987         }
16988         
16989         if (!this.parent.el) {
16990                 // probably an old style ctor, which has been disabled.
16991                 return;
16992
16993         }
16994                 // The 'tree' method is  '_tree now' 
16995             
16996         tree.region = tree.region || this.region;
16997         var is_body = false;
16998         if (this.parent.el === true) {
16999             // bootstrap... - body..
17000             if (el) {
17001                 tree.el = el;
17002             }
17003             this.parent.el = Roo.factory(tree);
17004             is_body = true;
17005         }
17006         
17007         this.el = this.parent.el.addxtype(tree, undefined, is_body);
17008         this.fireEvent('built', this);
17009         
17010         this.panel = this.el;
17011         this.layout = this.panel.layout;
17012         this.parentLayout = this.parent.layout  || false;  
17013          
17014     }
17015     
17016 });
17017
17018 Roo.apply(Roo.XComponent, {
17019     /**
17020      * @property  hideProgress
17021      * true to disable the building progress bar.. usefull on single page renders.
17022      * @type Boolean
17023      */
17024     hideProgress : false,
17025     /**
17026      * @property  buildCompleted
17027      * True when the builder has completed building the interface.
17028      * @type Boolean
17029      */
17030     buildCompleted : false,
17031      
17032     /**
17033      * @property  topModule
17034      * the upper most module - uses document.element as it's constructor.
17035      * @type Object
17036      */
17037      
17038     topModule  : false,
17039       
17040     /**
17041      * @property  modules
17042      * array of modules to be created by registration system.
17043      * @type {Array} of Roo.XComponent
17044      */
17045     
17046     modules : [],
17047     /**
17048      * @property  elmodules
17049      * array of modules to be created by which use #ID 
17050      * @type {Array} of Roo.XComponent
17051      */
17052      
17053     elmodules : [],
17054
17055      /**
17056      * @property  is_alt
17057      * Is an alternative Root - normally used by bootstrap or other systems,
17058      *    where the top element in the tree can wrap 'body' 
17059      * @type {boolean}  (default false)
17060      */
17061      
17062     is_alt : false,
17063     /**
17064      * @property  build_from_html
17065      * Build elements from html - used by bootstrap HTML stuff 
17066      *    - this is cleared after build is completed
17067      * @type {boolean}    (default false)
17068      */
17069      
17070     build_from_html : false,
17071     /**
17072      * Register components to be built later.
17073      *
17074      * This solves the following issues
17075      * - Building is not done on page load, but after an authentication process has occured.
17076      * - Interface elements are registered on page load
17077      * - Parent Interface elements may not be loaded before child, so this handles that..
17078      * 
17079      *
17080      * example:
17081      * 
17082      * MyApp.register({
17083           order : '000001',
17084           module : 'Pman.Tab.projectMgr',
17085           region : 'center',
17086           parent : 'Pman.layout',
17087           disabled : false,  // or use a function..
17088         })
17089      
17090      * * @param {Object} details about module
17091      */
17092     register : function(obj) {
17093                 
17094         Roo.XComponent.event.fireEvent('register', obj);
17095         switch(typeof(obj.disabled) ) {
17096                 
17097             case 'undefined':
17098                 break;
17099             
17100             case 'function':
17101                 if ( obj.disabled() ) {
17102                         return;
17103                 }
17104                 break;
17105             
17106             default:
17107                 if (obj.disabled || obj.region == '#disabled') {
17108                         return;
17109                 }
17110                 break;
17111         }
17112                 
17113         this.modules.push(obj);
17114          
17115     },
17116     /**
17117      * convert a string to an object..
17118      * eg. 'AAA.BBB' -> finds AAA.BBB
17119
17120      */
17121     
17122     toObject : function(str)
17123     {
17124         if (!str || typeof(str) == 'object') {
17125             return str;
17126         }
17127         if (str.substring(0,1) == '#') {
17128             return str;
17129         }
17130
17131         var ar = str.split('.');
17132         var rt, o;
17133         rt = ar.shift();
17134             /** eval:var:o */
17135         try {
17136             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17137         } catch (e) {
17138             throw "Module not found : " + str;
17139         }
17140         
17141         if (o === false) {
17142             throw "Module not found : " + str;
17143         }
17144         Roo.each(ar, function(e) {
17145             if (typeof(o[e]) == 'undefined') {
17146                 throw "Module not found : " + str;
17147             }
17148             o = o[e];
17149         });
17150         
17151         return o;
17152         
17153     },
17154     
17155     
17156     /**
17157      * move modules into their correct place in the tree..
17158      * 
17159      */
17160     preBuild : function ()
17161     {
17162         var _t = this;
17163         Roo.each(this.modules , function (obj)
17164         {
17165             Roo.XComponent.event.fireEvent('beforebuild', obj);
17166             
17167             var opar = obj.parent;
17168             try { 
17169                 obj.parent = this.toObject(opar);
17170             } catch(e) {
17171                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17172                 return;
17173             }
17174             
17175             if (!obj.parent) {
17176                 Roo.debug && Roo.log("GOT top level module");
17177                 Roo.debug && Roo.log(obj);
17178                 obj.modules = new Roo.util.MixedCollection(false, 
17179                     function(o) { return o.order + '' }
17180                 );
17181                 this.topModule = obj;
17182                 return;
17183             }
17184                         // parent is a string (usually a dom element name..)
17185             if (typeof(obj.parent) == 'string') {
17186                 this.elmodules.push(obj);
17187                 return;
17188             }
17189             if (obj.parent.constructor != Roo.XComponent) {
17190                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17191             }
17192             if (!obj.parent.modules) {
17193                 obj.parent.modules = new Roo.util.MixedCollection(false, 
17194                     function(o) { return o.order + '' }
17195                 );
17196             }
17197             if (obj.parent.disabled) {
17198                 obj.disabled = true;
17199             }
17200             obj.parent.modules.add(obj);
17201         }, this);
17202     },
17203     
17204      /**
17205      * make a list of modules to build.
17206      * @return {Array} list of modules. 
17207      */ 
17208     
17209     buildOrder : function()
17210     {
17211         var _this = this;
17212         var cmp = function(a,b) {   
17213             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17214         };
17215         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17216             throw "No top level modules to build";
17217         }
17218         
17219         // make a flat list in order of modules to build.
17220         var mods = this.topModule ? [ this.topModule ] : [];
17221                 
17222         
17223         // elmodules (is a list of DOM based modules )
17224         Roo.each(this.elmodules, function(e) {
17225             mods.push(e);
17226             if (!this.topModule &&
17227                 typeof(e.parent) == 'string' &&
17228                 e.parent.substring(0,1) == '#' &&
17229                 Roo.get(e.parent.substr(1))
17230                ) {
17231                 
17232                 _this.topModule = e;
17233             }
17234             
17235         });
17236
17237         
17238         // add modules to their parents..
17239         var addMod = function(m) {
17240             Roo.debug && Roo.log("build Order: add: " + m.name);
17241                 
17242             mods.push(m);
17243             if (m.modules && !m.disabled) {
17244                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17245                 m.modules.keySort('ASC',  cmp );
17246                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17247     
17248                 m.modules.each(addMod);
17249             } else {
17250                 Roo.debug && Roo.log("build Order: no child modules");
17251             }
17252             // not sure if this is used any more..
17253             if (m.finalize) {
17254                 m.finalize.name = m.name + " (clean up) ";
17255                 mods.push(m.finalize);
17256             }
17257             
17258         }
17259         if (this.topModule && this.topModule.modules) { 
17260             this.topModule.modules.keySort('ASC',  cmp );
17261             this.topModule.modules.each(addMod);
17262         } 
17263         return mods;
17264     },
17265     
17266      /**
17267      * Build the registered modules.
17268      * @param {Object} parent element.
17269      * @param {Function} optional method to call after module has been added.
17270      * 
17271      */ 
17272    
17273     build : function(opts) 
17274     {
17275         
17276         if (typeof(opts) != 'undefined') {
17277             Roo.apply(this,opts);
17278         }
17279         
17280         this.preBuild();
17281         var mods = this.buildOrder();
17282       
17283         //this.allmods = mods;
17284         //Roo.debug && Roo.log(mods);
17285         //return;
17286         if (!mods.length) { // should not happen
17287             throw "NO modules!!!";
17288         }
17289         
17290         
17291         var msg = "Building Interface...";
17292         // flash it up as modal - so we store the mask!?
17293         if (!this.hideProgress && Roo.MessageBox) {
17294             Roo.MessageBox.show({ title: 'loading' });
17295             Roo.MessageBox.show({
17296                title: "Please wait...",
17297                msg: msg,
17298                width:450,
17299                progress:true,
17300                buttons : false,
17301                closable:false,
17302                modal: false
17303               
17304             });
17305         }
17306         var total = mods.length;
17307         
17308         var _this = this;
17309         var progressRun = function() {
17310             if (!mods.length) {
17311                 Roo.debug && Roo.log('hide?');
17312                 if (!this.hideProgress && Roo.MessageBox) {
17313                     Roo.MessageBox.hide();
17314                 }
17315                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17316                 
17317                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17318                 
17319                 // THE END...
17320                 return false;   
17321             }
17322             
17323             var m = mods.shift();
17324             
17325             
17326             Roo.debug && Roo.log(m);
17327             // not sure if this is supported any more.. - modules that are are just function
17328             if (typeof(m) == 'function') { 
17329                 m.call(this);
17330                 return progressRun.defer(10, _this);
17331             } 
17332             
17333             
17334             msg = "Building Interface " + (total  - mods.length) + 
17335                     " of " + total + 
17336                     (m.name ? (' - ' + m.name) : '');
17337                         Roo.debug && Roo.log(msg);
17338             if (!_this.hideProgress &&  Roo.MessageBox) { 
17339                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
17340             }
17341             
17342          
17343             // is the module disabled?
17344             var disabled = (typeof(m.disabled) == 'function') ?
17345                 m.disabled.call(m.module.disabled) : m.disabled;    
17346             
17347             
17348             if (disabled) {
17349                 return progressRun(); // we do not update the display!
17350             }
17351             
17352             // now build 
17353             
17354                         
17355                         
17356             m.render();
17357             // it's 10 on top level, and 1 on others??? why...
17358             return progressRun.defer(10, _this);
17359              
17360         }
17361         progressRun.defer(1, _this);
17362      
17363         
17364         
17365     },
17366     /**
17367      * Overlay a set of modified strings onto a component
17368      * This is dependant on our builder exporting the strings and 'named strings' elements.
17369      * 
17370      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17371      * @param {Object} associative array of 'named' string and it's new value.
17372      * 
17373      */
17374         overlayStrings : function( component, strings )
17375     {
17376         if (typeof(component['_named_strings']) == 'undefined') {
17377             throw "ERROR: component does not have _named_strings";
17378         }
17379         for ( var k in strings ) {
17380             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17381             if (md !== false) {
17382                 component['_strings'][md] = strings[k];
17383             } else {
17384                 Roo.log('could not find named string: ' + k + ' in');
17385                 Roo.log(component);
17386             }
17387             
17388         }
17389         
17390     },
17391     
17392         
17393         /**
17394          * Event Object.
17395          *
17396          *
17397          */
17398         event: false, 
17399     /**
17400          * wrapper for event.on - aliased later..  
17401          * Typically use to register a event handler for register:
17402          *
17403          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17404          *
17405          */
17406     on : false
17407    
17408     
17409     
17410 });
17411
17412 Roo.XComponent.event = new Roo.util.Observable({
17413                 events : { 
17414                         /**
17415                          * @event register
17416                          * Fires when an Component is registered,
17417                          * set the disable property on the Component to stop registration.
17418                          * @param {Roo.XComponent} c the component being registerd.
17419                          * 
17420                          */
17421                         'register' : true,
17422             /**
17423                          * @event beforebuild
17424                          * Fires before each Component is built
17425                          * can be used to apply permissions.
17426                          * @param {Roo.XComponent} c the component being registerd.
17427                          * 
17428                          */
17429                         'beforebuild' : true,
17430                         /**
17431                          * @event buildcomplete
17432                          * Fires on the top level element when all elements have been built
17433                          * @param {Roo.XComponent} the top level component.
17434                          */
17435                         'buildcomplete' : true
17436                         
17437                 }
17438 });
17439
17440 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
17441  //
17442  /**
17443  * marked - a markdown parser
17444  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17445  * https://github.com/chjj/marked
17446  */
17447
17448
17449 /**
17450  *
17451  * Roo.Markdown - is a very crude wrapper around marked..
17452  *
17453  * usage:
17454  * 
17455  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17456  * 
17457  * Note: move the sample code to the bottom of this
17458  * file before uncommenting it.
17459  *
17460  */
17461
17462 Roo.Markdown = {};
17463 Roo.Markdown.toHtml = function(text) {
17464     
17465     var c = new Roo.Markdown.marked.setOptions({
17466             renderer: new Roo.Markdown.marked.Renderer(),
17467             gfm: true,
17468             tables: true,
17469             breaks: false,
17470             pedantic: false,
17471             sanitize: false,
17472             smartLists: true,
17473             smartypants: false
17474           });
17475     // A FEW HACKS!!?
17476     
17477     text = text.replace(/\\\n/g,' ');
17478     return Roo.Markdown.marked(text);
17479 };
17480 //
17481 // converter
17482 //
17483 // Wraps all "globals" so that the only thing
17484 // exposed is makeHtml().
17485 //
17486 (function() {
17487     
17488      /**
17489          * eval:var:escape
17490          * eval:var:unescape
17491          * eval:var:replace
17492          */
17493       
17494     /**
17495      * Helpers
17496      */
17497     
17498     var escape = function (html, encode) {
17499       return html
17500         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17501         .replace(/</g, '&lt;')
17502         .replace(/>/g, '&gt;')
17503         .replace(/"/g, '&quot;')
17504         .replace(/'/g, '&#39;');
17505     }
17506     
17507     var unescape = function (html) {
17508         // explicitly match decimal, hex, and named HTML entities 
17509       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17510         n = n.toLowerCase();
17511         if (n === 'colon') { return ':'; }
17512         if (n.charAt(0) === '#') {
17513           return n.charAt(1) === 'x'
17514             ? String.fromCharCode(parseInt(n.substring(2), 16))
17515             : String.fromCharCode(+n.substring(1));
17516         }
17517         return '';
17518       });
17519     }
17520     
17521     var replace = function (regex, opt) {
17522       regex = regex.source;
17523       opt = opt || '';
17524       return function self(name, val) {
17525         if (!name) { return new RegExp(regex, opt); }
17526         val = val.source || val;
17527         val = val.replace(/(^|[^\[])\^/g, '$1');
17528         regex = regex.replace(name, val);
17529         return self;
17530       };
17531     }
17532
17533
17534          /**
17535          * eval:var:noop
17536     */
17537     var noop = function () {}
17538     noop.exec = noop;
17539     
17540          /**
17541          * eval:var:merge
17542     */
17543     var merge = function (obj) {
17544       var i = 1
17545         , target
17546         , key;
17547     
17548       for (; i < arguments.length; i++) {
17549         target = arguments[i];
17550         for (key in target) {
17551           if (Object.prototype.hasOwnProperty.call(target, key)) {
17552             obj[key] = target[key];
17553           }
17554         }
17555       }
17556     
17557       return obj;
17558     }
17559     
17560     
17561     /**
17562      * Block-Level Grammar
17563      */
17564     
17565     
17566     
17567     
17568     var block = {
17569       newline: /^\n+/,
17570       code: /^( {4}[^\n]+\n*)+/,
17571       fences: noop,
17572       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17573       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17574       nptable: noop,
17575       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17576       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17577       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17578       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17579       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17580       table: noop,
17581       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17582       text: /^[^\n]+/
17583     };
17584     
17585     block.bullet = /(?:[*+-]|\d+\.)/;
17586     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17587     block.item = replace(block.item, 'gm')
17588       (/bull/g, block.bullet)
17589       ();
17590     
17591     block.list = replace(block.list)
17592       (/bull/g, block.bullet)
17593       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17594       ('def', '\\n+(?=' + block.def.source + ')')
17595       ();
17596     
17597     block.blockquote = replace(block.blockquote)
17598       ('def', block.def)
17599       ();
17600     
17601     block._tag = '(?!(?:'
17602       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17603       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17604       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17605     
17606     block.html = replace(block.html)
17607       ('comment', /<!--[\s\S]*?-->/)
17608       ('closed', /<(tag)[\s\S]+?<\/\1>/)
17609       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17610       (/tag/g, block._tag)
17611       ();
17612     
17613     block.paragraph = replace(block.paragraph)
17614       ('hr', block.hr)
17615       ('heading', block.heading)
17616       ('lheading', block.lheading)
17617       ('blockquote', block.blockquote)
17618       ('tag', '<' + block._tag)
17619       ('def', block.def)
17620       ();
17621     
17622     /**
17623      * Normal Block Grammar
17624      */
17625     
17626     block.normal = merge({}, block);
17627     
17628     /**
17629      * GFM Block Grammar
17630      */
17631     
17632     block.gfm = merge({}, block.normal, {
17633       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17634       paragraph: /^/,
17635       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17636     });
17637     
17638     block.gfm.paragraph = replace(block.paragraph)
17639       ('(?!', '(?!'
17640         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17641         + block.list.source.replace('\\1', '\\3') + '|')
17642       ();
17643     
17644     /**
17645      * GFM + Tables Block Grammar
17646      */
17647     
17648     block.tables = merge({}, block.gfm, {
17649       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17650       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17651     });
17652     
17653     /**
17654      * Block Lexer
17655      */
17656     
17657     var Lexer = function (options) {
17658       this.tokens = [];
17659       this.tokens.links = {};
17660       this.options = options || marked.defaults;
17661       this.rules = block.normal;
17662     
17663       if (this.options.gfm) {
17664         if (this.options.tables) {
17665           this.rules = block.tables;
17666         } else {
17667           this.rules = block.gfm;
17668         }
17669       }
17670     }
17671     
17672     /**
17673      * Expose Block Rules
17674      */
17675     
17676     Lexer.rules = block;
17677     
17678     /**
17679      * Static Lex Method
17680      */
17681     
17682     Lexer.lex = function(src, options) {
17683       var lexer = new Lexer(options);
17684       return lexer.lex(src);
17685     };
17686     
17687     /**
17688      * Preprocessing
17689      */
17690     
17691     Lexer.prototype.lex = function(src) {
17692       src = src
17693         .replace(/\r\n|\r/g, '\n')
17694         .replace(/\t/g, '    ')
17695         .replace(/\u00a0/g, ' ')
17696         .replace(/\u2424/g, '\n');
17697     
17698       return this.token(src, true);
17699     };
17700     
17701     /**
17702      * Lexing
17703      */
17704     
17705     Lexer.prototype.token = function(src, top, bq) {
17706       var src = src.replace(/^ +$/gm, '')
17707         , next
17708         , loose
17709         , cap
17710         , bull
17711         , b
17712         , item
17713         , space
17714         , i
17715         , l;
17716     
17717       while (src) {
17718         // newline
17719         if (cap = this.rules.newline.exec(src)) {
17720           src = src.substring(cap[0].length);
17721           if (cap[0].length > 1) {
17722             this.tokens.push({
17723               type: 'space'
17724             });
17725           }
17726         }
17727     
17728         // code
17729         if (cap = this.rules.code.exec(src)) {
17730           src = src.substring(cap[0].length);
17731           cap = cap[0].replace(/^ {4}/gm, '');
17732           this.tokens.push({
17733             type: 'code',
17734             text: !this.options.pedantic
17735               ? cap.replace(/\n+$/, '')
17736               : cap
17737           });
17738           continue;
17739         }
17740     
17741         // fences (gfm)
17742         if (cap = this.rules.fences.exec(src)) {
17743           src = src.substring(cap[0].length);
17744           this.tokens.push({
17745             type: 'code',
17746             lang: cap[2],
17747             text: cap[3] || ''
17748           });
17749           continue;
17750         }
17751     
17752         // heading
17753         if (cap = this.rules.heading.exec(src)) {
17754           src = src.substring(cap[0].length);
17755           this.tokens.push({
17756             type: 'heading',
17757             depth: cap[1].length,
17758             text: cap[2]
17759           });
17760           continue;
17761         }
17762     
17763         // table no leading pipe (gfm)
17764         if (top && (cap = this.rules.nptable.exec(src))) {
17765           src = src.substring(cap[0].length);
17766     
17767           item = {
17768             type: 'table',
17769             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17770             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17771             cells: cap[3].replace(/\n$/, '').split('\n')
17772           };
17773     
17774           for (i = 0; i < item.align.length; i++) {
17775             if (/^ *-+: *$/.test(item.align[i])) {
17776               item.align[i] = 'right';
17777             } else if (/^ *:-+: *$/.test(item.align[i])) {
17778               item.align[i] = 'center';
17779             } else if (/^ *:-+ *$/.test(item.align[i])) {
17780               item.align[i] = 'left';
17781             } else {
17782               item.align[i] = null;
17783             }
17784           }
17785     
17786           for (i = 0; i < item.cells.length; i++) {
17787             item.cells[i] = item.cells[i].split(/ *\| */);
17788           }
17789     
17790           this.tokens.push(item);
17791     
17792           continue;
17793         }
17794     
17795         // lheading
17796         if (cap = this.rules.lheading.exec(src)) {
17797           src = src.substring(cap[0].length);
17798           this.tokens.push({
17799             type: 'heading',
17800             depth: cap[2] === '=' ? 1 : 2,
17801             text: cap[1]
17802           });
17803           continue;
17804         }
17805     
17806         // hr
17807         if (cap = this.rules.hr.exec(src)) {
17808           src = src.substring(cap[0].length);
17809           this.tokens.push({
17810             type: 'hr'
17811           });
17812           continue;
17813         }
17814     
17815         // blockquote
17816         if (cap = this.rules.blockquote.exec(src)) {
17817           src = src.substring(cap[0].length);
17818     
17819           this.tokens.push({
17820             type: 'blockquote_start'
17821           });
17822     
17823           cap = cap[0].replace(/^ *> ?/gm, '');
17824     
17825           // Pass `top` to keep the current
17826           // "toplevel" state. This is exactly
17827           // how markdown.pl works.
17828           this.token(cap, top, true);
17829     
17830           this.tokens.push({
17831             type: 'blockquote_end'
17832           });
17833     
17834           continue;
17835         }
17836     
17837         // list
17838         if (cap = this.rules.list.exec(src)) {
17839           src = src.substring(cap[0].length);
17840           bull = cap[2];
17841     
17842           this.tokens.push({
17843             type: 'list_start',
17844             ordered: bull.length > 1
17845           });
17846     
17847           // Get each top-level item.
17848           cap = cap[0].match(this.rules.item);
17849     
17850           next = false;
17851           l = cap.length;
17852           i = 0;
17853     
17854           for (; i < l; i++) {
17855             item = cap[i];
17856     
17857             // Remove the list item's bullet
17858             // so it is seen as the next token.
17859             space = item.length;
17860             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17861     
17862             // Outdent whatever the
17863             // list item contains. Hacky.
17864             if (~item.indexOf('\n ')) {
17865               space -= item.length;
17866               item = !this.options.pedantic
17867                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17868                 : item.replace(/^ {1,4}/gm, '');
17869             }
17870     
17871             // Determine whether the next list item belongs here.
17872             // Backpedal if it does not belong in this list.
17873             if (this.options.smartLists && i !== l - 1) {
17874               b = block.bullet.exec(cap[i + 1])[0];
17875               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17876                 src = cap.slice(i + 1).join('\n') + src;
17877                 i = l - 1;
17878               }
17879             }
17880     
17881             // Determine whether item is loose or not.
17882             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17883             // for discount behavior.
17884             loose = next || /\n\n(?!\s*$)/.test(item);
17885             if (i !== l - 1) {
17886               next = item.charAt(item.length - 1) === '\n';
17887               if (!loose) { loose = next; }
17888             }
17889     
17890             this.tokens.push({
17891               type: loose
17892                 ? 'loose_item_start'
17893                 : 'list_item_start'
17894             });
17895     
17896             // Recurse.
17897             this.token(item, false, bq);
17898     
17899             this.tokens.push({
17900               type: 'list_item_end'
17901             });
17902           }
17903     
17904           this.tokens.push({
17905             type: 'list_end'
17906           });
17907     
17908           continue;
17909         }
17910     
17911         // html
17912         if (cap = this.rules.html.exec(src)) {
17913           src = src.substring(cap[0].length);
17914           this.tokens.push({
17915             type: this.options.sanitize
17916               ? 'paragraph'
17917               : 'html',
17918             pre: !this.options.sanitizer
17919               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17920             text: cap[0]
17921           });
17922           continue;
17923         }
17924     
17925         // def
17926         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17927           src = src.substring(cap[0].length);
17928           this.tokens.links[cap[1].toLowerCase()] = {
17929             href: cap[2],
17930             title: cap[3]
17931           };
17932           continue;
17933         }
17934     
17935         // table (gfm)
17936         if (top && (cap = this.rules.table.exec(src))) {
17937           src = src.substring(cap[0].length);
17938     
17939           item = {
17940             type: 'table',
17941             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17942             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17943             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17944           };
17945     
17946           for (i = 0; i < item.align.length; i++) {
17947             if (/^ *-+: *$/.test(item.align[i])) {
17948               item.align[i] = 'right';
17949             } else if (/^ *:-+: *$/.test(item.align[i])) {
17950               item.align[i] = 'center';
17951             } else if (/^ *:-+ *$/.test(item.align[i])) {
17952               item.align[i] = 'left';
17953             } else {
17954               item.align[i] = null;
17955             }
17956           }
17957     
17958           for (i = 0; i < item.cells.length; i++) {
17959             item.cells[i] = item.cells[i]
17960               .replace(/^ *\| *| *\| *$/g, '')
17961               .split(/ *\| */);
17962           }
17963     
17964           this.tokens.push(item);
17965     
17966           continue;
17967         }
17968     
17969         // top-level paragraph
17970         if (top && (cap = this.rules.paragraph.exec(src))) {
17971           src = src.substring(cap[0].length);
17972           this.tokens.push({
17973             type: 'paragraph',
17974             text: cap[1].charAt(cap[1].length - 1) === '\n'
17975               ? cap[1].slice(0, -1)
17976               : cap[1]
17977           });
17978           continue;
17979         }
17980     
17981         // text
17982         if (cap = this.rules.text.exec(src)) {
17983           // Top-level should never reach here.
17984           src = src.substring(cap[0].length);
17985           this.tokens.push({
17986             type: 'text',
17987             text: cap[0]
17988           });
17989           continue;
17990         }
17991     
17992         if (src) {
17993           throw new
17994             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17995         }
17996       }
17997     
17998       return this.tokens;
17999     };
18000     
18001     /**
18002      * Inline-Level Grammar
18003      */
18004     
18005     var inline = {
18006       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18007       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18008       url: noop,
18009       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18010       link: /^!?\[(inside)\]\(href\)/,
18011       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18012       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18013       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18014       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18015       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18016       br: /^ {2,}\n(?!\s*$)/,
18017       del: noop,
18018       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18019     };
18020     
18021     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18022     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18023     
18024     inline.link = replace(inline.link)
18025       ('inside', inline._inside)
18026       ('href', inline._href)
18027       ();
18028     
18029     inline.reflink = replace(inline.reflink)
18030       ('inside', inline._inside)
18031       ();
18032     
18033     /**
18034      * Normal Inline Grammar
18035      */
18036     
18037     inline.normal = merge({}, inline);
18038     
18039     /**
18040      * Pedantic Inline Grammar
18041      */
18042     
18043     inline.pedantic = merge({}, inline.normal, {
18044       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18045       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18046     });
18047     
18048     /**
18049      * GFM Inline Grammar
18050      */
18051     
18052     inline.gfm = merge({}, inline.normal, {
18053       escape: replace(inline.escape)('])', '~|])')(),
18054       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18055       del: /^~~(?=\S)([\s\S]*?\S)~~/,
18056       text: replace(inline.text)
18057         (']|', '~]|')
18058         ('|', '|https?://|')
18059         ()
18060     });
18061     
18062     /**
18063      * GFM + Line Breaks Inline Grammar
18064      */
18065     
18066     inline.breaks = merge({}, inline.gfm, {
18067       br: replace(inline.br)('{2,}', '*')(),
18068       text: replace(inline.gfm.text)('{2,}', '*')()
18069     });
18070     
18071     /**
18072      * Inline Lexer & Compiler
18073      */
18074     
18075     var InlineLexer  = function (links, options) {
18076       this.options = options || marked.defaults;
18077       this.links = links;
18078       this.rules = inline.normal;
18079       this.renderer = this.options.renderer || new Renderer;
18080       this.renderer.options = this.options;
18081     
18082       if (!this.links) {
18083         throw new
18084           Error('Tokens array requires a `links` property.');
18085       }
18086     
18087       if (this.options.gfm) {
18088         if (this.options.breaks) {
18089           this.rules = inline.breaks;
18090         } else {
18091           this.rules = inline.gfm;
18092         }
18093       } else if (this.options.pedantic) {
18094         this.rules = inline.pedantic;
18095       }
18096     }
18097     
18098     /**
18099      * Expose Inline Rules
18100      */
18101     
18102     InlineLexer.rules = inline;
18103     
18104     /**
18105      * Static Lexing/Compiling Method
18106      */
18107     
18108     InlineLexer.output = function(src, links, options) {
18109       var inline = new InlineLexer(links, options);
18110       return inline.output(src);
18111     };
18112     
18113     /**
18114      * Lexing/Compiling
18115      */
18116     
18117     InlineLexer.prototype.output = function(src) {
18118       var out = ''
18119         , link
18120         , text
18121         , href
18122         , cap;
18123     
18124       while (src) {
18125         // escape
18126         if (cap = this.rules.escape.exec(src)) {
18127           src = src.substring(cap[0].length);
18128           out += cap[1];
18129           continue;
18130         }
18131     
18132         // autolink
18133         if (cap = this.rules.autolink.exec(src)) {
18134           src = src.substring(cap[0].length);
18135           if (cap[2] === '@') {
18136             text = cap[1].charAt(6) === ':'
18137               ? this.mangle(cap[1].substring(7))
18138               : this.mangle(cap[1]);
18139             href = this.mangle('mailto:') + text;
18140           } else {
18141             text = escape(cap[1]);
18142             href = text;
18143           }
18144           out += this.renderer.link(href, null, text);
18145           continue;
18146         }
18147     
18148         // url (gfm)
18149         if (!this.inLink && (cap = this.rules.url.exec(src))) {
18150           src = src.substring(cap[0].length);
18151           text = escape(cap[1]);
18152           href = text;
18153           out += this.renderer.link(href, null, text);
18154           continue;
18155         }
18156     
18157         // tag
18158         if (cap = this.rules.tag.exec(src)) {
18159           if (!this.inLink && /^<a /i.test(cap[0])) {
18160             this.inLink = true;
18161           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18162             this.inLink = false;
18163           }
18164           src = src.substring(cap[0].length);
18165           out += this.options.sanitize
18166             ? this.options.sanitizer
18167               ? this.options.sanitizer(cap[0])
18168               : escape(cap[0])
18169             : cap[0];
18170           continue;
18171         }
18172     
18173         // link
18174         if (cap = this.rules.link.exec(src)) {
18175           src = src.substring(cap[0].length);
18176           this.inLink = true;
18177           out += this.outputLink(cap, {
18178             href: cap[2],
18179             title: cap[3]
18180           });
18181           this.inLink = false;
18182           continue;
18183         }
18184     
18185         // reflink, nolink
18186         if ((cap = this.rules.reflink.exec(src))
18187             || (cap = this.rules.nolink.exec(src))) {
18188           src = src.substring(cap[0].length);
18189           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18190           link = this.links[link.toLowerCase()];
18191           if (!link || !link.href) {
18192             out += cap[0].charAt(0);
18193             src = cap[0].substring(1) + src;
18194             continue;
18195           }
18196           this.inLink = true;
18197           out += this.outputLink(cap, link);
18198           this.inLink = false;
18199           continue;
18200         }
18201     
18202         // strong
18203         if (cap = this.rules.strong.exec(src)) {
18204           src = src.substring(cap[0].length);
18205           out += this.renderer.strong(this.output(cap[2] || cap[1]));
18206           continue;
18207         }
18208     
18209         // em
18210         if (cap = this.rules.em.exec(src)) {
18211           src = src.substring(cap[0].length);
18212           out += this.renderer.em(this.output(cap[2] || cap[1]));
18213           continue;
18214         }
18215     
18216         // code
18217         if (cap = this.rules.code.exec(src)) {
18218           src = src.substring(cap[0].length);
18219           out += this.renderer.codespan(escape(cap[2], true));
18220           continue;
18221         }
18222     
18223         // br
18224         if (cap = this.rules.br.exec(src)) {
18225           src = src.substring(cap[0].length);
18226           out += this.renderer.br();
18227           continue;
18228         }
18229     
18230         // del (gfm)
18231         if (cap = this.rules.del.exec(src)) {
18232           src = src.substring(cap[0].length);
18233           out += this.renderer.del(this.output(cap[1]));
18234           continue;
18235         }
18236     
18237         // text
18238         if (cap = this.rules.text.exec(src)) {
18239           src = src.substring(cap[0].length);
18240           out += this.renderer.text(escape(this.smartypants(cap[0])));
18241           continue;
18242         }
18243     
18244         if (src) {
18245           throw new
18246             Error('Infinite loop on byte: ' + src.charCodeAt(0));
18247         }
18248       }
18249     
18250       return out;
18251     };
18252     
18253     /**
18254      * Compile Link
18255      */
18256     
18257     InlineLexer.prototype.outputLink = function(cap, link) {
18258       var href = escape(link.href)
18259         , title = link.title ? escape(link.title) : null;
18260     
18261       return cap[0].charAt(0) !== '!'
18262         ? this.renderer.link(href, title, this.output(cap[1]))
18263         : this.renderer.image(href, title, escape(cap[1]));
18264     };
18265     
18266     /**
18267      * Smartypants Transformations
18268      */
18269     
18270     InlineLexer.prototype.smartypants = function(text) {
18271       if (!this.options.smartypants)  { return text; }
18272       return text
18273         // em-dashes
18274         .replace(/---/g, '\u2014')
18275         // en-dashes
18276         .replace(/--/g, '\u2013')
18277         // opening singles
18278         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18279         // closing singles & apostrophes
18280         .replace(/'/g, '\u2019')
18281         // opening doubles
18282         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18283         // closing doubles
18284         .replace(/"/g, '\u201d')
18285         // ellipses
18286         .replace(/\.{3}/g, '\u2026');
18287     };
18288     
18289     /**
18290      * Mangle Links
18291      */
18292     
18293     InlineLexer.prototype.mangle = function(text) {
18294       if (!this.options.mangle) { return text; }
18295       var out = ''
18296         , l = text.length
18297         , i = 0
18298         , ch;
18299     
18300       for (; i < l; i++) {
18301         ch = text.charCodeAt(i);
18302         if (Math.random() > 0.5) {
18303           ch = 'x' + ch.toString(16);
18304         }
18305         out += '&#' + ch + ';';
18306       }
18307     
18308       return out;
18309     };
18310     
18311     /**
18312      * Renderer
18313      */
18314     
18315      /**
18316          * eval:var:Renderer
18317     */
18318     
18319     var Renderer   = function (options) {
18320       this.options = options || {};
18321     }
18322     
18323     Renderer.prototype.code = function(code, lang, escaped) {
18324       if (this.options.highlight) {
18325         var out = this.options.highlight(code, lang);
18326         if (out != null && out !== code) {
18327           escaped = true;
18328           code = out;
18329         }
18330       } else {
18331             // hack!!! - it's already escapeD?
18332             escaped = true;
18333       }
18334     
18335       if (!lang) {
18336         return '<pre><code>'
18337           + (escaped ? code : escape(code, true))
18338           + '\n</code></pre>';
18339       }
18340     
18341       return '<pre><code class="'
18342         + this.options.langPrefix
18343         + escape(lang, true)
18344         + '">'
18345         + (escaped ? code : escape(code, true))
18346         + '\n</code></pre>\n';
18347     };
18348     
18349     Renderer.prototype.blockquote = function(quote) {
18350       return '<blockquote>\n' + quote + '</blockquote>\n';
18351     };
18352     
18353     Renderer.prototype.html = function(html) {
18354       return html;
18355     };
18356     
18357     Renderer.prototype.heading = function(text, level, raw) {
18358       return '<h'
18359         + level
18360         + ' id="'
18361         + this.options.headerPrefix
18362         + raw.toLowerCase().replace(/[^\w]+/g, '-')
18363         + '">'
18364         + text
18365         + '</h'
18366         + level
18367         + '>\n';
18368     };
18369     
18370     Renderer.prototype.hr = function() {
18371       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18372     };
18373     
18374     Renderer.prototype.list = function(body, ordered) {
18375       var type = ordered ? 'ol' : 'ul';
18376       return '<' + type + '>\n' + body + '</' + type + '>\n';
18377     };
18378     
18379     Renderer.prototype.listitem = function(text) {
18380       return '<li>' + text + '</li>\n';
18381     };
18382     
18383     Renderer.prototype.paragraph = function(text) {
18384       return '<p>' + text + '</p>\n';
18385     };
18386     
18387     Renderer.prototype.table = function(header, body) {
18388       return '<table class="table table-striped">\n'
18389         + '<thead>\n'
18390         + header
18391         + '</thead>\n'
18392         + '<tbody>\n'
18393         + body
18394         + '</tbody>\n'
18395         + '</table>\n';
18396     };
18397     
18398     Renderer.prototype.tablerow = function(content) {
18399       return '<tr>\n' + content + '</tr>\n';
18400     };
18401     
18402     Renderer.prototype.tablecell = function(content, flags) {
18403       var type = flags.header ? 'th' : 'td';
18404       var tag = flags.align
18405         ? '<' + type + ' style="text-align:' + flags.align + '">'
18406         : '<' + type + '>';
18407       return tag + content + '</' + type + '>\n';
18408     };
18409     
18410     // span level renderer
18411     Renderer.prototype.strong = function(text) {
18412       return '<strong>' + text + '</strong>';
18413     };
18414     
18415     Renderer.prototype.em = function(text) {
18416       return '<em>' + text + '</em>';
18417     };
18418     
18419     Renderer.prototype.codespan = function(text) {
18420       return '<code>' + text + '</code>';
18421     };
18422     
18423     Renderer.prototype.br = function() {
18424       return this.options.xhtml ? '<br/>' : '<br>';
18425     };
18426     
18427     Renderer.prototype.del = function(text) {
18428       return '<del>' + text + '</del>';
18429     };
18430     
18431     Renderer.prototype.link = function(href, title, text) {
18432       if (this.options.sanitize) {
18433         try {
18434           var prot = decodeURIComponent(unescape(href))
18435             .replace(/[^\w:]/g, '')
18436             .toLowerCase();
18437         } catch (e) {
18438           return '';
18439         }
18440         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18441           return '';
18442         }
18443       }
18444       var out = '<a href="' + href + '"';
18445       if (title) {
18446         out += ' title="' + title + '"';
18447       }
18448       out += '>' + text + '</a>';
18449       return out;
18450     };
18451     
18452     Renderer.prototype.image = function(href, title, text) {
18453       var out = '<img src="' + href + '" alt="' + text + '"';
18454       if (title) {
18455         out += ' title="' + title + '"';
18456       }
18457       out += this.options.xhtml ? '/>' : '>';
18458       return out;
18459     };
18460     
18461     Renderer.prototype.text = function(text) {
18462       return text;
18463     };
18464     
18465     /**
18466      * Parsing & Compiling
18467      */
18468          /**
18469          * eval:var:Parser
18470     */
18471     
18472     var Parser= function (options) {
18473       this.tokens = [];
18474       this.token = null;
18475       this.options = options || marked.defaults;
18476       this.options.renderer = this.options.renderer || new Renderer;
18477       this.renderer = this.options.renderer;
18478       this.renderer.options = this.options;
18479     }
18480     
18481     /**
18482      * Static Parse Method
18483      */
18484     
18485     Parser.parse = function(src, options, renderer) {
18486       var parser = new Parser(options, renderer);
18487       return parser.parse(src);
18488     };
18489     
18490     /**
18491      * Parse Loop
18492      */
18493     
18494     Parser.prototype.parse = function(src) {
18495       this.inline = new InlineLexer(src.links, this.options, this.renderer);
18496       this.tokens = src.reverse();
18497     
18498       var out = '';
18499       while (this.next()) {
18500         out += this.tok();
18501       }
18502     
18503       return out;
18504     };
18505     
18506     /**
18507      * Next Token
18508      */
18509     
18510     Parser.prototype.next = function() {
18511       return this.token = this.tokens.pop();
18512     };
18513     
18514     /**
18515      * Preview Next Token
18516      */
18517     
18518     Parser.prototype.peek = function() {
18519       return this.tokens[this.tokens.length - 1] || 0;
18520     };
18521     
18522     /**
18523      * Parse Text Tokens
18524      */
18525     
18526     Parser.prototype.parseText = function() {
18527       var body = this.token.text;
18528     
18529       while (this.peek().type === 'text') {
18530         body += '\n' + this.next().text;
18531       }
18532     
18533       return this.inline.output(body);
18534     };
18535     
18536     /**
18537      * Parse Current Token
18538      */
18539     
18540     Parser.prototype.tok = function() {
18541       switch (this.token.type) {
18542         case 'space': {
18543           return '';
18544         }
18545         case 'hr': {
18546           return this.renderer.hr();
18547         }
18548         case 'heading': {
18549           return this.renderer.heading(
18550             this.inline.output(this.token.text),
18551             this.token.depth,
18552             this.token.text);
18553         }
18554         case 'code': {
18555           return this.renderer.code(this.token.text,
18556             this.token.lang,
18557             this.token.escaped);
18558         }
18559         case 'table': {
18560           var header = ''
18561             , body = ''
18562             , i
18563             , row
18564             , cell
18565             , flags
18566             , j;
18567     
18568           // header
18569           cell = '';
18570           for (i = 0; i < this.token.header.length; i++) {
18571             flags = { header: true, align: this.token.align[i] };
18572             cell += this.renderer.tablecell(
18573               this.inline.output(this.token.header[i]),
18574               { header: true, align: this.token.align[i] }
18575             );
18576           }
18577           header += this.renderer.tablerow(cell);
18578     
18579           for (i = 0; i < this.token.cells.length; i++) {
18580             row = this.token.cells[i];
18581     
18582             cell = '';
18583             for (j = 0; j < row.length; j++) {
18584               cell += this.renderer.tablecell(
18585                 this.inline.output(row[j]),
18586                 { header: false, align: this.token.align[j] }
18587               );
18588             }
18589     
18590             body += this.renderer.tablerow(cell);
18591           }
18592           return this.renderer.table(header, body);
18593         }
18594         case 'blockquote_start': {
18595           var body = '';
18596     
18597           while (this.next().type !== 'blockquote_end') {
18598             body += this.tok();
18599           }
18600     
18601           return this.renderer.blockquote(body);
18602         }
18603         case 'list_start': {
18604           var body = ''
18605             , ordered = this.token.ordered;
18606     
18607           while (this.next().type !== 'list_end') {
18608             body += this.tok();
18609           }
18610     
18611           return this.renderer.list(body, ordered);
18612         }
18613         case 'list_item_start': {
18614           var body = '';
18615     
18616           while (this.next().type !== 'list_item_end') {
18617             body += this.token.type === 'text'
18618               ? this.parseText()
18619               : this.tok();
18620           }
18621     
18622           return this.renderer.listitem(body);
18623         }
18624         case 'loose_item_start': {
18625           var body = '';
18626     
18627           while (this.next().type !== 'list_item_end') {
18628             body += this.tok();
18629           }
18630     
18631           return this.renderer.listitem(body);
18632         }
18633         case 'html': {
18634           var html = !this.token.pre && !this.options.pedantic
18635             ? this.inline.output(this.token.text)
18636             : this.token.text;
18637           return this.renderer.html(html);
18638         }
18639         case 'paragraph': {
18640           return this.renderer.paragraph(this.inline.output(this.token.text));
18641         }
18642         case 'text': {
18643           return this.renderer.paragraph(this.parseText());
18644         }
18645       }
18646     };
18647   
18648     
18649     /**
18650      * Marked
18651      */
18652          /**
18653          * eval:var:marked
18654     */
18655     var marked = function (src, opt, callback) {
18656       if (callback || typeof opt === 'function') {
18657         if (!callback) {
18658           callback = opt;
18659           opt = null;
18660         }
18661     
18662         opt = merge({}, marked.defaults, opt || {});
18663     
18664         var highlight = opt.highlight
18665           , tokens
18666           , pending
18667           , i = 0;
18668     
18669         try {
18670           tokens = Lexer.lex(src, opt)
18671         } catch (e) {
18672           return callback(e);
18673         }
18674     
18675         pending = tokens.length;
18676          /**
18677          * eval:var:done
18678     */
18679         var done = function(err) {
18680           if (err) {
18681             opt.highlight = highlight;
18682             return callback(err);
18683           }
18684     
18685           var out;
18686     
18687           try {
18688             out = Parser.parse(tokens, opt);
18689           } catch (e) {
18690             err = e;
18691           }
18692     
18693           opt.highlight = highlight;
18694     
18695           return err
18696             ? callback(err)
18697             : callback(null, out);
18698         };
18699     
18700         if (!highlight || highlight.length < 3) {
18701           return done();
18702         }
18703     
18704         delete opt.highlight;
18705     
18706         if (!pending) { return done(); }
18707     
18708         for (; i < tokens.length; i++) {
18709           (function(token) {
18710             if (token.type !== 'code') {
18711               return --pending || done();
18712             }
18713             return highlight(token.text, token.lang, function(err, code) {
18714               if (err) { return done(err); }
18715               if (code == null || code === token.text) {
18716                 return --pending || done();
18717               }
18718               token.text = code;
18719               token.escaped = true;
18720               --pending || done();
18721             });
18722           })(tokens[i]);
18723         }
18724     
18725         return;
18726       }
18727       try {
18728         if (opt) { opt = merge({}, marked.defaults, opt); }
18729         return Parser.parse(Lexer.lex(src, opt), opt);
18730       } catch (e) {
18731         e.message += '\nPlease report this to https://github.com/chjj/marked.';
18732         if ((opt || marked.defaults).silent) {
18733           return '<p>An error occured:</p><pre>'
18734             + escape(e.message + '', true)
18735             + '</pre>';
18736         }
18737         throw e;
18738       }
18739     }
18740     
18741     /**
18742      * Options
18743      */
18744     
18745     marked.options =
18746     marked.setOptions = function(opt) {
18747       merge(marked.defaults, opt);
18748       return marked;
18749     };
18750     
18751     marked.defaults = {
18752       gfm: true,
18753       tables: true,
18754       breaks: false,
18755       pedantic: false,
18756       sanitize: false,
18757       sanitizer: null,
18758       mangle: true,
18759       smartLists: false,
18760       silent: false,
18761       highlight: null,
18762       langPrefix: 'lang-',
18763       smartypants: false,
18764       headerPrefix: '',
18765       renderer: new Renderer,
18766       xhtml: false
18767     };
18768     
18769     /**
18770      * Expose
18771      */
18772     
18773     marked.Parser = Parser;
18774     marked.parser = Parser.parse;
18775     
18776     marked.Renderer = Renderer;
18777     
18778     marked.Lexer = Lexer;
18779     marked.lexer = Lexer.lex;
18780     
18781     marked.InlineLexer = InlineLexer;
18782     marked.inlineLexer = InlineLexer.output;
18783     
18784     marked.parse = marked;
18785     
18786     Roo.Markdown.marked = marked;
18787
18788 })();/*
18789  * Based on:
18790  * Ext JS Library 1.1.1
18791  * Copyright(c) 2006-2007, Ext JS, LLC.
18792  *
18793  * Originally Released Under LGPL - original licence link has changed is not relivant.
18794  *
18795  * Fork - LGPL
18796  * <script type="text/javascript">
18797  */
18798
18799
18800
18801 /*
18802  * These classes are derivatives of the similarly named classes in the YUI Library.
18803  * The original license:
18804  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18805  * Code licensed under the BSD License:
18806  * http://developer.yahoo.net/yui/license.txt
18807  */
18808
18809 (function() {
18810
18811 var Event=Roo.EventManager;
18812 var Dom=Roo.lib.Dom;
18813
18814 /**
18815  * @class Roo.dd.DragDrop
18816  * @extends Roo.util.Observable
18817  * Defines the interface and base operation of items that that can be
18818  * dragged or can be drop targets.  It was designed to be extended, overriding
18819  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18820  * Up to three html elements can be associated with a DragDrop instance:
18821  * <ul>
18822  * <li>linked element: the element that is passed into the constructor.
18823  * This is the element which defines the boundaries for interaction with
18824  * other DragDrop objects.</li>
18825  * <li>handle element(s): The drag operation only occurs if the element that
18826  * was clicked matches a handle element.  By default this is the linked
18827  * element, but there are times that you will want only a portion of the
18828  * linked element to initiate the drag operation, and the setHandleElId()
18829  * method provides a way to define this.</li>
18830  * <li>drag element: this represents the element that would be moved along
18831  * with the cursor during a drag operation.  By default, this is the linked
18832  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18833  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18834  * </li>
18835  * </ul>
18836  * This class should not be instantiated until the onload event to ensure that
18837  * the associated elements are available.
18838  * The following would define a DragDrop obj that would interact with any
18839  * other DragDrop obj in the "group1" group:
18840  * <pre>
18841  *  dd = new Roo.dd.DragDrop("div1", "group1");
18842  * </pre>
18843  * Since none of the event handlers have been implemented, nothing would
18844  * actually happen if you were to run the code above.  Normally you would
18845  * override this class or one of the default implementations, but you can
18846  * also override the methods you want on an instance of the class...
18847  * <pre>
18848  *  dd.onDragDrop = function(e, id) {
18849  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18850  *  }
18851  * </pre>
18852  * @constructor
18853  * @param {String} id of the element that is linked to this instance
18854  * @param {String} sGroup the group of related DragDrop objects
18855  * @param {object} config an object containing configurable attributes
18856  *                Valid properties for DragDrop:
18857  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18858  */
18859 Roo.dd.DragDrop = function(id, sGroup, config) {
18860     if (id) {
18861         this.init(id, sGroup, config);
18862     }
18863     
18864 };
18865
18866 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18867
18868     /**
18869      * The id of the element associated with this object.  This is what we
18870      * refer to as the "linked element" because the size and position of
18871      * this element is used to determine when the drag and drop objects have
18872      * interacted.
18873      * @property id
18874      * @type String
18875      */
18876     id: null,
18877
18878     /**
18879      * Configuration attributes passed into the constructor
18880      * @property config
18881      * @type object
18882      */
18883     config: null,
18884
18885     /**
18886      * The id of the element that will be dragged.  By default this is same
18887      * as the linked element , but could be changed to another element. Ex:
18888      * Roo.dd.DDProxy
18889      * @property dragElId
18890      * @type String
18891      * @private
18892      */
18893     dragElId: null,
18894
18895     /**
18896      * the id of the element that initiates the drag operation.  By default
18897      * this is the linked element, but could be changed to be a child of this
18898      * element.  This lets us do things like only starting the drag when the
18899      * header element within the linked html element is clicked.
18900      * @property handleElId
18901      * @type String
18902      * @private
18903      */
18904     handleElId: null,
18905
18906     /**
18907      * An associative array of HTML tags that will be ignored if clicked.
18908      * @property invalidHandleTypes
18909      * @type {string: string}
18910      */
18911     invalidHandleTypes: null,
18912
18913     /**
18914      * An associative array of ids for elements that will be ignored if clicked
18915      * @property invalidHandleIds
18916      * @type {string: string}
18917      */
18918     invalidHandleIds: null,
18919
18920     /**
18921      * An indexted array of css class names for elements that will be ignored
18922      * if clicked.
18923      * @property invalidHandleClasses
18924      * @type string[]
18925      */
18926     invalidHandleClasses: null,
18927
18928     /**
18929      * The linked element's absolute X position at the time the drag was
18930      * started
18931      * @property startPageX
18932      * @type int
18933      * @private
18934      */
18935     startPageX: 0,
18936
18937     /**
18938      * The linked element's absolute X position at the time the drag was
18939      * started
18940      * @property startPageY
18941      * @type int
18942      * @private
18943      */
18944     startPageY: 0,
18945
18946     /**
18947      * The group defines a logical collection of DragDrop objects that are
18948      * related.  Instances only get events when interacting with other
18949      * DragDrop object in the same group.  This lets us define multiple
18950      * groups using a single DragDrop subclass if we want.
18951      * @property groups
18952      * @type {string: string}
18953      */
18954     groups: null,
18955
18956     /**
18957      * Individual drag/drop instances can be locked.  This will prevent
18958      * onmousedown start drag.
18959      * @property locked
18960      * @type boolean
18961      * @private
18962      */
18963     locked: false,
18964
18965     /**
18966      * Lock this instance
18967      * @method lock
18968      */
18969     lock: function() { this.locked = true; },
18970
18971     /**
18972      * Unlock this instace
18973      * @method unlock
18974      */
18975     unlock: function() { this.locked = false; },
18976
18977     /**
18978      * By default, all insances can be a drop target.  This can be disabled by
18979      * setting isTarget to false.
18980      * @method isTarget
18981      * @type boolean
18982      */
18983     isTarget: true,
18984
18985     /**
18986      * The padding configured for this drag and drop object for calculating
18987      * the drop zone intersection with this object.
18988      * @method padding
18989      * @type int[]
18990      */
18991     padding: null,
18992
18993     /**
18994      * Cached reference to the linked element
18995      * @property _domRef
18996      * @private
18997      */
18998     _domRef: null,
18999
19000     /**
19001      * Internal typeof flag
19002      * @property __ygDragDrop
19003      * @private
19004      */
19005     __ygDragDrop: true,
19006
19007     /**
19008      * Set to true when horizontal contraints are applied
19009      * @property constrainX
19010      * @type boolean
19011      * @private
19012      */
19013     constrainX: false,
19014
19015     /**
19016      * Set to true when vertical contraints are applied
19017      * @property constrainY
19018      * @type boolean
19019      * @private
19020      */
19021     constrainY: false,
19022
19023     /**
19024      * The left constraint
19025      * @property minX
19026      * @type int
19027      * @private
19028      */
19029     minX: 0,
19030
19031     /**
19032      * The right constraint
19033      * @property maxX
19034      * @type int
19035      * @private
19036      */
19037     maxX: 0,
19038
19039     /**
19040      * The up constraint
19041      * @property minY
19042      * @type int
19043      * @type int
19044      * @private
19045      */
19046     minY: 0,
19047
19048     /**
19049      * The down constraint
19050      * @property maxY
19051      * @type int
19052      * @private
19053      */
19054     maxY: 0,
19055
19056     /**
19057      * Maintain offsets when we resetconstraints.  Set to true when you want
19058      * the position of the element relative to its parent to stay the same
19059      * when the page changes
19060      *
19061      * @property maintainOffset
19062      * @type boolean
19063      */
19064     maintainOffset: false,
19065
19066     /**
19067      * Array of pixel locations the element will snap to if we specified a
19068      * horizontal graduation/interval.  This array is generated automatically
19069      * when you define a tick interval.
19070      * @property xTicks
19071      * @type int[]
19072      */
19073     xTicks: null,
19074
19075     /**
19076      * Array of pixel locations the element will snap to if we specified a
19077      * vertical graduation/interval.  This array is generated automatically
19078      * when you define a tick interval.
19079      * @property yTicks
19080      * @type int[]
19081      */
19082     yTicks: null,
19083
19084     /**
19085      * By default the drag and drop instance will only respond to the primary
19086      * button click (left button for a right-handed mouse).  Set to true to
19087      * allow drag and drop to start with any mouse click that is propogated
19088      * by the browser
19089      * @property primaryButtonOnly
19090      * @type boolean
19091      */
19092     primaryButtonOnly: true,
19093
19094     /**
19095      * The availabe property is false until the linked dom element is accessible.
19096      * @property available
19097      * @type boolean
19098      */
19099     available: false,
19100
19101     /**
19102      * By default, drags can only be initiated if the mousedown occurs in the
19103      * region the linked element is.  This is done in part to work around a
19104      * bug in some browsers that mis-report the mousedown if the previous
19105      * mouseup happened outside of the window.  This property is set to true
19106      * if outer handles are defined.
19107      *
19108      * @property hasOuterHandles
19109      * @type boolean
19110      * @default false
19111      */
19112     hasOuterHandles: false,
19113
19114     /**
19115      * Code that executes immediately before the startDrag event
19116      * @method b4StartDrag
19117      * @private
19118      */
19119     b4StartDrag: function(x, y) { },
19120
19121     /**
19122      * Abstract method called after a drag/drop object is clicked
19123      * and the drag or mousedown time thresholds have beeen met.
19124      * @method startDrag
19125      * @param {int} X click location
19126      * @param {int} Y click location
19127      */
19128     startDrag: function(x, y) { /* override this */ },
19129
19130     /**
19131      * Code that executes immediately before the onDrag event
19132      * @method b4Drag
19133      * @private
19134      */
19135     b4Drag: function(e) { },
19136
19137     /**
19138      * Abstract method called during the onMouseMove event while dragging an
19139      * object.
19140      * @method onDrag
19141      * @param {Event} e the mousemove event
19142      */
19143     onDrag: function(e) { /* override this */ },
19144
19145     /**
19146      * Abstract method called when this element fist begins hovering over
19147      * another DragDrop obj
19148      * @method onDragEnter
19149      * @param {Event} e the mousemove event
19150      * @param {String|DragDrop[]} id In POINT mode, the element
19151      * id this is hovering over.  In INTERSECT mode, an array of one or more
19152      * dragdrop items being hovered over.
19153      */
19154     onDragEnter: function(e, id) { /* override this */ },
19155
19156     /**
19157      * Code that executes immediately before the onDragOver event
19158      * @method b4DragOver
19159      * @private
19160      */
19161     b4DragOver: function(e) { },
19162
19163     /**
19164      * Abstract method called when this element is hovering over another
19165      * DragDrop obj
19166      * @method onDragOver
19167      * @param {Event} e the mousemove event
19168      * @param {String|DragDrop[]} id In POINT mode, the element
19169      * id this is hovering over.  In INTERSECT mode, an array of dd items
19170      * being hovered over.
19171      */
19172     onDragOver: function(e, id) { /* override this */ },
19173
19174     /**
19175      * Code that executes immediately before the onDragOut event
19176      * @method b4DragOut
19177      * @private
19178      */
19179     b4DragOut: function(e) { },
19180
19181     /**
19182      * Abstract method called when we are no longer hovering over an element
19183      * @method onDragOut
19184      * @param {Event} e the mousemove event
19185      * @param {String|DragDrop[]} id In POINT mode, the element
19186      * id this was hovering over.  In INTERSECT mode, an array of dd items
19187      * that the mouse is no longer over.
19188      */
19189     onDragOut: function(e, id) { /* override this */ },
19190
19191     /**
19192      * Code that executes immediately before the onDragDrop event
19193      * @method b4DragDrop
19194      * @private
19195      */
19196     b4DragDrop: function(e) { },
19197
19198     /**
19199      * Abstract method called when this item is dropped on another DragDrop
19200      * obj
19201      * @method onDragDrop
19202      * @param {Event} e the mouseup event
19203      * @param {String|DragDrop[]} id In POINT mode, the element
19204      * id this was dropped on.  In INTERSECT mode, an array of dd items this
19205      * was dropped on.
19206      */
19207     onDragDrop: function(e, id) { /* override this */ },
19208
19209     /**
19210      * Abstract method called when this item is dropped on an area with no
19211      * drop target
19212      * @method onInvalidDrop
19213      * @param {Event} e the mouseup event
19214      */
19215     onInvalidDrop: function(e) { /* override this */ },
19216
19217     /**
19218      * Code that executes immediately before the endDrag event
19219      * @method b4EndDrag
19220      * @private
19221      */
19222     b4EndDrag: function(e) { },
19223
19224     /**
19225      * Fired when we are done dragging the object
19226      * @method endDrag
19227      * @param {Event} e the mouseup event
19228      */
19229     endDrag: function(e) { /* override this */ },
19230
19231     /**
19232      * Code executed immediately before the onMouseDown event
19233      * @method b4MouseDown
19234      * @param {Event} e the mousedown event
19235      * @private
19236      */
19237     b4MouseDown: function(e) {  },
19238
19239     /**
19240      * Event handler that fires when a drag/drop obj gets a mousedown
19241      * @method onMouseDown
19242      * @param {Event} e the mousedown event
19243      */
19244     onMouseDown: function(e) { /* override this */ },
19245
19246     /**
19247      * Event handler that fires when a drag/drop obj gets a mouseup
19248      * @method onMouseUp
19249      * @param {Event} e the mouseup event
19250      */
19251     onMouseUp: function(e) { /* override this */ },
19252
19253     /**
19254      * Override the onAvailable method to do what is needed after the initial
19255      * position was determined.
19256      * @method onAvailable
19257      */
19258     onAvailable: function () {
19259     },
19260
19261     /*
19262      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19263      * @type Object
19264      */
19265     defaultPadding : {left:0, right:0, top:0, bottom:0},
19266
19267     /*
19268      * Initializes the drag drop object's constraints to restrict movement to a certain element.
19269  *
19270  * Usage:
19271  <pre><code>
19272  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19273                 { dragElId: "existingProxyDiv" });
19274  dd.startDrag = function(){
19275      this.constrainTo("parent-id");
19276  };
19277  </code></pre>
19278  * Or you can initalize it using the {@link Roo.Element} object:
19279  <pre><code>
19280  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19281      startDrag : function(){
19282          this.constrainTo("parent-id");
19283      }
19284  });
19285  </code></pre>
19286      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19287      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19288      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19289      * an object containing the sides to pad. For example: {right:10, bottom:10}
19290      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19291      */
19292     constrainTo : function(constrainTo, pad, inContent){
19293         if(typeof pad == "number"){
19294             pad = {left: pad, right:pad, top:pad, bottom:pad};
19295         }
19296         pad = pad || this.defaultPadding;
19297         var b = Roo.get(this.getEl()).getBox();
19298         var ce = Roo.get(constrainTo);
19299         var s = ce.getScroll();
19300         var c, cd = ce.dom;
19301         if(cd == document.body){
19302             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19303         }else{
19304             xy = ce.getXY();
19305             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19306         }
19307
19308
19309         var topSpace = b.y - c.y;
19310         var leftSpace = b.x - c.x;
19311
19312         this.resetConstraints();
19313         this.setXConstraint(leftSpace - (pad.left||0), // left
19314                 c.width - leftSpace - b.width - (pad.right||0) //right
19315         );
19316         this.setYConstraint(topSpace - (pad.top||0), //top
19317                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19318         );
19319     },
19320
19321     /**
19322      * Returns a reference to the linked element
19323      * @method getEl
19324      * @return {HTMLElement} the html element
19325      */
19326     getEl: function() {
19327         if (!this._domRef) {
19328             this._domRef = Roo.getDom(this.id);
19329         }
19330
19331         return this._domRef;
19332     },
19333
19334     /**
19335      * Returns a reference to the actual element to drag.  By default this is
19336      * the same as the html element, but it can be assigned to another
19337      * element. An example of this can be found in Roo.dd.DDProxy
19338      * @method getDragEl
19339      * @return {HTMLElement} the html element
19340      */
19341     getDragEl: function() {
19342         return Roo.getDom(this.dragElId);
19343     },
19344
19345     /**
19346      * Sets up the DragDrop object.  Must be called in the constructor of any
19347      * Roo.dd.DragDrop subclass
19348      * @method init
19349      * @param id the id of the linked element
19350      * @param {String} sGroup the group of related items
19351      * @param {object} config configuration attributes
19352      */
19353     init: function(id, sGroup, config) {
19354         this.initTarget(id, sGroup, config);
19355         if (!Roo.isTouch) {
19356             Event.on(this.id, "mousedown", this.handleMouseDown, this);
19357         }
19358         Event.on(this.id, "touchstart", this.handleMouseDown, this);
19359         // Event.on(this.id, "selectstart", Event.preventDefault);
19360     },
19361
19362     /**
19363      * Initializes Targeting functionality only... the object does not
19364      * get a mousedown handler.
19365      * @method initTarget
19366      * @param id the id of the linked element
19367      * @param {String} sGroup the group of related items
19368      * @param {object} config configuration attributes
19369      */
19370     initTarget: function(id, sGroup, config) {
19371
19372         // configuration attributes
19373         this.config = config || {};
19374
19375         // create a local reference to the drag and drop manager
19376         this.DDM = Roo.dd.DDM;
19377         // initialize the groups array
19378         this.groups = {};
19379
19380         // assume that we have an element reference instead of an id if the
19381         // parameter is not a string
19382         if (typeof id !== "string") {
19383             id = Roo.id(id);
19384         }
19385
19386         // set the id
19387         this.id = id;
19388
19389         // add to an interaction group
19390         this.addToGroup((sGroup) ? sGroup : "default");
19391
19392         // We don't want to register this as the handle with the manager
19393         // so we just set the id rather than calling the setter.
19394         this.handleElId = id;
19395
19396         // the linked element is the element that gets dragged by default
19397         this.setDragElId(id);
19398
19399         // by default, clicked anchors will not start drag operations.
19400         this.invalidHandleTypes = { A: "A" };
19401         this.invalidHandleIds = {};
19402         this.invalidHandleClasses = [];
19403
19404         this.applyConfig();
19405
19406         this.handleOnAvailable();
19407     },
19408
19409     /**
19410      * Applies the configuration parameters that were passed into the constructor.
19411      * This is supposed to happen at each level through the inheritance chain.  So
19412      * a DDProxy implentation will execute apply config on DDProxy, DD, and
19413      * DragDrop in order to get all of the parameters that are available in
19414      * each object.
19415      * @method applyConfig
19416      */
19417     applyConfig: function() {
19418
19419         // configurable properties:
19420         //    padding, isTarget, maintainOffset, primaryButtonOnly
19421         this.padding           = this.config.padding || [0, 0, 0, 0];
19422         this.isTarget          = (this.config.isTarget !== false);
19423         this.maintainOffset    = (this.config.maintainOffset);
19424         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19425
19426     },
19427
19428     /**
19429      * Executed when the linked element is available
19430      * @method handleOnAvailable
19431      * @private
19432      */
19433     handleOnAvailable: function() {
19434         this.available = true;
19435         this.resetConstraints();
19436         this.onAvailable();
19437     },
19438
19439      /**
19440      * Configures the padding for the target zone in px.  Effectively expands
19441      * (or reduces) the virtual object size for targeting calculations.
19442      * Supports css-style shorthand; if only one parameter is passed, all sides
19443      * will have that padding, and if only two are passed, the top and bottom
19444      * will have the first param, the left and right the second.
19445      * @method setPadding
19446      * @param {int} iTop    Top pad
19447      * @param {int} iRight  Right pad
19448      * @param {int} iBot    Bot pad
19449      * @param {int} iLeft   Left pad
19450      */
19451     setPadding: function(iTop, iRight, iBot, iLeft) {
19452         // this.padding = [iLeft, iRight, iTop, iBot];
19453         if (!iRight && 0 !== iRight) {
19454             this.padding = [iTop, iTop, iTop, iTop];
19455         } else if (!iBot && 0 !== iBot) {
19456             this.padding = [iTop, iRight, iTop, iRight];
19457         } else {
19458             this.padding = [iTop, iRight, iBot, iLeft];
19459         }
19460     },
19461
19462     /**
19463      * Stores the initial placement of the linked element.
19464      * @method setInitialPosition
19465      * @param {int} diffX   the X offset, default 0
19466      * @param {int} diffY   the Y offset, default 0
19467      */
19468     setInitPosition: function(diffX, diffY) {
19469         var el = this.getEl();
19470
19471         if (!this.DDM.verifyEl(el)) {
19472             return;
19473         }
19474
19475         var dx = diffX || 0;
19476         var dy = diffY || 0;
19477
19478         var p = Dom.getXY( el );
19479
19480         this.initPageX = p[0] - dx;
19481         this.initPageY = p[1] - dy;
19482
19483         this.lastPageX = p[0];
19484         this.lastPageY = p[1];
19485
19486
19487         this.setStartPosition(p);
19488     },
19489
19490     /**
19491      * Sets the start position of the element.  This is set when the obj
19492      * is initialized, the reset when a drag is started.
19493      * @method setStartPosition
19494      * @param pos current position (from previous lookup)
19495      * @private
19496      */
19497     setStartPosition: function(pos) {
19498         var p = pos || Dom.getXY( this.getEl() );
19499         this.deltaSetXY = null;
19500
19501         this.startPageX = p[0];
19502         this.startPageY = p[1];
19503     },
19504
19505     /**
19506      * Add this instance to a group of related drag/drop objects.  All
19507      * instances belong to at least one group, and can belong to as many
19508      * groups as needed.
19509      * @method addToGroup
19510      * @param sGroup {string} the name of the group
19511      */
19512     addToGroup: function(sGroup) {
19513         this.groups[sGroup] = true;
19514         this.DDM.regDragDrop(this, sGroup);
19515     },
19516
19517     /**
19518      * Remove's this instance from the supplied interaction group
19519      * @method removeFromGroup
19520      * @param {string}  sGroup  The group to drop
19521      */
19522     removeFromGroup: function(sGroup) {
19523         if (this.groups[sGroup]) {
19524             delete this.groups[sGroup];
19525         }
19526
19527         this.DDM.removeDDFromGroup(this, sGroup);
19528     },
19529
19530     /**
19531      * Allows you to specify that an element other than the linked element
19532      * will be moved with the cursor during a drag
19533      * @method setDragElId
19534      * @param id {string} the id of the element that will be used to initiate the drag
19535      */
19536     setDragElId: function(id) {
19537         this.dragElId = id;
19538     },
19539
19540     /**
19541      * Allows you to specify a child of the linked element that should be
19542      * used to initiate the drag operation.  An example of this would be if
19543      * you have a content div with text and links.  Clicking anywhere in the
19544      * content area would normally start the drag operation.  Use this method
19545      * to specify that an element inside of the content div is the element
19546      * that starts the drag operation.
19547      * @method setHandleElId
19548      * @param id {string} the id of the element that will be used to
19549      * initiate the drag.
19550      */
19551     setHandleElId: function(id) {
19552         if (typeof id !== "string") {
19553             id = Roo.id(id);
19554         }
19555         this.handleElId = id;
19556         this.DDM.regHandle(this.id, id);
19557     },
19558
19559     /**
19560      * Allows you to set an element outside of the linked element as a drag
19561      * handle
19562      * @method setOuterHandleElId
19563      * @param id the id of the element that will be used to initiate the drag
19564      */
19565     setOuterHandleElId: function(id) {
19566         if (typeof id !== "string") {
19567             id = Roo.id(id);
19568         }
19569         Event.on(id, "mousedown",
19570                 this.handleMouseDown, this);
19571         this.setHandleElId(id);
19572
19573         this.hasOuterHandles = true;
19574     },
19575
19576     /**
19577      * Remove all drag and drop hooks for this element
19578      * @method unreg
19579      */
19580     unreg: function() {
19581         Event.un(this.id, "mousedown",
19582                 this.handleMouseDown);
19583         Event.un(this.id, "touchstart",
19584                 this.handleMouseDown);
19585         this._domRef = null;
19586         this.DDM._remove(this);
19587     },
19588
19589     destroy : function(){
19590         this.unreg();
19591     },
19592
19593     /**
19594      * Returns true if this instance is locked, or the drag drop mgr is locked
19595      * (meaning that all drag/drop is disabled on the page.)
19596      * @method isLocked
19597      * @return {boolean} true if this obj or all drag/drop is locked, else
19598      * false
19599      */
19600     isLocked: function() {
19601         return (this.DDM.isLocked() || this.locked);
19602     },
19603
19604     /**
19605      * Fired when this object is clicked
19606      * @method handleMouseDown
19607      * @param {Event} e
19608      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19609      * @private
19610      */
19611     handleMouseDown: function(e, oDD){
19612      
19613         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19614             //Roo.log('not touch/ button !=0');
19615             return;
19616         }
19617         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19618             return; // double touch..
19619         }
19620         
19621
19622         if (this.isLocked()) {
19623             //Roo.log('locked');
19624             return;
19625         }
19626
19627         this.DDM.refreshCache(this.groups);
19628 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19629         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19630         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
19631             //Roo.log('no outer handes or not over target');
19632                 // do nothing.
19633         } else {
19634 //            Roo.log('check validator');
19635             if (this.clickValidator(e)) {
19636 //                Roo.log('validate success');
19637                 // set the initial element position
19638                 this.setStartPosition();
19639
19640
19641                 this.b4MouseDown(e);
19642                 this.onMouseDown(e);
19643
19644                 this.DDM.handleMouseDown(e, this);
19645
19646                 this.DDM.stopEvent(e);
19647             } else {
19648
19649
19650             }
19651         }
19652     },
19653
19654     clickValidator: function(e) {
19655         var target = e.getTarget();
19656         return ( this.isValidHandleChild(target) &&
19657                     (this.id == this.handleElId ||
19658                         this.DDM.handleWasClicked(target, this.id)) );
19659     },
19660
19661     /**
19662      * Allows you to specify a tag name that should not start a drag operation
19663      * when clicked.  This is designed to facilitate embedding links within a
19664      * drag handle that do something other than start the drag.
19665      * @method addInvalidHandleType
19666      * @param {string} tagName the type of element to exclude
19667      */
19668     addInvalidHandleType: function(tagName) {
19669         var type = tagName.toUpperCase();
19670         this.invalidHandleTypes[type] = type;
19671     },
19672
19673     /**
19674      * Lets you to specify an element id for a child of a drag handle
19675      * that should not initiate a drag
19676      * @method addInvalidHandleId
19677      * @param {string} id the element id of the element you wish to ignore
19678      */
19679     addInvalidHandleId: function(id) {
19680         if (typeof id !== "string") {
19681             id = Roo.id(id);
19682         }
19683         this.invalidHandleIds[id] = id;
19684     },
19685
19686     /**
19687      * Lets you specify a css class of elements that will not initiate a drag
19688      * @method addInvalidHandleClass
19689      * @param {string} cssClass the class of the elements you wish to ignore
19690      */
19691     addInvalidHandleClass: function(cssClass) {
19692         this.invalidHandleClasses.push(cssClass);
19693     },
19694
19695     /**
19696      * Unsets an excluded tag name set by addInvalidHandleType
19697      * @method removeInvalidHandleType
19698      * @param {string} tagName the type of element to unexclude
19699      */
19700     removeInvalidHandleType: function(tagName) {
19701         var type = tagName.toUpperCase();
19702         // this.invalidHandleTypes[type] = null;
19703         delete this.invalidHandleTypes[type];
19704     },
19705
19706     /**
19707      * Unsets an invalid handle id
19708      * @method removeInvalidHandleId
19709      * @param {string} id the id of the element to re-enable
19710      */
19711     removeInvalidHandleId: function(id) {
19712         if (typeof id !== "string") {
19713             id = Roo.id(id);
19714         }
19715         delete this.invalidHandleIds[id];
19716     },
19717
19718     /**
19719      * Unsets an invalid css class
19720      * @method removeInvalidHandleClass
19721      * @param {string} cssClass the class of the element(s) you wish to
19722      * re-enable
19723      */
19724     removeInvalidHandleClass: function(cssClass) {
19725         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19726             if (this.invalidHandleClasses[i] == cssClass) {
19727                 delete this.invalidHandleClasses[i];
19728             }
19729         }
19730     },
19731
19732     /**
19733      * Checks the tag exclusion list to see if this click should be ignored
19734      * @method isValidHandleChild
19735      * @param {HTMLElement} node the HTMLElement to evaluate
19736      * @return {boolean} true if this is a valid tag type, false if not
19737      */
19738     isValidHandleChild: function(node) {
19739
19740         var valid = true;
19741         // var n = (node.nodeName == "#text") ? node.parentNode : node;
19742         var nodeName;
19743         try {
19744             nodeName = node.nodeName.toUpperCase();
19745         } catch(e) {
19746             nodeName = node.nodeName;
19747         }
19748         valid = valid && !this.invalidHandleTypes[nodeName];
19749         valid = valid && !this.invalidHandleIds[node.id];
19750
19751         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19752             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19753         }
19754
19755
19756         return valid;
19757
19758     },
19759
19760     /**
19761      * Create the array of horizontal tick marks if an interval was specified
19762      * in setXConstraint().
19763      * @method setXTicks
19764      * @private
19765      */
19766     setXTicks: function(iStartX, iTickSize) {
19767         this.xTicks = [];
19768         this.xTickSize = iTickSize;
19769
19770         var tickMap = {};
19771
19772         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19773             if (!tickMap[i]) {
19774                 this.xTicks[this.xTicks.length] = i;
19775                 tickMap[i] = true;
19776             }
19777         }
19778
19779         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19780             if (!tickMap[i]) {
19781                 this.xTicks[this.xTicks.length] = i;
19782                 tickMap[i] = true;
19783             }
19784         }
19785
19786         this.xTicks.sort(this.DDM.numericSort) ;
19787     },
19788
19789     /**
19790      * Create the array of vertical tick marks if an interval was specified in
19791      * setYConstraint().
19792      * @method setYTicks
19793      * @private
19794      */
19795     setYTicks: function(iStartY, iTickSize) {
19796         this.yTicks = [];
19797         this.yTickSize = iTickSize;
19798
19799         var tickMap = {};
19800
19801         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19802             if (!tickMap[i]) {
19803                 this.yTicks[this.yTicks.length] = i;
19804                 tickMap[i] = true;
19805             }
19806         }
19807
19808         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19809             if (!tickMap[i]) {
19810                 this.yTicks[this.yTicks.length] = i;
19811                 tickMap[i] = true;
19812             }
19813         }
19814
19815         this.yTicks.sort(this.DDM.numericSort) ;
19816     },
19817
19818     /**
19819      * By default, the element can be dragged any place on the screen.  Use
19820      * this method to limit the horizontal travel of the element.  Pass in
19821      * 0,0 for the parameters if you want to lock the drag to the y axis.
19822      * @method setXConstraint
19823      * @param {int} iLeft the number of pixels the element can move to the left
19824      * @param {int} iRight the number of pixels the element can move to the
19825      * right
19826      * @param {int} iTickSize optional parameter for specifying that the
19827      * element
19828      * should move iTickSize pixels at a time.
19829      */
19830     setXConstraint: function(iLeft, iRight, iTickSize) {
19831         this.leftConstraint = iLeft;
19832         this.rightConstraint = iRight;
19833
19834         this.minX = this.initPageX - iLeft;
19835         this.maxX = this.initPageX + iRight;
19836         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19837
19838         this.constrainX = true;
19839     },
19840
19841     /**
19842      * Clears any constraints applied to this instance.  Also clears ticks
19843      * since they can't exist independent of a constraint at this time.
19844      * @method clearConstraints
19845      */
19846     clearConstraints: function() {
19847         this.constrainX = false;
19848         this.constrainY = false;
19849         this.clearTicks();
19850     },
19851
19852     /**
19853      * Clears any tick interval defined for this instance
19854      * @method clearTicks
19855      */
19856     clearTicks: function() {
19857         this.xTicks = null;
19858         this.yTicks = null;
19859         this.xTickSize = 0;
19860         this.yTickSize = 0;
19861     },
19862
19863     /**
19864      * By default, the element can be dragged any place on the screen.  Set
19865      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19866      * parameters if you want to lock the drag to the x axis.
19867      * @method setYConstraint
19868      * @param {int} iUp the number of pixels the element can move up
19869      * @param {int} iDown the number of pixels the element can move down
19870      * @param {int} iTickSize optional parameter for specifying that the
19871      * element should move iTickSize pixels at a time.
19872      */
19873     setYConstraint: function(iUp, iDown, iTickSize) {
19874         this.topConstraint = iUp;
19875         this.bottomConstraint = iDown;
19876
19877         this.minY = this.initPageY - iUp;
19878         this.maxY = this.initPageY + iDown;
19879         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19880
19881         this.constrainY = true;
19882
19883     },
19884
19885     /**
19886      * resetConstraints must be called if you manually reposition a dd element.
19887      * @method resetConstraints
19888      * @param {boolean} maintainOffset
19889      */
19890     resetConstraints: function() {
19891
19892
19893         // Maintain offsets if necessary
19894         if (this.initPageX || this.initPageX === 0) {
19895             // figure out how much this thing has moved
19896             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19897             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19898
19899             this.setInitPosition(dx, dy);
19900
19901         // This is the first time we have detected the element's position
19902         } else {
19903             this.setInitPosition();
19904         }
19905
19906         if (this.constrainX) {
19907             this.setXConstraint( this.leftConstraint,
19908                                  this.rightConstraint,
19909                                  this.xTickSize        );
19910         }
19911
19912         if (this.constrainY) {
19913             this.setYConstraint( this.topConstraint,
19914                                  this.bottomConstraint,
19915                                  this.yTickSize         );
19916         }
19917     },
19918
19919     /**
19920      * Normally the drag element is moved pixel by pixel, but we can specify
19921      * that it move a number of pixels at a time.  This method resolves the
19922      * location when we have it set up like this.
19923      * @method getTick
19924      * @param {int} val where we want to place the object
19925      * @param {int[]} tickArray sorted array of valid points
19926      * @return {int} the closest tick
19927      * @private
19928      */
19929     getTick: function(val, tickArray) {
19930
19931         if (!tickArray) {
19932             // If tick interval is not defined, it is effectively 1 pixel,
19933             // so we return the value passed to us.
19934             return val;
19935         } else if (tickArray[0] >= val) {
19936             // The value is lower than the first tick, so we return the first
19937             // tick.
19938             return tickArray[0];
19939         } else {
19940             for (var i=0, len=tickArray.length; i<len; ++i) {
19941                 var next = i + 1;
19942                 if (tickArray[next] && tickArray[next] >= val) {
19943                     var diff1 = val - tickArray[i];
19944                     var diff2 = tickArray[next] - val;
19945                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19946                 }
19947             }
19948
19949             // The value is larger than the last tick, so we return the last
19950             // tick.
19951             return tickArray[tickArray.length - 1];
19952         }
19953     },
19954
19955     /**
19956      * toString method
19957      * @method toString
19958      * @return {string} string representation of the dd obj
19959      */
19960     toString: function() {
19961         return ("DragDrop " + this.id);
19962     }
19963
19964 });
19965
19966 })();
19967 /*
19968  * Based on:
19969  * Ext JS Library 1.1.1
19970  * Copyright(c) 2006-2007, Ext JS, LLC.
19971  *
19972  * Originally Released Under LGPL - original licence link has changed is not relivant.
19973  *
19974  * Fork - LGPL
19975  * <script type="text/javascript">
19976  */
19977
19978
19979 /**
19980  * The drag and drop utility provides a framework for building drag and drop
19981  * applications.  In addition to enabling drag and drop for specific elements,
19982  * the drag and drop elements are tracked by the manager class, and the
19983  * interactions between the various elements are tracked during the drag and
19984  * the implementing code is notified about these important moments.
19985  */
19986
19987 // Only load the library once.  Rewriting the manager class would orphan
19988 // existing drag and drop instances.
19989 if (!Roo.dd.DragDropMgr) {
19990
19991 /**
19992  * @class Roo.dd.DragDropMgr
19993  * DragDropMgr is a singleton that tracks the element interaction for
19994  * all DragDrop items in the window.  Generally, you will not call
19995  * this class directly, but it does have helper methods that could
19996  * be useful in your DragDrop implementations.
19997  * @singleton
19998  */
19999 Roo.dd.DragDropMgr = function() {
20000
20001     var Event = Roo.EventManager;
20002
20003     return {
20004
20005         /**
20006          * Two dimensional Array of registered DragDrop objects.  The first
20007          * dimension is the DragDrop item group, the second the DragDrop
20008          * object.
20009          * @property ids
20010          * @type {string: string}
20011          * @private
20012          * @static
20013          */
20014         ids: {},
20015
20016         /**
20017          * Array of element ids defined as drag handles.  Used to determine
20018          * if the element that generated the mousedown event is actually the
20019          * handle and not the html element itself.
20020          * @property handleIds
20021          * @type {string: string}
20022          * @private
20023          * @static
20024          */
20025         handleIds: {},
20026
20027         /**
20028          * the DragDrop object that is currently being dragged
20029          * @property dragCurrent
20030          * @type DragDrop
20031          * @private
20032          * @static
20033          **/
20034         dragCurrent: null,
20035
20036         /**
20037          * the DragDrop object(s) that are being hovered over
20038          * @property dragOvers
20039          * @type Array
20040          * @private
20041          * @static
20042          */
20043         dragOvers: {},
20044
20045         /**
20046          * the X distance between the cursor and the object being dragged
20047          * @property deltaX
20048          * @type int
20049          * @private
20050          * @static
20051          */
20052         deltaX: 0,
20053
20054         /**
20055          * the Y distance between the cursor and the object being dragged
20056          * @property deltaY
20057          * @type int
20058          * @private
20059          * @static
20060          */
20061         deltaY: 0,
20062
20063         /**
20064          * Flag to determine if we should prevent the default behavior of the
20065          * events we define. By default this is true, but this can be set to
20066          * false if you need the default behavior (not recommended)
20067          * @property preventDefault
20068          * @type boolean
20069          * @static
20070          */
20071         preventDefault: true,
20072
20073         /**
20074          * Flag to determine if we should stop the propagation of the events
20075          * we generate. This is true by default but you may want to set it to
20076          * false if the html element contains other features that require the
20077          * mouse click.
20078          * @property stopPropagation
20079          * @type boolean
20080          * @static
20081          */
20082         stopPropagation: true,
20083
20084         /**
20085          * Internal flag that is set to true when drag and drop has been
20086          * intialized
20087          * @property initialized
20088          * @private
20089          * @static
20090          */
20091         initalized: false,
20092
20093         /**
20094          * All drag and drop can be disabled.
20095          * @property locked
20096          * @private
20097          * @static
20098          */
20099         locked: false,
20100
20101         /**
20102          * Called the first time an element is registered.
20103          * @method init
20104          * @private
20105          * @static
20106          */
20107         init: function() {
20108             this.initialized = true;
20109         },
20110
20111         /**
20112          * In point mode, drag and drop interaction is defined by the
20113          * location of the cursor during the drag/drop
20114          * @property POINT
20115          * @type int
20116          * @static
20117          */
20118         POINT: 0,
20119
20120         /**
20121          * In intersect mode, drag and drop interactio nis defined by the
20122          * overlap of two or more drag and drop objects.
20123          * @property INTERSECT
20124          * @type int
20125          * @static
20126          */
20127         INTERSECT: 1,
20128
20129         /**
20130          * The current drag and drop mode.  Default: POINT
20131          * @property mode
20132          * @type int
20133          * @static
20134          */
20135         mode: 0,
20136
20137         /**
20138          * Runs method on all drag and drop objects
20139          * @method _execOnAll
20140          * @private
20141          * @static
20142          */
20143         _execOnAll: function(sMethod, args) {
20144             for (var i in this.ids) {
20145                 for (var j in this.ids[i]) {
20146                     var oDD = this.ids[i][j];
20147                     if (! this.isTypeOfDD(oDD)) {
20148                         continue;
20149                     }
20150                     oDD[sMethod].apply(oDD, args);
20151                 }
20152             }
20153         },
20154
20155         /**
20156          * Drag and drop initialization.  Sets up the global event handlers
20157          * @method _onLoad
20158          * @private
20159          * @static
20160          */
20161         _onLoad: function() {
20162
20163             this.init();
20164
20165             if (!Roo.isTouch) {
20166                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
20167                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20168             }
20169             Event.on(document, "touchend",   this.handleMouseUp, this, true);
20170             Event.on(document, "touchmove", this.handleMouseMove, this, true);
20171             
20172             Event.on(window,   "unload",    this._onUnload, this, true);
20173             Event.on(window,   "resize",    this._onResize, this, true);
20174             // Event.on(window,   "mouseout",    this._test);
20175
20176         },
20177
20178         /**
20179          * Reset constraints on all drag and drop objs
20180          * @method _onResize
20181          * @private
20182          * @static
20183          */
20184         _onResize: function(e) {
20185             this._execOnAll("resetConstraints", []);
20186         },
20187
20188         /**
20189          * Lock all drag and drop functionality
20190          * @method lock
20191          * @static
20192          */
20193         lock: function() { this.locked = true; },
20194
20195         /**
20196          * Unlock all drag and drop functionality
20197          * @method unlock
20198          * @static
20199          */
20200         unlock: function() { this.locked = false; },
20201
20202         /**
20203          * Is drag and drop locked?
20204          * @method isLocked
20205          * @return {boolean} True if drag and drop is locked, false otherwise.
20206          * @static
20207          */
20208         isLocked: function() { return this.locked; },
20209
20210         /**
20211          * Location cache that is set for all drag drop objects when a drag is
20212          * initiated, cleared when the drag is finished.
20213          * @property locationCache
20214          * @private
20215          * @static
20216          */
20217         locationCache: {},
20218
20219         /**
20220          * Set useCache to false if you want to force object the lookup of each
20221          * drag and drop linked element constantly during a drag.
20222          * @property useCache
20223          * @type boolean
20224          * @static
20225          */
20226         useCache: true,
20227
20228         /**
20229          * The number of pixels that the mouse needs to move after the
20230          * mousedown before the drag is initiated.  Default=3;
20231          * @property clickPixelThresh
20232          * @type int
20233          * @static
20234          */
20235         clickPixelThresh: 3,
20236
20237         /**
20238          * The number of milliseconds after the mousedown event to initiate the
20239          * drag if we don't get a mouseup event. Default=1000
20240          * @property clickTimeThresh
20241          * @type int
20242          * @static
20243          */
20244         clickTimeThresh: 350,
20245
20246         /**
20247          * Flag that indicates that either the drag pixel threshold or the
20248          * mousdown time threshold has been met
20249          * @property dragThreshMet
20250          * @type boolean
20251          * @private
20252          * @static
20253          */
20254         dragThreshMet: false,
20255
20256         /**
20257          * Timeout used for the click time threshold
20258          * @property clickTimeout
20259          * @type Object
20260          * @private
20261          * @static
20262          */
20263         clickTimeout: null,
20264
20265         /**
20266          * The X position of the mousedown event stored for later use when a
20267          * drag threshold is met.
20268          * @property startX
20269          * @type int
20270          * @private
20271          * @static
20272          */
20273         startX: 0,
20274
20275         /**
20276          * The Y position of the mousedown event stored for later use when a
20277          * drag threshold is met.
20278          * @property startY
20279          * @type int
20280          * @private
20281          * @static
20282          */
20283         startY: 0,
20284
20285         /**
20286          * Each DragDrop instance must be registered with the DragDropMgr.
20287          * This is executed in DragDrop.init()
20288          * @method regDragDrop
20289          * @param {DragDrop} oDD the DragDrop object to register
20290          * @param {String} sGroup the name of the group this element belongs to
20291          * @static
20292          */
20293         regDragDrop: function(oDD, sGroup) {
20294             if (!this.initialized) { this.init(); }
20295
20296             if (!this.ids[sGroup]) {
20297                 this.ids[sGroup] = {};
20298             }
20299             this.ids[sGroup][oDD.id] = oDD;
20300         },
20301
20302         /**
20303          * Removes the supplied dd instance from the supplied group. Executed
20304          * by DragDrop.removeFromGroup, so don't call this function directly.
20305          * @method removeDDFromGroup
20306          * @private
20307          * @static
20308          */
20309         removeDDFromGroup: function(oDD, sGroup) {
20310             if (!this.ids[sGroup]) {
20311                 this.ids[sGroup] = {};
20312             }
20313
20314             var obj = this.ids[sGroup];
20315             if (obj && obj[oDD.id]) {
20316                 delete obj[oDD.id];
20317             }
20318         },
20319
20320         /**
20321          * Unregisters a drag and drop item.  This is executed in
20322          * DragDrop.unreg, use that method instead of calling this directly.
20323          * @method _remove
20324          * @private
20325          * @static
20326          */
20327         _remove: function(oDD) {
20328             for (var g in oDD.groups) {
20329                 if (g && this.ids[g][oDD.id]) {
20330                     delete this.ids[g][oDD.id];
20331                 }
20332             }
20333             delete this.handleIds[oDD.id];
20334         },
20335
20336         /**
20337          * Each DragDrop handle element must be registered.  This is done
20338          * automatically when executing DragDrop.setHandleElId()
20339          * @method regHandle
20340          * @param {String} sDDId the DragDrop id this element is a handle for
20341          * @param {String} sHandleId the id of the element that is the drag
20342          * handle
20343          * @static
20344          */
20345         regHandle: function(sDDId, sHandleId) {
20346             if (!this.handleIds[sDDId]) {
20347                 this.handleIds[sDDId] = {};
20348             }
20349             this.handleIds[sDDId][sHandleId] = sHandleId;
20350         },
20351
20352         /**
20353          * Utility function to determine if a given element has been
20354          * registered as a drag drop item.
20355          * @method isDragDrop
20356          * @param {String} id the element id to check
20357          * @return {boolean} true if this element is a DragDrop item,
20358          * false otherwise
20359          * @static
20360          */
20361         isDragDrop: function(id) {
20362             return ( this.getDDById(id) ) ? true : false;
20363         },
20364
20365         /**
20366          * Returns the drag and drop instances that are in all groups the
20367          * passed in instance belongs to.
20368          * @method getRelated
20369          * @param {DragDrop} p_oDD the obj to get related data for
20370          * @param {boolean} bTargetsOnly if true, only return targetable objs
20371          * @return {DragDrop[]} the related instances
20372          * @static
20373          */
20374         getRelated: function(p_oDD, bTargetsOnly) {
20375             var oDDs = [];
20376             for (var i in p_oDD.groups) {
20377                 for (j in this.ids[i]) {
20378                     var dd = this.ids[i][j];
20379                     if (! this.isTypeOfDD(dd)) {
20380                         continue;
20381                     }
20382                     if (!bTargetsOnly || dd.isTarget) {
20383                         oDDs[oDDs.length] = dd;
20384                     }
20385                 }
20386             }
20387
20388             return oDDs;
20389         },
20390
20391         /**
20392          * Returns true if the specified dd target is a legal target for
20393          * the specifice drag obj
20394          * @method isLegalTarget
20395          * @param {DragDrop} the drag obj
20396          * @param {DragDrop} the target
20397          * @return {boolean} true if the target is a legal target for the
20398          * dd obj
20399          * @static
20400          */
20401         isLegalTarget: function (oDD, oTargetDD) {
20402             var targets = this.getRelated(oDD, true);
20403             for (var i=0, len=targets.length;i<len;++i) {
20404                 if (targets[i].id == oTargetDD.id) {
20405                     return true;
20406                 }
20407             }
20408
20409             return false;
20410         },
20411
20412         /**
20413          * My goal is to be able to transparently determine if an object is
20414          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
20415          * returns "object", oDD.constructor.toString() always returns
20416          * "DragDrop" and not the name of the subclass.  So for now it just
20417          * evaluates a well-known variable in DragDrop.
20418          * @method isTypeOfDD
20419          * @param {Object} the object to evaluate
20420          * @return {boolean} true if typeof oDD = DragDrop
20421          * @static
20422          */
20423         isTypeOfDD: function (oDD) {
20424             return (oDD && oDD.__ygDragDrop);
20425         },
20426
20427         /**
20428          * Utility function to determine if a given element has been
20429          * registered as a drag drop handle for the given Drag Drop object.
20430          * @method isHandle
20431          * @param {String} id the element id to check
20432          * @return {boolean} true if this element is a DragDrop handle, false
20433          * otherwise
20434          * @static
20435          */
20436         isHandle: function(sDDId, sHandleId) {
20437             return ( this.handleIds[sDDId] &&
20438                             this.handleIds[sDDId][sHandleId] );
20439         },
20440
20441         /**
20442          * Returns the DragDrop instance for a given id
20443          * @method getDDById
20444          * @param {String} id the id of the DragDrop object
20445          * @return {DragDrop} the drag drop object, null if it is not found
20446          * @static
20447          */
20448         getDDById: function(id) {
20449             for (var i in this.ids) {
20450                 if (this.ids[i][id]) {
20451                     return this.ids[i][id];
20452                 }
20453             }
20454             return null;
20455         },
20456
20457         /**
20458          * Fired after a registered DragDrop object gets the mousedown event.
20459          * Sets up the events required to track the object being dragged
20460          * @method handleMouseDown
20461          * @param {Event} e the event
20462          * @param oDD the DragDrop object being dragged
20463          * @private
20464          * @static
20465          */
20466         handleMouseDown: function(e, oDD) {
20467             if(Roo.QuickTips){
20468                 Roo.QuickTips.disable();
20469             }
20470             this.currentTarget = e.getTarget();
20471
20472             this.dragCurrent = oDD;
20473
20474             var el = oDD.getEl();
20475
20476             // track start position
20477             this.startX = e.getPageX();
20478             this.startY = e.getPageY();
20479
20480             this.deltaX = this.startX - el.offsetLeft;
20481             this.deltaY = this.startY - el.offsetTop;
20482
20483             this.dragThreshMet = false;
20484
20485             this.clickTimeout = setTimeout(
20486                     function() {
20487                         var DDM = Roo.dd.DDM;
20488                         DDM.startDrag(DDM.startX, DDM.startY);
20489                     },
20490                     this.clickTimeThresh );
20491         },
20492
20493         /**
20494          * Fired when either the drag pixel threshol or the mousedown hold
20495          * time threshold has been met.
20496          * @method startDrag
20497          * @param x {int} the X position of the original mousedown
20498          * @param y {int} the Y position of the original mousedown
20499          * @static
20500          */
20501         startDrag: function(x, y) {
20502             clearTimeout(this.clickTimeout);
20503             if (this.dragCurrent) {
20504                 this.dragCurrent.b4StartDrag(x, y);
20505                 this.dragCurrent.startDrag(x, y);
20506             }
20507             this.dragThreshMet = true;
20508         },
20509
20510         /**
20511          * Internal function to handle the mouseup event.  Will be invoked
20512          * from the context of the document.
20513          * @method handleMouseUp
20514          * @param {Event} e the event
20515          * @private
20516          * @static
20517          */
20518         handleMouseUp: function(e) {
20519
20520             if(Roo.QuickTips){
20521                 Roo.QuickTips.enable();
20522             }
20523             if (! this.dragCurrent) {
20524                 return;
20525             }
20526
20527             clearTimeout(this.clickTimeout);
20528
20529             if (this.dragThreshMet) {
20530                 this.fireEvents(e, true);
20531             } else {
20532             }
20533
20534             this.stopDrag(e);
20535
20536             this.stopEvent(e);
20537         },
20538
20539         /**
20540          * Utility to stop event propagation and event default, if these
20541          * features are turned on.
20542          * @method stopEvent
20543          * @param {Event} e the event as returned by this.getEvent()
20544          * @static
20545          */
20546         stopEvent: function(e){
20547             if(this.stopPropagation) {
20548                 e.stopPropagation();
20549             }
20550
20551             if (this.preventDefault) {
20552                 e.preventDefault();
20553             }
20554         },
20555
20556         /**
20557          * Internal function to clean up event handlers after the drag
20558          * operation is complete
20559          * @method stopDrag
20560          * @param {Event} e the event
20561          * @private
20562          * @static
20563          */
20564         stopDrag: function(e) {
20565             // Fire the drag end event for the item that was dragged
20566             if (this.dragCurrent) {
20567                 if (this.dragThreshMet) {
20568                     this.dragCurrent.b4EndDrag(e);
20569                     this.dragCurrent.endDrag(e);
20570                 }
20571
20572                 this.dragCurrent.onMouseUp(e);
20573             }
20574
20575             this.dragCurrent = null;
20576             this.dragOvers = {};
20577         },
20578
20579         /**
20580          * Internal function to handle the mousemove event.  Will be invoked
20581          * from the context of the html element.
20582          *
20583          * @TODO figure out what we can do about mouse events lost when the
20584          * user drags objects beyond the window boundary.  Currently we can
20585          * detect this in internet explorer by verifying that the mouse is
20586          * down during the mousemove event.  Firefox doesn't give us the
20587          * button state on the mousemove event.
20588          * @method handleMouseMove
20589          * @param {Event} e the event
20590          * @private
20591          * @static
20592          */
20593         handleMouseMove: function(e) {
20594             if (! this.dragCurrent) {
20595                 return true;
20596             }
20597
20598             // var button = e.which || e.button;
20599
20600             // check for IE mouseup outside of page boundary
20601             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20602                 this.stopEvent(e);
20603                 return this.handleMouseUp(e);
20604             }
20605
20606             if (!this.dragThreshMet) {
20607                 var diffX = Math.abs(this.startX - e.getPageX());
20608                 var diffY = Math.abs(this.startY - e.getPageY());
20609                 if (diffX > this.clickPixelThresh ||
20610                             diffY > this.clickPixelThresh) {
20611                     this.startDrag(this.startX, this.startY);
20612                 }
20613             }
20614
20615             if (this.dragThreshMet) {
20616                 this.dragCurrent.b4Drag(e);
20617                 this.dragCurrent.onDrag(e);
20618                 if(!this.dragCurrent.moveOnly){
20619                     this.fireEvents(e, false);
20620                 }
20621             }
20622
20623             this.stopEvent(e);
20624
20625             return true;
20626         },
20627
20628         /**
20629          * Iterates over all of the DragDrop elements to find ones we are
20630          * hovering over or dropping on
20631          * @method fireEvents
20632          * @param {Event} e the event
20633          * @param {boolean} isDrop is this a drop op or a mouseover op?
20634          * @private
20635          * @static
20636          */
20637         fireEvents: function(e, isDrop) {
20638             var dc = this.dragCurrent;
20639
20640             // If the user did the mouse up outside of the window, we could
20641             // get here even though we have ended the drag.
20642             if (!dc || dc.isLocked()) {
20643                 return;
20644             }
20645
20646             var pt = e.getPoint();
20647
20648             // cache the previous dragOver array
20649             var oldOvers = [];
20650
20651             var outEvts   = [];
20652             var overEvts  = [];
20653             var dropEvts  = [];
20654             var enterEvts = [];
20655
20656             // Check to see if the object(s) we were hovering over is no longer
20657             // being hovered over so we can fire the onDragOut event
20658             for (var i in this.dragOvers) {
20659
20660                 var ddo = this.dragOvers[i];
20661
20662                 if (! this.isTypeOfDD(ddo)) {
20663                     continue;
20664                 }
20665
20666                 if (! this.isOverTarget(pt, ddo, this.mode)) {
20667                     outEvts.push( ddo );
20668                 }
20669
20670                 oldOvers[i] = true;
20671                 delete this.dragOvers[i];
20672             }
20673
20674             for (var sGroup in dc.groups) {
20675
20676                 if ("string" != typeof sGroup) {
20677                     continue;
20678                 }
20679
20680                 for (i in this.ids[sGroup]) {
20681                     var oDD = this.ids[sGroup][i];
20682                     if (! this.isTypeOfDD(oDD)) {
20683                         continue;
20684                     }
20685
20686                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20687                         if (this.isOverTarget(pt, oDD, this.mode)) {
20688                             // look for drop interactions
20689                             if (isDrop) {
20690                                 dropEvts.push( oDD );
20691                             // look for drag enter and drag over interactions
20692                             } else {
20693
20694                                 // initial drag over: dragEnter fires
20695                                 if (!oldOvers[oDD.id]) {
20696                                     enterEvts.push( oDD );
20697                                 // subsequent drag overs: dragOver fires
20698                                 } else {
20699                                     overEvts.push( oDD );
20700                                 }
20701
20702                                 this.dragOvers[oDD.id] = oDD;
20703                             }
20704                         }
20705                     }
20706                 }
20707             }
20708
20709             if (this.mode) {
20710                 if (outEvts.length) {
20711                     dc.b4DragOut(e, outEvts);
20712                     dc.onDragOut(e, outEvts);
20713                 }
20714
20715                 if (enterEvts.length) {
20716                     dc.onDragEnter(e, enterEvts);
20717                 }
20718
20719                 if (overEvts.length) {
20720                     dc.b4DragOver(e, overEvts);
20721                     dc.onDragOver(e, overEvts);
20722                 }
20723
20724                 if (dropEvts.length) {
20725                     dc.b4DragDrop(e, dropEvts);
20726                     dc.onDragDrop(e, dropEvts);
20727                 }
20728
20729             } else {
20730                 // fire dragout events
20731                 var len = 0;
20732                 for (i=0, len=outEvts.length; i<len; ++i) {
20733                     dc.b4DragOut(e, outEvts[i].id);
20734                     dc.onDragOut(e, outEvts[i].id);
20735                 }
20736
20737                 // fire enter events
20738                 for (i=0,len=enterEvts.length; i<len; ++i) {
20739                     // dc.b4DragEnter(e, oDD.id);
20740                     dc.onDragEnter(e, enterEvts[i].id);
20741                 }
20742
20743                 // fire over events
20744                 for (i=0,len=overEvts.length; i<len; ++i) {
20745                     dc.b4DragOver(e, overEvts[i].id);
20746                     dc.onDragOver(e, overEvts[i].id);
20747                 }
20748
20749                 // fire drop events
20750                 for (i=0, len=dropEvts.length; i<len; ++i) {
20751                     dc.b4DragDrop(e, dropEvts[i].id);
20752                     dc.onDragDrop(e, dropEvts[i].id);
20753                 }
20754
20755             }
20756
20757             // notify about a drop that did not find a target
20758             if (isDrop && !dropEvts.length) {
20759                 dc.onInvalidDrop(e);
20760             }
20761
20762         },
20763
20764         /**
20765          * Helper function for getting the best match from the list of drag
20766          * and drop objects returned by the drag and drop events when we are
20767          * in INTERSECT mode.  It returns either the first object that the
20768          * cursor is over, or the object that has the greatest overlap with
20769          * the dragged element.
20770          * @method getBestMatch
20771          * @param  {DragDrop[]} dds The array of drag and drop objects
20772          * targeted
20773          * @return {DragDrop}       The best single match
20774          * @static
20775          */
20776         getBestMatch: function(dds) {
20777             var winner = null;
20778             // Return null if the input is not what we expect
20779             //if (!dds || !dds.length || dds.length == 0) {
20780                // winner = null;
20781             // If there is only one item, it wins
20782             //} else if (dds.length == 1) {
20783
20784             var len = dds.length;
20785
20786             if (len == 1) {
20787                 winner = dds[0];
20788             } else {
20789                 // Loop through the targeted items
20790                 for (var i=0; i<len; ++i) {
20791                     var dd = dds[i];
20792                     // If the cursor is over the object, it wins.  If the
20793                     // cursor is over multiple matches, the first one we come
20794                     // to wins.
20795                     if (dd.cursorIsOver) {
20796                         winner = dd;
20797                         break;
20798                     // Otherwise the object with the most overlap wins
20799                     } else {
20800                         if (!winner ||
20801                             winner.overlap.getArea() < dd.overlap.getArea()) {
20802                             winner = dd;
20803                         }
20804                     }
20805                 }
20806             }
20807
20808             return winner;
20809         },
20810
20811         /**
20812          * Refreshes the cache of the top-left and bottom-right points of the
20813          * drag and drop objects in the specified group(s).  This is in the
20814          * format that is stored in the drag and drop instance, so typical
20815          * usage is:
20816          * <code>
20817          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20818          * </code>
20819          * Alternatively:
20820          * <code>
20821          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20822          * </code>
20823          * @TODO this really should be an indexed array.  Alternatively this
20824          * method could accept both.
20825          * @method refreshCache
20826          * @param {Object} groups an associative array of groups to refresh
20827          * @static
20828          */
20829         refreshCache: function(groups) {
20830             for (var sGroup in groups) {
20831                 if ("string" != typeof sGroup) {
20832                     continue;
20833                 }
20834                 for (var i in this.ids[sGroup]) {
20835                     var oDD = this.ids[sGroup][i];
20836
20837                     if (this.isTypeOfDD(oDD)) {
20838                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20839                         var loc = this.getLocation(oDD);
20840                         if (loc) {
20841                             this.locationCache[oDD.id] = loc;
20842                         } else {
20843                             delete this.locationCache[oDD.id];
20844                             // this will unregister the drag and drop object if
20845                             // the element is not in a usable state
20846                             // oDD.unreg();
20847                         }
20848                     }
20849                 }
20850             }
20851         },
20852
20853         /**
20854          * This checks to make sure an element exists and is in the DOM.  The
20855          * main purpose is to handle cases where innerHTML is used to remove
20856          * drag and drop objects from the DOM.  IE provides an 'unspecified
20857          * error' when trying to access the offsetParent of such an element
20858          * @method verifyEl
20859          * @param {HTMLElement} el the element to check
20860          * @return {boolean} true if the element looks usable
20861          * @static
20862          */
20863         verifyEl: function(el) {
20864             if (el) {
20865                 var parent;
20866                 if(Roo.isIE){
20867                     try{
20868                         parent = el.offsetParent;
20869                     }catch(e){}
20870                 }else{
20871                     parent = el.offsetParent;
20872                 }
20873                 if (parent) {
20874                     return true;
20875                 }
20876             }
20877
20878             return false;
20879         },
20880
20881         /**
20882          * Returns a Region object containing the drag and drop element's position
20883          * and size, including the padding configured for it
20884          * @method getLocation
20885          * @param {DragDrop} oDD the drag and drop object to get the
20886          *                       location for
20887          * @return {Roo.lib.Region} a Region object representing the total area
20888          *                             the element occupies, including any padding
20889          *                             the instance is configured for.
20890          * @static
20891          */
20892         getLocation: function(oDD) {
20893             if (! this.isTypeOfDD(oDD)) {
20894                 return null;
20895             }
20896
20897             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20898
20899             try {
20900                 pos= Roo.lib.Dom.getXY(el);
20901             } catch (e) { }
20902
20903             if (!pos) {
20904                 return null;
20905             }
20906
20907             x1 = pos[0];
20908             x2 = x1 + el.offsetWidth;
20909             y1 = pos[1];
20910             y2 = y1 + el.offsetHeight;
20911
20912             t = y1 - oDD.padding[0];
20913             r = x2 + oDD.padding[1];
20914             b = y2 + oDD.padding[2];
20915             l = x1 - oDD.padding[3];
20916
20917             return new Roo.lib.Region( t, r, b, l );
20918         },
20919
20920         /**
20921          * Checks the cursor location to see if it over the target
20922          * @method isOverTarget
20923          * @param {Roo.lib.Point} pt The point to evaluate
20924          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20925          * @return {boolean} true if the mouse is over the target
20926          * @private
20927          * @static
20928          */
20929         isOverTarget: function(pt, oTarget, intersect) {
20930             // use cache if available
20931             var loc = this.locationCache[oTarget.id];
20932             if (!loc || !this.useCache) {
20933                 loc = this.getLocation(oTarget);
20934                 this.locationCache[oTarget.id] = loc;
20935
20936             }
20937
20938             if (!loc) {
20939                 return false;
20940             }
20941
20942             oTarget.cursorIsOver = loc.contains( pt );
20943
20944             // DragDrop is using this as a sanity check for the initial mousedown
20945             // in this case we are done.  In POINT mode, if the drag obj has no
20946             // contraints, we are also done. Otherwise we need to evaluate the
20947             // location of the target as related to the actual location of the
20948             // dragged element.
20949             var dc = this.dragCurrent;
20950             if (!dc || !dc.getTargetCoord ||
20951                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20952                 return oTarget.cursorIsOver;
20953             }
20954
20955             oTarget.overlap = null;
20956
20957             // Get the current location of the drag element, this is the
20958             // location of the mouse event less the delta that represents
20959             // where the original mousedown happened on the element.  We
20960             // need to consider constraints and ticks as well.
20961             var pos = dc.getTargetCoord(pt.x, pt.y);
20962
20963             var el = dc.getDragEl();
20964             var curRegion = new Roo.lib.Region( pos.y,
20965                                                    pos.x + el.offsetWidth,
20966                                                    pos.y + el.offsetHeight,
20967                                                    pos.x );
20968
20969             var overlap = curRegion.intersect(loc);
20970
20971             if (overlap) {
20972                 oTarget.overlap = overlap;
20973                 return (intersect) ? true : oTarget.cursorIsOver;
20974             } else {
20975                 return false;
20976             }
20977         },
20978
20979         /**
20980          * unload event handler
20981          * @method _onUnload
20982          * @private
20983          * @static
20984          */
20985         _onUnload: function(e, me) {
20986             Roo.dd.DragDropMgr.unregAll();
20987         },
20988
20989         /**
20990          * Cleans up the drag and drop events and objects.
20991          * @method unregAll
20992          * @private
20993          * @static
20994          */
20995         unregAll: function() {
20996
20997             if (this.dragCurrent) {
20998                 this.stopDrag();
20999                 this.dragCurrent = null;
21000             }
21001
21002             this._execOnAll("unreg", []);
21003
21004             for (i in this.elementCache) {
21005                 delete this.elementCache[i];
21006             }
21007
21008             this.elementCache = {};
21009             this.ids = {};
21010         },
21011
21012         /**
21013          * A cache of DOM elements
21014          * @property elementCache
21015          * @private
21016          * @static
21017          */
21018         elementCache: {},
21019
21020         /**
21021          * Get the wrapper for the DOM element specified
21022          * @method getElWrapper
21023          * @param {String} id the id of the element to get
21024          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21025          * @private
21026          * @deprecated This wrapper isn't that useful
21027          * @static
21028          */
21029         getElWrapper: function(id) {
21030             var oWrapper = this.elementCache[id];
21031             if (!oWrapper || !oWrapper.el) {
21032                 oWrapper = this.elementCache[id] =
21033                     new this.ElementWrapper(Roo.getDom(id));
21034             }
21035             return oWrapper;
21036         },
21037
21038         /**
21039          * Returns the actual DOM element
21040          * @method getElement
21041          * @param {String} id the id of the elment to get
21042          * @return {Object} The element
21043          * @deprecated use Roo.getDom instead
21044          * @static
21045          */
21046         getElement: function(id) {
21047             return Roo.getDom(id);
21048         },
21049
21050         /**
21051          * Returns the style property for the DOM element (i.e.,
21052          * document.getElById(id).style)
21053          * @method getCss
21054          * @param {String} id the id of the elment to get
21055          * @return {Object} The style property of the element
21056          * @deprecated use Roo.getDom instead
21057          * @static
21058          */
21059         getCss: function(id) {
21060             var el = Roo.getDom(id);
21061             return (el) ? el.style : null;
21062         },
21063
21064         /**
21065          * Inner class for cached elements
21066          * @class DragDropMgr.ElementWrapper
21067          * @for DragDropMgr
21068          * @private
21069          * @deprecated
21070          */
21071         ElementWrapper: function(el) {
21072                 /**
21073                  * The element
21074                  * @property el
21075                  */
21076                 this.el = el || null;
21077                 /**
21078                  * The element id
21079                  * @property id
21080                  */
21081                 this.id = this.el && el.id;
21082                 /**
21083                  * A reference to the style property
21084                  * @property css
21085                  */
21086                 this.css = this.el && el.style;
21087             },
21088
21089         /**
21090          * Returns the X position of an html element
21091          * @method getPosX
21092          * @param el the element for which to get the position
21093          * @return {int} the X coordinate
21094          * @for DragDropMgr
21095          * @deprecated use Roo.lib.Dom.getX instead
21096          * @static
21097          */
21098         getPosX: function(el) {
21099             return Roo.lib.Dom.getX(el);
21100         },
21101
21102         /**
21103          * Returns the Y position of an html element
21104          * @method getPosY
21105          * @param el the element for which to get the position
21106          * @return {int} the Y coordinate
21107          * @deprecated use Roo.lib.Dom.getY instead
21108          * @static
21109          */
21110         getPosY: function(el) {
21111             return Roo.lib.Dom.getY(el);
21112         },
21113
21114         /**
21115          * Swap two nodes.  In IE, we use the native method, for others we
21116          * emulate the IE behavior
21117          * @method swapNode
21118          * @param n1 the first node to swap
21119          * @param n2 the other node to swap
21120          * @static
21121          */
21122         swapNode: function(n1, n2) {
21123             if (n1.swapNode) {
21124                 n1.swapNode(n2);
21125             } else {
21126                 var p = n2.parentNode;
21127                 var s = n2.nextSibling;
21128
21129                 if (s == n1) {
21130                     p.insertBefore(n1, n2);
21131                 } else if (n2 == n1.nextSibling) {
21132                     p.insertBefore(n2, n1);
21133                 } else {
21134                     n1.parentNode.replaceChild(n2, n1);
21135                     p.insertBefore(n1, s);
21136                 }
21137             }
21138         },
21139
21140         /**
21141          * Returns the current scroll position
21142          * @method getScroll
21143          * @private
21144          * @static
21145          */
21146         getScroll: function () {
21147             var t, l, dde=document.documentElement, db=document.body;
21148             if (dde && (dde.scrollTop || dde.scrollLeft)) {
21149                 t = dde.scrollTop;
21150                 l = dde.scrollLeft;
21151             } else if (db) {
21152                 t = db.scrollTop;
21153                 l = db.scrollLeft;
21154             } else {
21155
21156             }
21157             return { top: t, left: l };
21158         },
21159
21160         /**
21161          * Returns the specified element style property
21162          * @method getStyle
21163          * @param {HTMLElement} el          the element
21164          * @param {string}      styleProp   the style property
21165          * @return {string} The value of the style property
21166          * @deprecated use Roo.lib.Dom.getStyle
21167          * @static
21168          */
21169         getStyle: function(el, styleProp) {
21170             return Roo.fly(el).getStyle(styleProp);
21171         },
21172
21173         /**
21174          * Gets the scrollTop
21175          * @method getScrollTop
21176          * @return {int} the document's scrollTop
21177          * @static
21178          */
21179         getScrollTop: function () { return this.getScroll().top; },
21180
21181         /**
21182          * Gets the scrollLeft
21183          * @method getScrollLeft
21184          * @return {int} the document's scrollTop
21185          * @static
21186          */
21187         getScrollLeft: function () { return this.getScroll().left; },
21188
21189         /**
21190          * Sets the x/y position of an element to the location of the
21191          * target element.
21192          * @method moveToEl
21193          * @param {HTMLElement} moveEl      The element to move
21194          * @param {HTMLElement} targetEl    The position reference element
21195          * @static
21196          */
21197         moveToEl: function (moveEl, targetEl) {
21198             var aCoord = Roo.lib.Dom.getXY(targetEl);
21199             Roo.lib.Dom.setXY(moveEl, aCoord);
21200         },
21201
21202         /**
21203          * Numeric array sort function
21204          * @method numericSort
21205          * @static
21206          */
21207         numericSort: function(a, b) { return (a - b); },
21208
21209         /**
21210          * Internal counter
21211          * @property _timeoutCount
21212          * @private
21213          * @static
21214          */
21215         _timeoutCount: 0,
21216
21217         /**
21218          * Trying to make the load order less important.  Without this we get
21219          * an error if this file is loaded before the Event Utility.
21220          * @method _addListeners
21221          * @private
21222          * @static
21223          */
21224         _addListeners: function() {
21225             var DDM = Roo.dd.DDM;
21226             if ( Roo.lib.Event && document ) {
21227                 DDM._onLoad();
21228             } else {
21229                 if (DDM._timeoutCount > 2000) {
21230                 } else {
21231                     setTimeout(DDM._addListeners, 10);
21232                     if (document && document.body) {
21233                         DDM._timeoutCount += 1;
21234                     }
21235                 }
21236             }
21237         },
21238
21239         /**
21240          * Recursively searches the immediate parent and all child nodes for
21241          * the handle element in order to determine wheter or not it was
21242          * clicked.
21243          * @method handleWasClicked
21244          * @param node the html element to inspect
21245          * @static
21246          */
21247         handleWasClicked: function(node, id) {
21248             if (this.isHandle(id, node.id)) {
21249                 return true;
21250             } else {
21251                 // check to see if this is a text node child of the one we want
21252                 var p = node.parentNode;
21253
21254                 while (p) {
21255                     if (this.isHandle(id, p.id)) {
21256                         return true;
21257                     } else {
21258                         p = p.parentNode;
21259                     }
21260                 }
21261             }
21262
21263             return false;
21264         }
21265
21266     };
21267
21268 }();
21269
21270 // shorter alias, save a few bytes
21271 Roo.dd.DDM = Roo.dd.DragDropMgr;
21272 Roo.dd.DDM._addListeners();
21273
21274 }/*
21275  * Based on:
21276  * Ext JS Library 1.1.1
21277  * Copyright(c) 2006-2007, Ext JS, LLC.
21278  *
21279  * Originally Released Under LGPL - original licence link has changed is not relivant.
21280  *
21281  * Fork - LGPL
21282  * <script type="text/javascript">
21283  */
21284
21285 /**
21286  * @class Roo.dd.DD
21287  * A DragDrop implementation where the linked element follows the
21288  * mouse cursor during a drag.
21289  * @extends Roo.dd.DragDrop
21290  * @constructor
21291  * @param {String} id the id of the linked element
21292  * @param {String} sGroup the group of related DragDrop items
21293  * @param {object} config an object containing configurable attributes
21294  *                Valid properties for DD:
21295  *                    scroll
21296  */
21297 Roo.dd.DD = function(id, sGroup, config) {
21298     if (id) {
21299         this.init(id, sGroup, config);
21300     }
21301 };
21302
21303 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21304
21305     /**
21306      * When set to true, the utility automatically tries to scroll the browser
21307      * window wehn a drag and drop element is dragged near the viewport boundary.
21308      * Defaults to true.
21309      * @property scroll
21310      * @type boolean
21311      */
21312     scroll: true,
21313
21314     /**
21315      * Sets the pointer offset to the distance between the linked element's top
21316      * left corner and the location the element was clicked
21317      * @method autoOffset
21318      * @param {int} iPageX the X coordinate of the click
21319      * @param {int} iPageY the Y coordinate of the click
21320      */
21321     autoOffset: function(iPageX, iPageY) {
21322         var x = iPageX - this.startPageX;
21323         var y = iPageY - this.startPageY;
21324         this.setDelta(x, y);
21325     },
21326
21327     /**
21328      * Sets the pointer offset.  You can call this directly to force the
21329      * offset to be in a particular location (e.g., pass in 0,0 to set it
21330      * to the center of the object)
21331      * @method setDelta
21332      * @param {int} iDeltaX the distance from the left
21333      * @param {int} iDeltaY the distance from the top
21334      */
21335     setDelta: function(iDeltaX, iDeltaY) {
21336         this.deltaX = iDeltaX;
21337         this.deltaY = iDeltaY;
21338     },
21339
21340     /**
21341      * Sets the drag element to the location of the mousedown or click event,
21342      * maintaining the cursor location relative to the location on the element
21343      * that was clicked.  Override this if you want to place the element in a
21344      * location other than where the cursor is.
21345      * @method setDragElPos
21346      * @param {int} iPageX the X coordinate of the mousedown or drag event
21347      * @param {int} iPageY the Y coordinate of the mousedown or drag event
21348      */
21349     setDragElPos: function(iPageX, iPageY) {
21350         // the first time we do this, we are going to check to make sure
21351         // the element has css positioning
21352
21353         var el = this.getDragEl();
21354         this.alignElWithMouse(el, iPageX, iPageY);
21355     },
21356
21357     /**
21358      * Sets the element to the location of the mousedown or click event,
21359      * maintaining the cursor location relative to the location on the element
21360      * that was clicked.  Override this if you want to place the element in a
21361      * location other than where the cursor is.
21362      * @method alignElWithMouse
21363      * @param {HTMLElement} el the element to move
21364      * @param {int} iPageX the X coordinate of the mousedown or drag event
21365      * @param {int} iPageY the Y coordinate of the mousedown or drag event
21366      */
21367     alignElWithMouse: function(el, iPageX, iPageY) {
21368         var oCoord = this.getTargetCoord(iPageX, iPageY);
21369         var fly = el.dom ? el : Roo.fly(el);
21370         if (!this.deltaSetXY) {
21371             var aCoord = [oCoord.x, oCoord.y];
21372             fly.setXY(aCoord);
21373             var newLeft = fly.getLeft(true);
21374             var newTop  = fly.getTop(true);
21375             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21376         } else {
21377             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21378         }
21379
21380         this.cachePosition(oCoord.x, oCoord.y);
21381         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21382         return oCoord;
21383     },
21384
21385     /**
21386      * Saves the most recent position so that we can reset the constraints and
21387      * tick marks on-demand.  We need to know this so that we can calculate the
21388      * number of pixels the element is offset from its original position.
21389      * @method cachePosition
21390      * @param iPageX the current x position (optional, this just makes it so we
21391      * don't have to look it up again)
21392      * @param iPageY the current y position (optional, this just makes it so we
21393      * don't have to look it up again)
21394      */
21395     cachePosition: function(iPageX, iPageY) {
21396         if (iPageX) {
21397             this.lastPageX = iPageX;
21398             this.lastPageY = iPageY;
21399         } else {
21400             var aCoord = Roo.lib.Dom.getXY(this.getEl());
21401             this.lastPageX = aCoord[0];
21402             this.lastPageY = aCoord[1];
21403         }
21404     },
21405
21406     /**
21407      * Auto-scroll the window if the dragged object has been moved beyond the
21408      * visible window boundary.
21409      * @method autoScroll
21410      * @param {int} x the drag element's x position
21411      * @param {int} y the drag element's y position
21412      * @param {int} h the height of the drag element
21413      * @param {int} w the width of the drag element
21414      * @private
21415      */
21416     autoScroll: function(x, y, h, w) {
21417
21418         if (this.scroll) {
21419             // The client height
21420             var clientH = Roo.lib.Dom.getViewWidth();
21421
21422             // The client width
21423             var clientW = Roo.lib.Dom.getViewHeight();
21424
21425             // The amt scrolled down
21426             var st = this.DDM.getScrollTop();
21427
21428             // The amt scrolled right
21429             var sl = this.DDM.getScrollLeft();
21430
21431             // Location of the bottom of the element
21432             var bot = h + y;
21433
21434             // Location of the right of the element
21435             var right = w + x;
21436
21437             // The distance from the cursor to the bottom of the visible area,
21438             // adjusted so that we don't scroll if the cursor is beyond the
21439             // element drag constraints
21440             var toBot = (clientH + st - y - this.deltaY);
21441
21442             // The distance from the cursor to the right of the visible area
21443             var toRight = (clientW + sl - x - this.deltaX);
21444
21445
21446             // How close to the edge the cursor must be before we scroll
21447             // var thresh = (document.all) ? 100 : 40;
21448             var thresh = 40;
21449
21450             // How many pixels to scroll per autoscroll op.  This helps to reduce
21451             // clunky scrolling. IE is more sensitive about this ... it needs this
21452             // value to be higher.
21453             var scrAmt = (document.all) ? 80 : 30;
21454
21455             // Scroll down if we are near the bottom of the visible page and the
21456             // obj extends below the crease
21457             if ( bot > clientH && toBot < thresh ) {
21458                 window.scrollTo(sl, st + scrAmt);
21459             }
21460
21461             // Scroll up if the window is scrolled down and the top of the object
21462             // goes above the top border
21463             if ( y < st && st > 0 && y - st < thresh ) {
21464                 window.scrollTo(sl, st - scrAmt);
21465             }
21466
21467             // Scroll right if the obj is beyond the right border and the cursor is
21468             // near the border.
21469             if ( right > clientW && toRight < thresh ) {
21470                 window.scrollTo(sl + scrAmt, st);
21471             }
21472
21473             // Scroll left if the window has been scrolled to the right and the obj
21474             // extends past the left border
21475             if ( x < sl && sl > 0 && x - sl < thresh ) {
21476                 window.scrollTo(sl - scrAmt, st);
21477             }
21478         }
21479     },
21480
21481     /**
21482      * Finds the location the element should be placed if we want to move
21483      * it to where the mouse location less the click offset would place us.
21484      * @method getTargetCoord
21485      * @param {int} iPageX the X coordinate of the click
21486      * @param {int} iPageY the Y coordinate of the click
21487      * @return an object that contains the coordinates (Object.x and Object.y)
21488      * @private
21489      */
21490     getTargetCoord: function(iPageX, iPageY) {
21491
21492
21493         var x = iPageX - this.deltaX;
21494         var y = iPageY - this.deltaY;
21495
21496         if (this.constrainX) {
21497             if (x < this.minX) { x = this.minX; }
21498             if (x > this.maxX) { x = this.maxX; }
21499         }
21500
21501         if (this.constrainY) {
21502             if (y < this.minY) { y = this.minY; }
21503             if (y > this.maxY) { y = this.maxY; }
21504         }
21505
21506         x = this.getTick(x, this.xTicks);
21507         y = this.getTick(y, this.yTicks);
21508
21509
21510         return {x:x, y:y};
21511     },
21512
21513     /*
21514      * Sets up config options specific to this class. Overrides
21515      * Roo.dd.DragDrop, but all versions of this method through the
21516      * inheritance chain are called
21517      */
21518     applyConfig: function() {
21519         Roo.dd.DD.superclass.applyConfig.call(this);
21520         this.scroll = (this.config.scroll !== false);
21521     },
21522
21523     /*
21524      * Event that fires prior to the onMouseDown event.  Overrides
21525      * Roo.dd.DragDrop.
21526      */
21527     b4MouseDown: function(e) {
21528         // this.resetConstraints();
21529         this.autoOffset(e.getPageX(),
21530                             e.getPageY());
21531     },
21532
21533     /*
21534      * Event that fires prior to the onDrag event.  Overrides
21535      * Roo.dd.DragDrop.
21536      */
21537     b4Drag: function(e) {
21538         this.setDragElPos(e.getPageX(),
21539                             e.getPageY());
21540     },
21541
21542     toString: function() {
21543         return ("DD " + this.id);
21544     }
21545
21546     //////////////////////////////////////////////////////////////////////////
21547     // Debugging ygDragDrop events that can be overridden
21548     //////////////////////////////////////////////////////////////////////////
21549     /*
21550     startDrag: function(x, y) {
21551     },
21552
21553     onDrag: function(e) {
21554     },
21555
21556     onDragEnter: function(e, id) {
21557     },
21558
21559     onDragOver: function(e, id) {
21560     },
21561
21562     onDragOut: function(e, id) {
21563     },
21564
21565     onDragDrop: function(e, id) {
21566     },
21567
21568     endDrag: function(e) {
21569     }
21570
21571     */
21572
21573 });/*
21574  * Based on:
21575  * Ext JS Library 1.1.1
21576  * Copyright(c) 2006-2007, Ext JS, LLC.
21577  *
21578  * Originally Released Under LGPL - original licence link has changed is not relivant.
21579  *
21580  * Fork - LGPL
21581  * <script type="text/javascript">
21582  */
21583
21584 /**
21585  * @class Roo.dd.DDProxy
21586  * A DragDrop implementation that inserts an empty, bordered div into
21587  * the document that follows the cursor during drag operations.  At the time of
21588  * the click, the frame div is resized to the dimensions of the linked html
21589  * element, and moved to the exact location of the linked element.
21590  *
21591  * References to the "frame" element refer to the single proxy element that
21592  * was created to be dragged in place of all DDProxy elements on the
21593  * page.
21594  *
21595  * @extends Roo.dd.DD
21596  * @constructor
21597  * @param {String} id the id of the linked html element
21598  * @param {String} sGroup the group of related DragDrop objects
21599  * @param {object} config an object containing configurable attributes
21600  *                Valid properties for DDProxy in addition to those in DragDrop:
21601  *                   resizeFrame, centerFrame, dragElId
21602  */
21603 Roo.dd.DDProxy = function(id, sGroup, config) {
21604     if (id) {
21605         this.init(id, sGroup, config);
21606         this.initFrame();
21607     }
21608 };
21609
21610 /**
21611  * The default drag frame div id
21612  * @property Roo.dd.DDProxy.dragElId
21613  * @type String
21614  * @static
21615  */
21616 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21617
21618 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21619
21620     /**
21621      * By default we resize the drag frame to be the same size as the element
21622      * we want to drag (this is to get the frame effect).  We can turn it off
21623      * if we want a different behavior.
21624      * @property resizeFrame
21625      * @type boolean
21626      */
21627     resizeFrame: true,
21628
21629     /**
21630      * By default the frame is positioned exactly where the drag element is, so
21631      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
21632      * you do not have constraints on the obj is to have the drag frame centered
21633      * around the cursor.  Set centerFrame to true for this effect.
21634      * @property centerFrame
21635      * @type boolean
21636      */
21637     centerFrame: false,
21638
21639     /**
21640      * Creates the proxy element if it does not yet exist
21641      * @method createFrame
21642      */
21643     createFrame: function() {
21644         var self = this;
21645         var body = document.body;
21646
21647         if (!body || !body.firstChild) {
21648             setTimeout( function() { self.createFrame(); }, 50 );
21649             return;
21650         }
21651
21652         var div = this.getDragEl();
21653
21654         if (!div) {
21655             div    = document.createElement("div");
21656             div.id = this.dragElId;
21657             var s  = div.style;
21658
21659             s.position   = "absolute";
21660             s.visibility = "hidden";
21661             s.cursor     = "move";
21662             s.border     = "2px solid #aaa";
21663             s.zIndex     = 999;
21664
21665             // appendChild can blow up IE if invoked prior to the window load event
21666             // while rendering a table.  It is possible there are other scenarios
21667             // that would cause this to happen as well.
21668             body.insertBefore(div, body.firstChild);
21669         }
21670     },
21671
21672     /**
21673      * Initialization for the drag frame element.  Must be called in the
21674      * constructor of all subclasses
21675      * @method initFrame
21676      */
21677     initFrame: function() {
21678         this.createFrame();
21679     },
21680
21681     applyConfig: function() {
21682         Roo.dd.DDProxy.superclass.applyConfig.call(this);
21683
21684         this.resizeFrame = (this.config.resizeFrame !== false);
21685         this.centerFrame = (this.config.centerFrame);
21686         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21687     },
21688
21689     /**
21690      * Resizes the drag frame to the dimensions of the clicked object, positions
21691      * it over the object, and finally displays it
21692      * @method showFrame
21693      * @param {int} iPageX X click position
21694      * @param {int} iPageY Y click position
21695      * @private
21696      */
21697     showFrame: function(iPageX, iPageY) {
21698         var el = this.getEl();
21699         var dragEl = this.getDragEl();
21700         var s = dragEl.style;
21701
21702         this._resizeProxy();
21703
21704         if (this.centerFrame) {
21705             this.setDelta( Math.round(parseInt(s.width,  10)/2),
21706                            Math.round(parseInt(s.height, 10)/2) );
21707         }
21708
21709         this.setDragElPos(iPageX, iPageY);
21710
21711         Roo.fly(dragEl).show();
21712     },
21713
21714     /**
21715      * The proxy is automatically resized to the dimensions of the linked
21716      * element when a drag is initiated, unless resizeFrame is set to false
21717      * @method _resizeProxy
21718      * @private
21719      */
21720     _resizeProxy: function() {
21721         if (this.resizeFrame) {
21722             var el = this.getEl();
21723             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21724         }
21725     },
21726
21727     // overrides Roo.dd.DragDrop
21728     b4MouseDown: function(e) {
21729         var x = e.getPageX();
21730         var y = e.getPageY();
21731         this.autoOffset(x, y);
21732         this.setDragElPos(x, y);
21733     },
21734
21735     // overrides Roo.dd.DragDrop
21736     b4StartDrag: function(x, y) {
21737         // show the drag frame
21738         this.showFrame(x, y);
21739     },
21740
21741     // overrides Roo.dd.DragDrop
21742     b4EndDrag: function(e) {
21743         Roo.fly(this.getDragEl()).hide();
21744     },
21745
21746     // overrides Roo.dd.DragDrop
21747     // By default we try to move the element to the last location of the frame.
21748     // This is so that the default behavior mirrors that of Roo.dd.DD.
21749     endDrag: function(e) {
21750
21751         var lel = this.getEl();
21752         var del = this.getDragEl();
21753
21754         // Show the drag frame briefly so we can get its position
21755         del.style.visibility = "";
21756
21757         this.beforeMove();
21758         // Hide the linked element before the move to get around a Safari
21759         // rendering bug.
21760         lel.style.visibility = "hidden";
21761         Roo.dd.DDM.moveToEl(lel, del);
21762         del.style.visibility = "hidden";
21763         lel.style.visibility = "";
21764
21765         this.afterDrag();
21766     },
21767
21768     beforeMove : function(){
21769
21770     },
21771
21772     afterDrag : function(){
21773
21774     },
21775
21776     toString: function() {
21777         return ("DDProxy " + this.id);
21778     }
21779
21780 });
21781 /*
21782  * Based on:
21783  * Ext JS Library 1.1.1
21784  * Copyright(c) 2006-2007, Ext JS, LLC.
21785  *
21786  * Originally Released Under LGPL - original licence link has changed is not relivant.
21787  *
21788  * Fork - LGPL
21789  * <script type="text/javascript">
21790  */
21791
21792  /**
21793  * @class Roo.dd.DDTarget
21794  * A DragDrop implementation that does not move, but can be a drop
21795  * target.  You would get the same result by simply omitting implementation
21796  * for the event callbacks, but this way we reduce the processing cost of the
21797  * event listener and the callbacks.
21798  * @extends Roo.dd.DragDrop
21799  * @constructor
21800  * @param {String} id the id of the element that is a drop target
21801  * @param {String} sGroup the group of related DragDrop objects
21802  * @param {object} config an object containing configurable attributes
21803  *                 Valid properties for DDTarget in addition to those in
21804  *                 DragDrop:
21805  *                    none
21806  */
21807 Roo.dd.DDTarget = function(id, sGroup, config) {
21808     if (id) {
21809         this.initTarget(id, sGroup, config);
21810     }
21811     if (config && (config.listeners || config.events)) { 
21812         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
21813             listeners : config.listeners || {}, 
21814             events : config.events || {} 
21815         });    
21816     }
21817 };
21818
21819 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21820 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21821     toString: function() {
21822         return ("DDTarget " + this.id);
21823     }
21824 });
21825 /*
21826  * Based on:
21827  * Ext JS Library 1.1.1
21828  * Copyright(c) 2006-2007, Ext JS, LLC.
21829  *
21830  * Originally Released Under LGPL - original licence link has changed is not relivant.
21831  *
21832  * Fork - LGPL
21833  * <script type="text/javascript">
21834  */
21835  
21836
21837 /**
21838  * @class Roo.dd.ScrollManager
21839  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21840  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21841  * @singleton
21842  */
21843 Roo.dd.ScrollManager = function(){
21844     var ddm = Roo.dd.DragDropMgr;
21845     var els = {};
21846     var dragEl = null;
21847     var proc = {};
21848     
21849     
21850     
21851     var onStop = function(e){
21852         dragEl = null;
21853         clearProc();
21854     };
21855     
21856     var triggerRefresh = function(){
21857         if(ddm.dragCurrent){
21858              ddm.refreshCache(ddm.dragCurrent.groups);
21859         }
21860     };
21861     
21862     var doScroll = function(){
21863         if(ddm.dragCurrent){
21864             var dds = Roo.dd.ScrollManager;
21865             if(!dds.animate){
21866                 if(proc.el.scroll(proc.dir, dds.increment)){
21867                     triggerRefresh();
21868                 }
21869             }else{
21870                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21871             }
21872         }
21873     };
21874     
21875     var clearProc = function(){
21876         if(proc.id){
21877             clearInterval(proc.id);
21878         }
21879         proc.id = 0;
21880         proc.el = null;
21881         proc.dir = "";
21882     };
21883     
21884     var startProc = function(el, dir){
21885          Roo.log('scroll startproc');
21886         clearProc();
21887         proc.el = el;
21888         proc.dir = dir;
21889         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21890     };
21891     
21892     var onFire = function(e, isDrop){
21893        
21894         if(isDrop || !ddm.dragCurrent){ return; }
21895         var dds = Roo.dd.ScrollManager;
21896         if(!dragEl || dragEl != ddm.dragCurrent){
21897             dragEl = ddm.dragCurrent;
21898             // refresh regions on drag start
21899             dds.refreshCache();
21900         }
21901         
21902         var xy = Roo.lib.Event.getXY(e);
21903         var pt = new Roo.lib.Point(xy[0], xy[1]);
21904         for(var id in els){
21905             var el = els[id], r = el._region;
21906             if(r && r.contains(pt) && el.isScrollable()){
21907                 if(r.bottom - pt.y <= dds.thresh){
21908                     if(proc.el != el){
21909                         startProc(el, "down");
21910                     }
21911                     return;
21912                 }else if(r.right - pt.x <= dds.thresh){
21913                     if(proc.el != el){
21914                         startProc(el, "left");
21915                     }
21916                     return;
21917                 }else if(pt.y - r.top <= dds.thresh){
21918                     if(proc.el != el){
21919                         startProc(el, "up");
21920                     }
21921                     return;
21922                 }else if(pt.x - r.left <= dds.thresh){
21923                     if(proc.el != el){
21924                         startProc(el, "right");
21925                     }
21926                     return;
21927                 }
21928             }
21929         }
21930         clearProc();
21931     };
21932     
21933     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21934     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21935     
21936     return {
21937         /**
21938          * Registers new overflow element(s) to auto scroll
21939          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21940          */
21941         register : function(el){
21942             if(el instanceof Array){
21943                 for(var i = 0, len = el.length; i < len; i++) {
21944                         this.register(el[i]);
21945                 }
21946             }else{
21947                 el = Roo.get(el);
21948                 els[el.id] = el;
21949             }
21950             Roo.dd.ScrollManager.els = els;
21951         },
21952         
21953         /**
21954          * Unregisters overflow element(s) so they are no longer scrolled
21955          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21956          */
21957         unregister : function(el){
21958             if(el instanceof Array){
21959                 for(var i = 0, len = el.length; i < len; i++) {
21960                         this.unregister(el[i]);
21961                 }
21962             }else{
21963                 el = Roo.get(el);
21964                 delete els[el.id];
21965             }
21966         },
21967         
21968         /**
21969          * The number of pixels from the edge of a container the pointer needs to be to 
21970          * trigger scrolling (defaults to 25)
21971          * @type Number
21972          */
21973         thresh : 25,
21974         
21975         /**
21976          * The number of pixels to scroll in each scroll increment (defaults to 50)
21977          * @type Number
21978          */
21979         increment : 100,
21980         
21981         /**
21982          * The frequency of scrolls in milliseconds (defaults to 500)
21983          * @type Number
21984          */
21985         frequency : 500,
21986         
21987         /**
21988          * True to animate the scroll (defaults to true)
21989          * @type Boolean
21990          */
21991         animate: true,
21992         
21993         /**
21994          * The animation duration in seconds - 
21995          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21996          * @type Number
21997          */
21998         animDuration: .4,
21999         
22000         /**
22001          * Manually trigger a cache refresh.
22002          */
22003         refreshCache : function(){
22004             for(var id in els){
22005                 if(typeof els[id] == 'object'){ // for people extending the object prototype
22006                     els[id]._region = els[id].getRegion();
22007                 }
22008             }
22009         }
22010     };
22011 }();/*
22012  * Based on:
22013  * Ext JS Library 1.1.1
22014  * Copyright(c) 2006-2007, Ext JS, LLC.
22015  *
22016  * Originally Released Under LGPL - original licence link has changed is not relivant.
22017  *
22018  * Fork - LGPL
22019  * <script type="text/javascript">
22020  */
22021  
22022
22023 /**
22024  * @class Roo.dd.Registry
22025  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
22026  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22027  * @singleton
22028  */
22029 Roo.dd.Registry = function(){
22030     var elements = {}; 
22031     var handles = {}; 
22032     var autoIdSeed = 0;
22033
22034     var getId = function(el, autogen){
22035         if(typeof el == "string"){
22036             return el;
22037         }
22038         var id = el.id;
22039         if(!id && autogen !== false){
22040             id = "roodd-" + (++autoIdSeed);
22041             el.id = id;
22042         }
22043         return id;
22044     };
22045     
22046     return {
22047     /**
22048      * Register a drag drop element
22049      * @param {String|HTMLElement} element The id or DOM node to register
22050      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22051      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
22052      * knows how to interpret, plus there are some specific properties known to the Registry that should be
22053      * populated in the data object (if applicable):
22054      * <pre>
22055 Value      Description<br />
22056 ---------  ------------------------------------------<br />
22057 handles    Array of DOM nodes that trigger dragging<br />
22058            for the element being registered<br />
22059 isHandle   True if the element passed in triggers<br />
22060            dragging itself, else false
22061 </pre>
22062      */
22063         register : function(el, data){
22064             data = data || {};
22065             if(typeof el == "string"){
22066                 el = document.getElementById(el);
22067             }
22068             data.ddel = el;
22069             elements[getId(el)] = data;
22070             if(data.isHandle !== false){
22071                 handles[data.ddel.id] = data;
22072             }
22073             if(data.handles){
22074                 var hs = data.handles;
22075                 for(var i = 0, len = hs.length; i < len; i++){
22076                         handles[getId(hs[i])] = data;
22077                 }
22078             }
22079         },
22080
22081     /**
22082      * Unregister a drag drop element
22083      * @param {String|HTMLElement}  element The id or DOM node to unregister
22084      */
22085         unregister : function(el){
22086             var id = getId(el, false);
22087             var data = elements[id];
22088             if(data){
22089                 delete elements[id];
22090                 if(data.handles){
22091                     var hs = data.handles;
22092                     for(var i = 0, len = hs.length; i < len; i++){
22093                         delete handles[getId(hs[i], false)];
22094                     }
22095                 }
22096             }
22097         },
22098
22099     /**
22100      * Returns the handle registered for a DOM Node by id
22101      * @param {String|HTMLElement} id The DOM node or id to look up
22102      * @return {Object} handle The custom handle data
22103      */
22104         getHandle : function(id){
22105             if(typeof id != "string"){ // must be element?
22106                 id = id.id;
22107             }
22108             return handles[id];
22109         },
22110
22111     /**
22112      * Returns the handle that is registered for the DOM node that is the target of the event
22113      * @param {Event} e The event
22114      * @return {Object} handle The custom handle data
22115      */
22116         getHandleFromEvent : function(e){
22117             var t = Roo.lib.Event.getTarget(e);
22118             return t ? handles[t.id] : null;
22119         },
22120
22121     /**
22122      * Returns a custom data object that is registered for a DOM node by id
22123      * @param {String|HTMLElement} id The DOM node or id to look up
22124      * @return {Object} data The custom data
22125      */
22126         getTarget : function(id){
22127             if(typeof id != "string"){ // must be element?
22128                 id = id.id;
22129             }
22130             return elements[id];
22131         },
22132
22133     /**
22134      * Returns a custom data object that is registered for the DOM node that is the target of the event
22135      * @param {Event} e The event
22136      * @return {Object} data The custom data
22137      */
22138         getTargetFromEvent : function(e){
22139             var t = Roo.lib.Event.getTarget(e);
22140             return t ? elements[t.id] || handles[t.id] : null;
22141         }
22142     };
22143 }();/*
22144  * Based on:
22145  * Ext JS Library 1.1.1
22146  * Copyright(c) 2006-2007, Ext JS, LLC.
22147  *
22148  * Originally Released Under LGPL - original licence link has changed is not relivant.
22149  *
22150  * Fork - LGPL
22151  * <script type="text/javascript">
22152  */
22153  
22154
22155 /**
22156  * @class Roo.dd.StatusProxy
22157  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
22158  * default drag proxy used by all Roo.dd components.
22159  * @constructor
22160  * @param {Object} config
22161  */
22162 Roo.dd.StatusProxy = function(config){
22163     Roo.apply(this, config);
22164     this.id = this.id || Roo.id();
22165     this.el = new Roo.Layer({
22166         dh: {
22167             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22168                 {tag: "div", cls: "x-dd-drop-icon"},
22169                 {tag: "div", cls: "x-dd-drag-ghost"}
22170             ]
22171         }, 
22172         shadow: !config || config.shadow !== false
22173     });
22174     this.ghost = Roo.get(this.el.dom.childNodes[1]);
22175     this.dropStatus = this.dropNotAllowed;
22176 };
22177
22178 Roo.dd.StatusProxy.prototype = {
22179     /**
22180      * @cfg {String} dropAllowed
22181      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22182      */
22183     dropAllowed : "x-dd-drop-ok",
22184     /**
22185      * @cfg {String} dropNotAllowed
22186      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22187      */
22188     dropNotAllowed : "x-dd-drop-nodrop",
22189
22190     /**
22191      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22192      * over the current target element.
22193      * @param {String} cssClass The css class for the new drop status indicator image
22194      */
22195     setStatus : function(cssClass){
22196         cssClass = cssClass || this.dropNotAllowed;
22197         if(this.dropStatus != cssClass){
22198             this.el.replaceClass(this.dropStatus, cssClass);
22199             this.dropStatus = cssClass;
22200         }
22201     },
22202
22203     /**
22204      * Resets the status indicator to the default dropNotAllowed value
22205      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22206      */
22207     reset : function(clearGhost){
22208         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22209         this.dropStatus = this.dropNotAllowed;
22210         if(clearGhost){
22211             this.ghost.update("");
22212         }
22213     },
22214
22215     /**
22216      * Updates the contents of the ghost element
22217      * @param {String} html The html that will replace the current innerHTML of the ghost element
22218      */
22219     update : function(html){
22220         if(typeof html == "string"){
22221             this.ghost.update(html);
22222         }else{
22223             this.ghost.update("");
22224             html.style.margin = "0";
22225             this.ghost.dom.appendChild(html);
22226         }
22227         // ensure float = none set?? cant remember why though.
22228         var el = this.ghost.dom.firstChild;
22229                 if(el){
22230                         Roo.fly(el).setStyle('float', 'none');
22231                 }
22232     },
22233     
22234     /**
22235      * Returns the underlying proxy {@link Roo.Layer}
22236      * @return {Roo.Layer} el
22237     */
22238     getEl : function(){
22239         return this.el;
22240     },
22241
22242     /**
22243      * Returns the ghost element
22244      * @return {Roo.Element} el
22245      */
22246     getGhost : function(){
22247         return this.ghost;
22248     },
22249
22250     /**
22251      * Hides the proxy
22252      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22253      */
22254     hide : function(clear){
22255         this.el.hide();
22256         if(clear){
22257             this.reset(true);
22258         }
22259     },
22260
22261     /**
22262      * Stops the repair animation if it's currently running
22263      */
22264     stop : function(){
22265         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22266             this.anim.stop();
22267         }
22268     },
22269
22270     /**
22271      * Displays this proxy
22272      */
22273     show : function(){
22274         this.el.show();
22275     },
22276
22277     /**
22278      * Force the Layer to sync its shadow and shim positions to the element
22279      */
22280     sync : function(){
22281         this.el.sync();
22282     },
22283
22284     /**
22285      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
22286      * invalid drop operation by the item being dragged.
22287      * @param {Array} xy The XY position of the element ([x, y])
22288      * @param {Function} callback The function to call after the repair is complete
22289      * @param {Object} scope The scope in which to execute the callback
22290      */
22291     repair : function(xy, callback, scope){
22292         this.callback = callback;
22293         this.scope = scope;
22294         if(xy && this.animRepair !== false){
22295             this.el.addClass("x-dd-drag-repair");
22296             this.el.hideUnders(true);
22297             this.anim = this.el.shift({
22298                 duration: this.repairDuration || .5,
22299                 easing: 'easeOut',
22300                 xy: xy,
22301                 stopFx: true,
22302                 callback: this.afterRepair,
22303                 scope: this
22304             });
22305         }else{
22306             this.afterRepair();
22307         }
22308     },
22309
22310     // private
22311     afterRepair : function(){
22312         this.hide(true);
22313         if(typeof this.callback == "function"){
22314             this.callback.call(this.scope || this);
22315         }
22316         this.callback = null;
22317         this.scope = null;
22318     }
22319 };/*
22320  * Based on:
22321  * Ext JS Library 1.1.1
22322  * Copyright(c) 2006-2007, Ext JS, LLC.
22323  *
22324  * Originally Released Under LGPL - original licence link has changed is not relivant.
22325  *
22326  * Fork - LGPL
22327  * <script type="text/javascript">
22328  */
22329
22330 /**
22331  * @class Roo.dd.DragSource
22332  * @extends Roo.dd.DDProxy
22333  * A simple class that provides the basic implementation needed to make any element draggable.
22334  * @constructor
22335  * @param {String/HTMLElement/Element} el The container element
22336  * @param {Object} config
22337  */
22338 Roo.dd.DragSource = function(el, config){
22339     this.el = Roo.get(el);
22340     this.dragData = {};
22341     
22342     Roo.apply(this, config);
22343     
22344     if(!this.proxy){
22345         this.proxy = new Roo.dd.StatusProxy();
22346     }
22347
22348     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22349           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22350     
22351     this.dragging = false;
22352 };
22353
22354 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22355     /**
22356      * @cfg {String} dropAllowed
22357      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22358      */
22359     dropAllowed : "x-dd-drop-ok",
22360     /**
22361      * @cfg {String} dropNotAllowed
22362      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22363      */
22364     dropNotAllowed : "x-dd-drop-nodrop",
22365
22366     /**
22367      * Returns the data object associated with this drag source
22368      * @return {Object} data An object containing arbitrary data
22369      */
22370     getDragData : function(e){
22371         return this.dragData;
22372     },
22373
22374     // private
22375     onDragEnter : function(e, id){
22376         var target = Roo.dd.DragDropMgr.getDDById(id);
22377         this.cachedTarget = target;
22378         if(this.beforeDragEnter(target, e, id) !== false){
22379             if(target.isNotifyTarget){
22380                 var status = target.notifyEnter(this, e, this.dragData);
22381                 this.proxy.setStatus(status);
22382             }else{
22383                 this.proxy.setStatus(this.dropAllowed);
22384             }
22385             
22386             if(this.afterDragEnter){
22387                 /**
22388                  * An empty function by default, but provided so that you can perform a custom action
22389                  * when the dragged item enters the drop target by providing an implementation.
22390                  * @param {Roo.dd.DragDrop} target The drop target
22391                  * @param {Event} e The event object
22392                  * @param {String} id The id of the dragged element
22393                  * @method afterDragEnter
22394                  */
22395                 this.afterDragEnter(target, e, id);
22396             }
22397         }
22398     },
22399
22400     /**
22401      * An empty function by default, but provided so that you can perform a custom action
22402      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22403      * @param {Roo.dd.DragDrop} target The drop target
22404      * @param {Event} e The event object
22405      * @param {String} id The id of the dragged element
22406      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22407      */
22408     beforeDragEnter : function(target, e, id){
22409         return true;
22410     },
22411
22412     // private
22413     alignElWithMouse: function() {
22414         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22415         this.proxy.sync();
22416     },
22417
22418     // private
22419     onDragOver : function(e, id){
22420         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22421         if(this.beforeDragOver(target, e, id) !== false){
22422             if(target.isNotifyTarget){
22423                 var status = target.notifyOver(this, e, this.dragData);
22424                 this.proxy.setStatus(status);
22425             }
22426
22427             if(this.afterDragOver){
22428                 /**
22429                  * An empty function by default, but provided so that you can perform a custom action
22430                  * while the dragged item is over the drop target by providing an implementation.
22431                  * @param {Roo.dd.DragDrop} target The drop target
22432                  * @param {Event} e The event object
22433                  * @param {String} id The id of the dragged element
22434                  * @method afterDragOver
22435                  */
22436                 this.afterDragOver(target, e, id);
22437             }
22438         }
22439     },
22440
22441     /**
22442      * An empty function by default, but provided so that you can perform a custom action
22443      * while the dragged item is over the drop target and optionally cancel the onDragOver.
22444      * @param {Roo.dd.DragDrop} target The drop target
22445      * @param {Event} e The event object
22446      * @param {String} id The id of the dragged element
22447      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22448      */
22449     beforeDragOver : function(target, e, id){
22450         return true;
22451     },
22452
22453     // private
22454     onDragOut : function(e, id){
22455         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22456         if(this.beforeDragOut(target, e, id) !== false){
22457             if(target.isNotifyTarget){
22458                 target.notifyOut(this, e, this.dragData);
22459             }
22460             this.proxy.reset();
22461             if(this.afterDragOut){
22462                 /**
22463                  * An empty function by default, but provided so that you can perform a custom action
22464                  * after the dragged item is dragged out of the target without dropping.
22465                  * @param {Roo.dd.DragDrop} target The drop target
22466                  * @param {Event} e The event object
22467                  * @param {String} id The id of the dragged element
22468                  * @method afterDragOut
22469                  */
22470                 this.afterDragOut(target, e, id);
22471             }
22472         }
22473         this.cachedTarget = null;
22474     },
22475
22476     /**
22477      * An empty function by default, but provided so that you can perform a custom action before the dragged
22478      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22479      * @param {Roo.dd.DragDrop} target The drop target
22480      * @param {Event} e The event object
22481      * @param {String} id The id of the dragged element
22482      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22483      */
22484     beforeDragOut : function(target, e, id){
22485         return true;
22486     },
22487     
22488     // private
22489     onDragDrop : function(e, id){
22490         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22491         if(this.beforeDragDrop(target, e, id) !== false){
22492             if(target.isNotifyTarget){
22493                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22494                     this.onValidDrop(target, e, id);
22495                 }else{
22496                     this.onInvalidDrop(target, e, id);
22497                 }
22498             }else{
22499                 this.onValidDrop(target, e, id);
22500             }
22501             
22502             if(this.afterDragDrop){
22503                 /**
22504                  * An empty function by default, but provided so that you can perform a custom action
22505                  * after a valid drag drop has occurred by providing an implementation.
22506                  * @param {Roo.dd.DragDrop} target The drop target
22507                  * @param {Event} e The event object
22508                  * @param {String} id The id of the dropped element
22509                  * @method afterDragDrop
22510                  */
22511                 this.afterDragDrop(target, e, id);
22512             }
22513         }
22514         delete this.cachedTarget;
22515     },
22516
22517     /**
22518      * An empty function by default, but provided so that you can perform a custom action before the dragged
22519      * item is dropped onto the target and optionally cancel the onDragDrop.
22520      * @param {Roo.dd.DragDrop} target The drop target
22521      * @param {Event} e The event object
22522      * @param {String} id The id of the dragged element
22523      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22524      */
22525     beforeDragDrop : function(target, e, id){
22526         return true;
22527     },
22528
22529     // private
22530     onValidDrop : function(target, e, id){
22531         this.hideProxy();
22532         if(this.afterValidDrop){
22533             /**
22534              * An empty function by default, but provided so that you can perform a custom action
22535              * after a valid drop has occurred by providing an implementation.
22536              * @param {Object} target The target DD 
22537              * @param {Event} e The event object
22538              * @param {String} id The id of the dropped element
22539              * @method afterInvalidDrop
22540              */
22541             this.afterValidDrop(target, e, id);
22542         }
22543     },
22544
22545     // private
22546     getRepairXY : function(e, data){
22547         return this.el.getXY();  
22548     },
22549
22550     // private
22551     onInvalidDrop : function(target, e, id){
22552         this.beforeInvalidDrop(target, e, id);
22553         if(this.cachedTarget){
22554             if(this.cachedTarget.isNotifyTarget){
22555                 this.cachedTarget.notifyOut(this, e, this.dragData);
22556             }
22557             this.cacheTarget = null;
22558         }
22559         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22560
22561         if(this.afterInvalidDrop){
22562             /**
22563              * An empty function by default, but provided so that you can perform a custom action
22564              * after an invalid drop has occurred by providing an implementation.
22565              * @param {Event} e The event object
22566              * @param {String} id The id of the dropped element
22567              * @method afterInvalidDrop
22568              */
22569             this.afterInvalidDrop(e, id);
22570         }
22571     },
22572
22573     // private
22574     afterRepair : function(){
22575         if(Roo.enableFx){
22576             this.el.highlight(this.hlColor || "c3daf9");
22577         }
22578         this.dragging = false;
22579     },
22580
22581     /**
22582      * An empty function by default, but provided so that you can perform a custom action after an invalid
22583      * drop has occurred.
22584      * @param {Roo.dd.DragDrop} target The drop target
22585      * @param {Event} e The event object
22586      * @param {String} id The id of the dragged element
22587      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22588      */
22589     beforeInvalidDrop : function(target, e, id){
22590         return true;
22591     },
22592
22593     // private
22594     handleMouseDown : function(e){
22595         if(this.dragging) {
22596             return;
22597         }
22598         var data = this.getDragData(e);
22599         if(data && this.onBeforeDrag(data, e) !== false){
22600             this.dragData = data;
22601             this.proxy.stop();
22602             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22603         } 
22604     },
22605
22606     /**
22607      * An empty function by default, but provided so that you can perform a custom action before the initial
22608      * drag event begins and optionally cancel it.
22609      * @param {Object} data An object containing arbitrary data to be shared with drop targets
22610      * @param {Event} e The event object
22611      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22612      */
22613     onBeforeDrag : function(data, e){
22614         return true;
22615     },
22616
22617     /**
22618      * An empty function by default, but provided so that you can perform a custom action once the initial
22619      * drag event has begun.  The drag cannot be canceled from this function.
22620      * @param {Number} x The x position of the click on the dragged object
22621      * @param {Number} y The y position of the click on the dragged object
22622      */
22623     onStartDrag : Roo.emptyFn,
22624
22625     // private - YUI override
22626     startDrag : function(x, y){
22627         this.proxy.reset();
22628         this.dragging = true;
22629         this.proxy.update("");
22630         this.onInitDrag(x, y);
22631         this.proxy.show();
22632     },
22633
22634     // private
22635     onInitDrag : function(x, y){
22636         var clone = this.el.dom.cloneNode(true);
22637         clone.id = Roo.id(); // prevent duplicate ids
22638         this.proxy.update(clone);
22639         this.onStartDrag(x, y);
22640         return true;
22641     },
22642
22643     /**
22644      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22645      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22646      */
22647     getProxy : function(){
22648         return this.proxy;  
22649     },
22650
22651     /**
22652      * Hides the drag source's {@link Roo.dd.StatusProxy}
22653      */
22654     hideProxy : function(){
22655         this.proxy.hide();  
22656         this.proxy.reset(true);
22657         this.dragging = false;
22658     },
22659
22660     // private
22661     triggerCacheRefresh : function(){
22662         Roo.dd.DDM.refreshCache(this.groups);
22663     },
22664
22665     // private - override to prevent hiding
22666     b4EndDrag: function(e) {
22667     },
22668
22669     // private - override to prevent moving
22670     endDrag : function(e){
22671         this.onEndDrag(this.dragData, e);
22672     },
22673
22674     // private
22675     onEndDrag : function(data, e){
22676     },
22677     
22678     // private - pin to cursor
22679     autoOffset : function(x, y) {
22680         this.setDelta(-12, -20);
22681     }    
22682 });/*
22683  * Based on:
22684  * Ext JS Library 1.1.1
22685  * Copyright(c) 2006-2007, Ext JS, LLC.
22686  *
22687  * Originally Released Under LGPL - original licence link has changed is not relivant.
22688  *
22689  * Fork - LGPL
22690  * <script type="text/javascript">
22691  */
22692
22693
22694 /**
22695  * @class Roo.dd.DropTarget
22696  * @extends Roo.dd.DDTarget
22697  * A simple class that provides the basic implementation needed to make any element a drop target that can have
22698  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
22699  * @constructor
22700  * @param {String/HTMLElement/Element} el The container element
22701  * @param {Object} config
22702  */
22703 Roo.dd.DropTarget = function(el, config){
22704     this.el = Roo.get(el);
22705     
22706     var listeners = false; ;
22707     if (config && config.listeners) {
22708         listeners= config.listeners;
22709         delete config.listeners;
22710     }
22711     Roo.apply(this, config);
22712     
22713     if(this.containerScroll){
22714         Roo.dd.ScrollManager.register(this.el);
22715     }
22716     this.addEvents( {
22717          /**
22718          * @scope Roo.dd.DropTarget
22719          */
22720          
22721          /**
22722          * @event enter
22723          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22724          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
22725          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
22726          * 
22727          * IMPORTANT : it should set  this.valid to true|false
22728          * 
22729          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22730          * @param {Event} e The event
22731          * @param {Object} data An object containing arbitrary data supplied by the drag source
22732          */
22733         "enter" : true,
22734         
22735          /**
22736          * @event over
22737          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22738          * This method will be called on every mouse movement while the drag source is over the drop target.
22739          * This default implementation simply returns the dropAllowed config value.
22740          * 
22741          * IMPORTANT : it should set  this.valid to true|false
22742          * 
22743          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22744          * @param {Event} e The event
22745          * @param {Object} data An object containing arbitrary data supplied by the drag source
22746          
22747          */
22748         "over" : true,
22749         /**
22750          * @event out
22751          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22752          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
22753          * overClass (if any) from the drop element.
22754          * 
22755          * 
22756          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22757          * @param {Event} e The event
22758          * @param {Object} data An object containing arbitrary data supplied by the drag source
22759          */
22760          "out" : true,
22761          
22762         /**
22763          * @event drop
22764          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22765          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
22766          * implementation that does something to process the drop event and returns true so that the drag source's
22767          * repair action does not run.
22768          * 
22769          * IMPORTANT : it should set this.success
22770          * 
22771          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22772          * @param {Event} e The event
22773          * @param {Object} data An object containing arbitrary data supplied by the drag source
22774         */
22775          "drop" : true
22776     });
22777             
22778      
22779     Roo.dd.DropTarget.superclass.constructor.call(  this, 
22780         this.el.dom, 
22781         this.ddGroup || this.group,
22782         {
22783             isTarget: true,
22784             listeners : listeners || {} 
22785            
22786         
22787         }
22788     );
22789
22790 };
22791
22792 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22793     /**
22794      * @cfg {String} overClass
22795      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22796      */
22797      /**
22798      * @cfg {String} ddGroup
22799      * The drag drop group to handle drop events for
22800      */
22801      
22802     /**
22803      * @cfg {String} dropAllowed
22804      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22805      */
22806     dropAllowed : "x-dd-drop-ok",
22807     /**
22808      * @cfg {String} dropNotAllowed
22809      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22810      */
22811     dropNotAllowed : "x-dd-drop-nodrop",
22812     /**
22813      * @cfg {boolean} success
22814      * set this after drop listener.. 
22815      */
22816     success : false,
22817     /**
22818      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22819      * if the drop point is valid for over/enter..
22820      */
22821     valid : false,
22822     // private
22823     isTarget : true,
22824
22825     // private
22826     isNotifyTarget : true,
22827     
22828     /**
22829      * @hide
22830      */
22831     notifyEnter : function(dd, e, data)
22832     {
22833         this.valid = true;
22834         this.fireEvent('enter', dd, e, data);
22835         if(this.overClass){
22836             this.el.addClass(this.overClass);
22837         }
22838         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22839             this.valid ? this.dropAllowed : this.dropNotAllowed
22840         );
22841     },
22842
22843     /**
22844      * @hide
22845      */
22846     notifyOver : function(dd, e, data)
22847     {
22848         this.valid = true;
22849         this.fireEvent('over', dd, e, data);
22850         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22851             this.valid ? this.dropAllowed : this.dropNotAllowed
22852         );
22853     },
22854
22855     /**
22856      * @hide
22857      */
22858     notifyOut : function(dd, e, data)
22859     {
22860         this.fireEvent('out', dd, e, data);
22861         if(this.overClass){
22862             this.el.removeClass(this.overClass);
22863         }
22864     },
22865
22866     /**
22867      * @hide
22868      */
22869     notifyDrop : function(dd, e, data)
22870     {
22871         this.success = false;
22872         this.fireEvent('drop', dd, e, data);
22873         return this.success;
22874     }
22875 });/*
22876  * Based on:
22877  * Ext JS Library 1.1.1
22878  * Copyright(c) 2006-2007, Ext JS, LLC.
22879  *
22880  * Originally Released Under LGPL - original licence link has changed is not relivant.
22881  *
22882  * Fork - LGPL
22883  * <script type="text/javascript">
22884  */
22885
22886
22887 /**
22888  * @class Roo.dd.DragZone
22889  * @extends Roo.dd.DragSource
22890  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22891  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22892  * @constructor
22893  * @param {String/HTMLElement/Element} el The container element
22894  * @param {Object} config
22895  */
22896 Roo.dd.DragZone = function(el, config){
22897     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22898     if(this.containerScroll){
22899         Roo.dd.ScrollManager.register(this.el);
22900     }
22901 };
22902
22903 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22904     /**
22905      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22906      * for auto scrolling during drag operations.
22907      */
22908     /**
22909      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22910      * method after a failed drop (defaults to "c3daf9" - light blue)
22911      */
22912
22913     /**
22914      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22915      * for a valid target to drag based on the mouse down. Override this method
22916      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22917      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22918      * @param {EventObject} e The mouse down event
22919      * @return {Object} The dragData
22920      */
22921     getDragData : function(e){
22922         return Roo.dd.Registry.getHandleFromEvent(e);
22923     },
22924     
22925     /**
22926      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22927      * this.dragData.ddel
22928      * @param {Number} x The x position of the click on the dragged object
22929      * @param {Number} y The y position of the click on the dragged object
22930      * @return {Boolean} true to continue the drag, false to cancel
22931      */
22932     onInitDrag : function(x, y){
22933         this.proxy.update(this.dragData.ddel.cloneNode(true));
22934         this.onStartDrag(x, y);
22935         return true;
22936     },
22937     
22938     /**
22939      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22940      */
22941     afterRepair : function(){
22942         if(Roo.enableFx){
22943             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22944         }
22945         this.dragging = false;
22946     },
22947
22948     /**
22949      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22950      * the XY of this.dragData.ddel
22951      * @param {EventObject} e The mouse up event
22952      * @return {Array} The xy location (e.g. [100, 200])
22953      */
22954     getRepairXY : function(e){
22955         return Roo.Element.fly(this.dragData.ddel).getXY();  
22956     }
22957 });/*
22958  * Based on:
22959  * Ext JS Library 1.1.1
22960  * Copyright(c) 2006-2007, Ext JS, LLC.
22961  *
22962  * Originally Released Under LGPL - original licence link has changed is not relivant.
22963  *
22964  * Fork - LGPL
22965  * <script type="text/javascript">
22966  */
22967 /**
22968  * @class Roo.dd.DropZone
22969  * @extends Roo.dd.DropTarget
22970  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22971  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22972  * @constructor
22973  * @param {String/HTMLElement/Element} el The container element
22974  * @param {Object} config
22975  */
22976 Roo.dd.DropZone = function(el, config){
22977     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22978 };
22979
22980 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22981     /**
22982      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22983      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22984      * provide your own custom lookup.
22985      * @param {Event} e The event
22986      * @return {Object} data The custom data
22987      */
22988     getTargetFromEvent : function(e){
22989         return Roo.dd.Registry.getTargetFromEvent(e);
22990     },
22991
22992     /**
22993      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22994      * that it has registered.  This method has no default implementation and should be overridden to provide
22995      * node-specific processing if necessary.
22996      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22997      * {@link #getTargetFromEvent} for this node)
22998      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22999      * @param {Event} e The event
23000      * @param {Object} data An object containing arbitrary data supplied by the drag source
23001      */
23002     onNodeEnter : function(n, dd, e, data){
23003         
23004     },
23005
23006     /**
23007      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23008      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
23009      * overridden to provide the proper feedback.
23010      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23011      * {@link #getTargetFromEvent} for this node)
23012      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23013      * @param {Event} e The event
23014      * @param {Object} data An object containing arbitrary data supplied by the drag source
23015      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23016      * underlying {@link Roo.dd.StatusProxy} can be updated
23017      */
23018     onNodeOver : function(n, dd, e, data){
23019         return this.dropAllowed;
23020     },
23021
23022     /**
23023      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23024      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
23025      * node-specific processing if necessary.
23026      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23027      * {@link #getTargetFromEvent} for this node)
23028      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23029      * @param {Event} e The event
23030      * @param {Object} data An object containing arbitrary data supplied by the drag source
23031      */
23032     onNodeOut : function(n, dd, e, data){
23033         
23034     },
23035
23036     /**
23037      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23038      * the drop node.  The default implementation returns false, so it should be overridden to provide the
23039      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23040      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23041      * {@link #getTargetFromEvent} for this node)
23042      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23043      * @param {Event} e The event
23044      * @param {Object} data An object containing arbitrary data supplied by the drag source
23045      * @return {Boolean} True if the drop was valid, else false
23046      */
23047     onNodeDrop : function(n, dd, e, data){
23048         return false;
23049     },
23050
23051     /**
23052      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23053      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
23054      * it should be overridden to provide the proper feedback if necessary.
23055      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23056      * @param {Event} e The event
23057      * @param {Object} data An object containing arbitrary data supplied by the drag source
23058      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23059      * underlying {@link Roo.dd.StatusProxy} can be updated
23060      */
23061     onContainerOver : function(dd, e, data){
23062         return this.dropNotAllowed;
23063     },
23064
23065     /**
23066      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23067      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
23068      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23069      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
23070      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23071      * @param {Event} e The event
23072      * @param {Object} data An object containing arbitrary data supplied by the drag source
23073      * @return {Boolean} True if the drop was valid, else false
23074      */
23075     onContainerDrop : function(dd, e, data){
23076         return false;
23077     },
23078
23079     /**
23080      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23081      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
23082      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23083      * you should override this method and provide a custom implementation.
23084      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23085      * @param {Event} e The event
23086      * @param {Object} data An object containing arbitrary data supplied by the drag source
23087      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23088      * underlying {@link Roo.dd.StatusProxy} can be updated
23089      */
23090     notifyEnter : function(dd, e, data){
23091         return this.dropNotAllowed;
23092     },
23093
23094     /**
23095      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23096      * This method will be called on every mouse movement while the drag source is over the drop zone.
23097      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23098      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23099      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23100      * registered node, it will call {@link #onContainerOver}.
23101      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23102      * @param {Event} e The event
23103      * @param {Object} data An object containing arbitrary data supplied by the drag source
23104      * @return {String} status The CSS class that communicates the drop status back to the source so that the
23105      * underlying {@link Roo.dd.StatusProxy} can be updated
23106      */
23107     notifyOver : function(dd, e, data){
23108         var n = this.getTargetFromEvent(e);
23109         if(!n){ // not over valid drop target
23110             if(this.lastOverNode){
23111                 this.onNodeOut(this.lastOverNode, dd, e, data);
23112                 this.lastOverNode = null;
23113             }
23114             return this.onContainerOver(dd, e, data);
23115         }
23116         if(this.lastOverNode != n){
23117             if(this.lastOverNode){
23118                 this.onNodeOut(this.lastOverNode, dd, e, data);
23119             }
23120             this.onNodeEnter(n, dd, e, data);
23121             this.lastOverNode = n;
23122         }
23123         return this.onNodeOver(n, dd, e, data);
23124     },
23125
23126     /**
23127      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23128      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
23129      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23130      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23131      * @param {Event} e The event
23132      * @param {Object} data An object containing arbitrary data supplied by the drag zone
23133      */
23134     notifyOut : function(dd, e, data){
23135         if(this.lastOverNode){
23136             this.onNodeOut(this.lastOverNode, dd, e, data);
23137             this.lastOverNode = null;
23138         }
23139     },
23140
23141     /**
23142      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23143      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
23144      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23145      * otherwise it will call {@link #onContainerDrop}.
23146      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23147      * @param {Event} e The event
23148      * @param {Object} data An object containing arbitrary data supplied by the drag source
23149      * @return {Boolean} True if the drop was valid, else false
23150      */
23151     notifyDrop : function(dd, e, data){
23152         if(this.lastOverNode){
23153             this.onNodeOut(this.lastOverNode, dd, e, data);
23154             this.lastOverNode = null;
23155         }
23156         var n = this.getTargetFromEvent(e);
23157         return n ?
23158             this.onNodeDrop(n, dd, e, data) :
23159             this.onContainerDrop(dd, e, data);
23160     },
23161
23162     // private
23163     triggerCacheRefresh : function(){
23164         Roo.dd.DDM.refreshCache(this.groups);
23165     }  
23166 });