roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @static
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             
346             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         },
672                 /**
673                  * Find the current bootstrap width Grid size
674                  * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675                  * @returns {String} (xs|sm|md|lg|xl)
676                  */
677                 
678                 getGridSize : function()
679                 {
680                         var w = Roo.lib.Dom.getViewWidth();
681                         switch(true) {
682                                 case w > 1200:
683                                         return 'xl';
684                                 case w > 992:
685                                         return 'lg';
686                                 case w > 768:
687                                         return 'md';
688                                 case w > 576:
689                                         return 'sm';
690                                 default:
691                                         return 'xs'
692                         }
693                         
694                 } 
695         
696     });
697
698
699 })();
700
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
703                 "Roo.app", "Roo.ux" 
704                );
705 /*
706  * Based on:
707  * Ext JS Library 1.1.1
708  * Copyright(c) 2006-2007, Ext JS, LLC.
709  *
710  * Originally Released Under LGPL - original licence link has changed is not relivant.
711  *
712  * Fork - LGPL
713  * <script type="text/javascript">
714  */
715
716 (function() {    
717     // wrappedn so fnCleanup is not in global scope...
718     if(Roo.isIE) {
719         function fnCleanUp() {
720             var p = Function.prototype;
721             delete p.createSequence;
722             delete p.defer;
723             delete p.createDelegate;
724             delete p.createCallback;
725             delete p.createInterceptor;
726
727             window.detachEvent("onunload", fnCleanUp);
728         }
729         window.attachEvent("onunload", fnCleanUp);
730     }
731 })();
732
733
734 /**
735  * @class Function
736  * These functions are available on every Function object (any JavaScript function).
737  */
738 Roo.apply(Function.prototype, {
739      /**
740      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
741      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
742      * Will create a function that is bound to those 2 args.
743      * @return {Function} The new function
744     */
745     createCallback : function(/*args...*/){
746         // make args available, in function below
747         var args = arguments;
748         var method = this;
749         return function() {
750             return method.apply(window, args);
751         };
752     },
753
754     /**
755      * Creates a delegate (callback) that sets the scope to obj.
756      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
757      * Will create a function that is automatically scoped to this.
758      * @param {Object} obj (optional) The object for which the scope is set
759      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
760      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
761      *                                             if a number the args are inserted at the specified position
762      * @return {Function} The new function
763      */
764     createDelegate : function(obj, args, appendArgs){
765         var method = this;
766         return function() {
767             var callArgs = args || arguments;
768             if(appendArgs === true){
769                 callArgs = Array.prototype.slice.call(arguments, 0);
770                 callArgs = callArgs.concat(args);
771             }else if(typeof appendArgs == "number"){
772                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
773                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
774                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
775             }
776             return method.apply(obj || window, callArgs);
777         };
778     },
779
780     /**
781      * Calls this function after the number of millseconds specified.
782      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
783      * @param {Object} obj (optional) The object for which the scope is set
784      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
785      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
786      *                                             if a number the args are inserted at the specified position
787      * @return {Number} The timeout id that can be used with clearTimeout
788      */
789     defer : function(millis, obj, args, appendArgs){
790         var fn = this.createDelegate(obj, args, appendArgs);
791         if(millis){
792             return setTimeout(fn, millis);
793         }
794         fn();
795         return 0;
796     },
797     /**
798      * Create a combined function call sequence of the original function + the passed function.
799      * The resulting function returns the results of the original function.
800      * The passed fcn is called with the parameters of the original function
801      * @param {Function} fcn The function to sequence
802      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
803      * @return {Function} The new function
804      */
805     createSequence : function(fcn, scope){
806         if(typeof fcn != "function"){
807             return this;
808         }
809         var method = this;
810         return function() {
811             var retval = method.apply(this || window, arguments);
812             fcn.apply(scope || this || window, arguments);
813             return retval;
814         };
815     },
816
817     /**
818      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
819      * The resulting function returns the results of the original function.
820      * The passed fcn is called with the parameters of the original function.
821      * @addon
822      * @param {Function} fcn The function to call before the original
823      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
824      * @return {Function} The new function
825      */
826     createInterceptor : function(fcn, scope){
827         if(typeof fcn != "function"){
828             return this;
829         }
830         var method = this;
831         return function() {
832             fcn.target = this;
833             fcn.method = method;
834             if(fcn.apply(scope || this || window, arguments) === false){
835                 return;
836             }
837             return method.apply(this || window, arguments);
838         };
839     }
840 });
841 /*
842  * Based on:
843  * Ext JS Library 1.1.1
844  * Copyright(c) 2006-2007, Ext JS, LLC.
845  *
846  * Originally Released Under LGPL - original licence link has changed is not relivant.
847  *
848  * Fork - LGPL
849  * <script type="text/javascript">
850  */
851
852 Roo.applyIf(String, {
853     
854     /** @scope String */
855     
856     /**
857      * Escapes the passed string for ' and \
858      * @param {String} string The string to escape
859      * @return {String} The escaped string
860      * @static
861      */
862     escape : function(string) {
863         return string.replace(/('|\\)/g, "\\$1");
864     },
865
866     /**
867      * Pads the left side of a string with a specified character.  This is especially useful
868      * for normalizing number and date strings.  Example usage:
869      * <pre><code>
870 var s = String.leftPad('123', 5, '0');
871 // s now contains the string: '00123'
872 </code></pre>
873      * @param {String} string The original string
874      * @param {Number} size The total length of the output string
875      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
876      * @return {String} The padded string
877      * @static
878      */
879     leftPad : function (val, size, ch) {
880         var result = new String(val);
881         if(ch === null || ch === undefined || ch === '') {
882             ch = " ";
883         }
884         while (result.length < size) {
885             result = ch + result;
886         }
887         return result;
888     },
889
890     /**
891      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
892      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
893      * <pre><code>
894 var cls = 'my-class', text = 'Some text';
895 var s = String.format('<div class="{0}">{1}</div>', cls, text);
896 // s now contains the string: '<div class="my-class">Some text</div>'
897 </code></pre>
898      * @param {String} string The tokenized string to be formatted
899      * @param {String} value1 The value to replace token {0}
900      * @param {String} value2 Etc...
901      * @return {String} The formatted string
902      * @static
903      */
904     format : function(format){
905         var args = Array.prototype.slice.call(arguments, 1);
906         return format.replace(/\{(\d+)\}/g, function(m, i){
907             return Roo.util.Format.htmlEncode(args[i]);
908         });
909     }
910   
911     
912 });
913
914 /**
915  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
916  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
917  * they are already different, the first value passed in is returned.  Note that this method returns the new value
918  * but does not change the current string.
919  * <pre><code>
920 // alternate sort directions
921 sort = sort.toggle('ASC', 'DESC');
922
923 // instead of conditional logic:
924 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
925 </code></pre>
926  * @param {String} value The value to compare to the current string
927  * @param {String} other The new value to use if the string already equals the first value passed in
928  * @return {String} The new value
929  */
930  
931 String.prototype.toggle = function(value, other){
932     return this == value ? other : value;
933 };
934
935
936 /**
937   * Remove invalid unicode characters from a string 
938   *
939   * @return {String} The clean string
940   */
941 String.prototype.unicodeClean = function () {
942     return this.replace(/[\s\S]/g,
943         function(character) {
944             if (character.charCodeAt()< 256) {
945               return character;
946            }
947            try {
948                 encodeURIComponent(character);
949            } catch(e) { 
950               return '';
951            }
952            return character;
953         }
954     );
955 };
956   
957
958 /**
959   * Make the first letter of a string uppercase
960   *
961   * @return {String} The new string.
962   */
963 String.prototype.toUpperCaseFirst = function () {
964     return this.charAt(0).toUpperCase() + this.slice(1);
965 };  
966   
967 /*
968  * Based on:
969  * Ext JS Library 1.1.1
970  * Copyright(c) 2006-2007, Ext JS, LLC.
971  *
972  * Originally Released Under LGPL - original licence link has changed is not relivant.
973  *
974  * Fork - LGPL
975  * <script type="text/javascript">
976  */
977
978  /**
979  * @class Number
980  */
981 Roo.applyIf(Number.prototype, {
982     /**
983      * Checks whether or not the current number is within a desired range.  If the number is already within the
984      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
985      * exceeded.  Note that this method returns the constrained value but does not change the current number.
986      * @param {Number} min The minimum number in the range
987      * @param {Number} max The maximum number in the range
988      * @return {Number} The constrained value if outside the range, otherwise the current value
989      */
990     constrain : function(min, max){
991         return Math.min(Math.max(this, min), max);
992     }
993 });/*
994  * Based on:
995  * Ext JS Library 1.1.1
996  * Copyright(c) 2006-2007, Ext JS, LLC.
997  *
998  * Originally Released Under LGPL - original licence link has changed is not relivant.
999  *
1000  * Fork - LGPL
1001  * <script type="text/javascript">
1002  */
1003  /**
1004  * @class Array
1005  */
1006 Roo.applyIf(Array.prototype, {
1007     /**
1008      * 
1009      * Checks whether or not the specified object exists in the array.
1010      * @param {Object} o The object to check for
1011      * @return {Number} The index of o in the array (or -1 if it is not found)
1012      */
1013     indexOf : function(o){
1014        for (var i = 0, len = this.length; i < len; i++){
1015               if(this[i] == o) { return i; }
1016        }
1017            return -1;
1018     },
1019
1020     /**
1021      * Removes the specified object from the array.  If the object is not found nothing happens.
1022      * @param {Object} o The object to remove
1023      */
1024     remove : function(o){
1025        var index = this.indexOf(o);
1026        if(index != -1){
1027            this.splice(index, 1);
1028        }
1029     },
1030     /**
1031      * Map (JS 1.6 compatibility)
1032      * @param {Function} function  to call
1033      */
1034     map : function(fun )
1035     {
1036         var len = this.length >>> 0;
1037         if (typeof fun != "function") {
1038             throw new TypeError();
1039         }
1040         var res = new Array(len);
1041         var thisp = arguments[1];
1042         for (var i = 0; i < len; i++)
1043         {
1044             if (i in this) {
1045                 res[i] = fun.call(thisp, this[i], i, this);
1046             }
1047         }
1048
1049         return res;
1050     },
1051     /**
1052      * equals
1053      * @param {Array} o The array to compare to
1054      * @returns {Boolean} true if the same
1055      */
1056     equals : function(b)
1057     {
1058             // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1059         if (this === b) {
1060             return true;
1061         }
1062         if (b == null) {
1063             return false;
1064         }
1065         if (this.length !== b.length) {
1066             return false;
1067         }
1068           
1069         // sort?? a.sort().equals(b.sort());
1070           
1071         for (var i = 0; i < this.length; ++i) {
1072             if (this[i] !== b[i]) {
1073             return false;
1074             }
1075         }
1076         return true;
1077     } 
1078     
1079     
1080     
1081     
1082 });
1083
1084 Roo.applyIf(Array, {
1085  /**
1086      * from
1087      * @static
1088      * @param {Array} o Or Array like object (eg. nodelist)
1089      * @returns {Array} 
1090      */
1091     from : function(o)
1092     {
1093         var ret= [];
1094     
1095         for (var i =0; i < o.length; i++) { 
1096             ret[i] = o[i];
1097         }
1098         return ret;
1099       
1100     }
1101 });
1102 /*
1103  * Based on:
1104  * Ext JS Library 1.1.1
1105  * Copyright(c) 2006-2007, Ext JS, LLC.
1106  *
1107  * Originally Released Under LGPL - original licence link has changed is not relivant.
1108  *
1109  * Fork - LGPL
1110  * <script type="text/javascript">
1111  */
1112
1113 /**
1114  * @class Date
1115  *
1116  * The date parsing and format syntax is a subset of
1117  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1118  * supported will provide results equivalent to their PHP versions.
1119  *
1120  * Following is the list of all currently supported formats:
1121  *<pre>
1122 Sample date:
1123 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1124
1125 Format  Output      Description
1126 ------  ----------  --------------------------------------------------------------
1127   d      10         Day of the month, 2 digits with leading zeros
1128   D      Wed        A textual representation of a day, three letters
1129   j      10         Day of the month without leading zeros
1130   l      Wednesday  A full textual representation of the day of the week
1131   S      th         English ordinal day of month suffix, 2 chars (use with j)
1132   w      3          Numeric representation of the day of the week
1133   z      9          The julian date, or day of the year (0-365)
1134   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1135   F      January    A full textual representation of the month
1136   m      01         Numeric representation of a month, with leading zeros
1137   M      Jan        Month name abbreviation, three letters
1138   n      1          Numeric representation of a month, without leading zeros
1139   t      31         Number of days in the given month
1140   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1141   Y      2007       A full numeric representation of a year, 4 digits
1142   y      07         A two digit representation of a year
1143   a      pm         Lowercase Ante meridiem and Post meridiem
1144   A      PM         Uppercase Ante meridiem and Post meridiem
1145   g      3          12-hour format of an hour without leading zeros
1146   G      15         24-hour format of an hour without leading zeros
1147   h      03         12-hour format of an hour with leading zeros
1148   H      15         24-hour format of an hour with leading zeros
1149   i      05         Minutes with leading zeros
1150   s      01         Seconds, with leading zeros
1151   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1152   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1153   T      CST        Timezone setting of the machine running the code
1154   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1155 </pre>
1156  *
1157  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1158  * <pre><code>
1159 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1160 document.write(dt.format('Y-m-d'));                         //2007-01-10
1161 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1162 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1163  </code></pre>
1164  *
1165  * Here are some standard date/time patterns that you might find helpful.  They
1166  * are not part of the source of Date.js, but to use them you can simply copy this
1167  * block of code into any script that is included after Date.js and they will also become
1168  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1169  * <pre><code>
1170 Date.patterns = {
1171     ISO8601Long:"Y-m-d H:i:s",
1172     ISO8601Short:"Y-m-d",
1173     ShortDate: "n/j/Y",
1174     LongDate: "l, F d, Y",
1175     FullDateTime: "l, F d, Y g:i:s A",
1176     MonthDay: "F d",
1177     ShortTime: "g:i A",
1178     LongTime: "g:i:s A",
1179     SortableDateTime: "Y-m-d\\TH:i:s",
1180     UniversalSortableDateTime: "Y-m-d H:i:sO",
1181     YearMonth: "F, Y"
1182 };
1183 </code></pre>
1184  *
1185  * Example usage:
1186  * <pre><code>
1187 var dt = new Date();
1188 document.write(dt.format(Date.patterns.ShortDate));
1189  </code></pre>
1190  */
1191
1192 /*
1193  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1194  * They generate precompiled functions from date formats instead of parsing and
1195  * processing the pattern every time you format a date.  These functions are available
1196  * on every Date object (any javascript function).
1197  *
1198  * The original article and download are here:
1199  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1200  *
1201  */
1202  
1203  
1204  // was in core
1205 /**
1206  Returns the number of milliseconds between this date and date
1207  @param {Date} date (optional) Defaults to now
1208  @param {String} interval (optional) Default Date.MILLI, A valid date interval enum value (eg. Date.DAY) 
1209  @return {Number} The diff in milliseconds or units of interval
1210  @member Date getElapsed
1211  */
1212 Date.prototype.getElapsed = function(date, interval)
1213 {
1214     date = date ||  new Date();
1215     var ret = Math.abs(date.getTime()-this.getTime());
1216     switch (interval) {
1217        
1218         case  Date.SECOND:
1219             return Math.floor(ret / (1000));
1220         case  Date.MINUTE:
1221             return Math.floor(ret / (1000*60));
1222         case  Date.HOUR:
1223             return Math.floor(ret / (1000*60*60));
1224         case  Date.DAY:
1225             return Math.floor(ret / (1000*60*60*24));
1226         case  Date.MONTH: // this does not give exact number...??
1227             return ((date.format("Y") - this.format("Y")) * 12) + (date.format("m") - this.format("m"));
1228         case  Date.YEAR: // this does not give exact number...??
1229             return (date.format("Y") - this.format("Y"));
1230        
1231         case  Date.MILLI:
1232         default:
1233             return ret;
1234     }
1235 };
1236  
1237 // was in date file..
1238
1239
1240 // private
1241 Date.parseFunctions = {count:0};
1242 // private
1243 Date.parseRegexes = [];
1244 // private
1245 Date.formatFunctions = {count:0};
1246
1247 // private
1248 Date.prototype.dateFormat = function(format) {
1249     if (Date.formatFunctions[format] == null) {
1250         Date.createNewFormat(format);
1251     }
1252     var func = Date.formatFunctions[format];
1253     return this[func]();
1254 };
1255
1256
1257 /**
1258  * Formats a date given the supplied format string
1259  * @param {String} format The format string
1260  * @return {String} The formatted date
1261  * @method
1262  */
1263 Date.prototype.format = Date.prototype.dateFormat;
1264
1265 // private
1266 Date.createNewFormat = function(format) {
1267     var funcName = "format" + Date.formatFunctions.count++;
1268     Date.formatFunctions[format] = funcName;
1269     var code = "Date.prototype." + funcName + " = function(){return ";
1270     var special = false;
1271     var ch = '';
1272     for (var i = 0; i < format.length; ++i) {
1273         ch = format.charAt(i);
1274         if (!special && ch == "\\") {
1275             special = true;
1276         }
1277         else if (special) {
1278             special = false;
1279             code += "'" + String.escape(ch) + "' + ";
1280         }
1281         else {
1282             code += Date.getFormatCode(ch);
1283         }
1284     }
1285     /** eval:var:zzzzzzzzzzzzz */
1286     eval(code.substring(0, code.length - 3) + ";}");
1287 };
1288
1289 // private
1290 Date.getFormatCode = function(character) {
1291     switch (character) {
1292     case "d":
1293         return "String.leftPad(this.getDate(), 2, '0') + ";
1294     case "D":
1295         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1296     case "j":
1297         return "this.getDate() + ";
1298     case "l":
1299         return "Date.dayNames[this.getDay()] + ";
1300     case "S":
1301         return "this.getSuffix() + ";
1302     case "w":
1303         return "this.getDay() + ";
1304     case "z":
1305         return "this.getDayOfYear() + ";
1306     case "W":
1307         return "this.getWeekOfYear() + ";
1308     case "F":
1309         return "Date.monthNames[this.getMonth()] + ";
1310     case "m":
1311         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1312     case "M":
1313         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1314     case "n":
1315         return "(this.getMonth() + 1) + ";
1316     case "t":
1317         return "this.getDaysInMonth() + ";
1318     case "L":
1319         return "(this.isLeapYear() ? 1 : 0) + ";
1320     case "Y":
1321         return "this.getFullYear() + ";
1322     case "y":
1323         return "('' + this.getFullYear()).substring(2, 4) + ";
1324     case "a":
1325         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1326     case "A":
1327         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1328     case "g":
1329         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1330     case "G":
1331         return "this.getHours() + ";
1332     case "h":
1333         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1334     case "H":
1335         return "String.leftPad(this.getHours(), 2, '0') + ";
1336     case "i":
1337         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1338     case "s":
1339         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1340     case "O":
1341         return "this.getGMTOffset() + ";
1342     case "P":
1343         return "this.getGMTColonOffset() + ";
1344     case "T":
1345         return "this.getTimezone() + ";
1346     case "Z":
1347         return "(this.getTimezoneOffset() * -60) + ";
1348     default:
1349         return "'" + String.escape(character) + "' + ";
1350     }
1351 };
1352
1353 /**
1354  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1355  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1356  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1357  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1358  * string or the parse operation will fail.
1359  * Example Usage:
1360 <pre><code>
1361 //dt = Fri May 25 2007 (current date)
1362 var dt = new Date();
1363
1364 //dt = Thu May 25 2006 (today's month/day in 2006)
1365 dt = Date.parseDate("2006", "Y");
1366
1367 //dt = Sun Jan 15 2006 (all date parts specified)
1368 dt = Date.parseDate("2006-1-15", "Y-m-d");
1369
1370 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1371 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1372 </code></pre>
1373  * @param {String} input The unparsed date as a string
1374  * @param {String} format The format the date is in
1375  * @return {Date} The parsed date
1376  * @static
1377  */
1378 Date.parseDate = function(input, format) {
1379     if (Date.parseFunctions[format] == null) {
1380         Date.createParser(format);
1381     }
1382     var func = Date.parseFunctions[format];
1383     return Date[func](input);
1384 };
1385 /**
1386  * @private
1387  */
1388
1389 Date.createParser = function(format) {
1390     var funcName = "parse" + Date.parseFunctions.count++;
1391     var regexNum = Date.parseRegexes.length;
1392     var currentGroup = 1;
1393     Date.parseFunctions[format] = funcName;
1394
1395     var code = "Date." + funcName + " = function(input){\n"
1396         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1397         + "var d = new Date();\n"
1398         + "y = d.getFullYear();\n"
1399         + "m = d.getMonth();\n"
1400         + "d = d.getDate();\n"
1401         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1402         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1403         + "if (results && results.length > 0) {";
1404     var regex = "";
1405
1406     var special = false;
1407     var ch = '';
1408     for (var i = 0; i < format.length; ++i) {
1409         ch = format.charAt(i);
1410         if (!special && ch == "\\") {
1411             special = true;
1412         }
1413         else if (special) {
1414             special = false;
1415             regex += String.escape(ch);
1416         }
1417         else {
1418             var obj = Date.formatCodeToRegex(ch, currentGroup);
1419             currentGroup += obj.g;
1420             regex += obj.s;
1421             if (obj.g && obj.c) {
1422                 code += obj.c;
1423             }
1424         }
1425     }
1426
1427     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1428         + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1429         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1430         + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1431         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1432         + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1433         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1434         + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1435         + "else if (y >= 0 && m >= 0)\n"
1436         + "{v = new Date(y, m); v.setFullYear(y);}\n"
1437         + "else if (y >= 0)\n"
1438         + "{v = new Date(y); v.setFullYear(y);}\n"
1439         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1440         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1441         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1442         + ";}";
1443
1444     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1445     /** eval:var:zzzzzzzzzzzzz */
1446     eval(code);
1447 };
1448
1449 // private
1450 Date.formatCodeToRegex = function(character, currentGroup) {
1451     switch (character) {
1452     case "D":
1453         return {g:0,
1454         c:null,
1455         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1456     case "j":
1457         return {g:1,
1458             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1459             s:"(\\d{1,2})"}; // day of month without leading zeroes
1460     case "d":
1461         return {g:1,
1462             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1463             s:"(\\d{2})"}; // day of month with leading zeroes
1464     case "l":
1465         return {g:0,
1466             c:null,
1467             s:"(?:" + Date.dayNames.join("|") + ")"};
1468     case "S":
1469         return {g:0,
1470             c:null,
1471             s:"(?:st|nd|rd|th)"};
1472     case "w":
1473         return {g:0,
1474             c:null,
1475             s:"\\d"};
1476     case "z":
1477         return {g:0,
1478             c:null,
1479             s:"(?:\\d{1,3})"};
1480     case "W":
1481         return {g:0,
1482             c:null,
1483             s:"(?:\\d{2})"};
1484     case "F":
1485         return {g:1,
1486             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1487             s:"(" + Date.monthNames.join("|") + ")"};
1488     case "M":
1489         return {g:1,
1490             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1491             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1492     case "n":
1493         return {g:1,
1494             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1495             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1496     case "m":
1497         return {g:1,
1498             c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1499             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1500     case "t":
1501         return {g:0,
1502             c:null,
1503             s:"\\d{1,2}"};
1504     case "L":
1505         return {g:0,
1506             c:null,
1507             s:"(?:1|0)"};
1508     case "Y":
1509         return {g:1,
1510             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1511             s:"(\\d{4})"};
1512     case "y":
1513         return {g:1,
1514             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1515                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1516             s:"(\\d{1,2})"};
1517     case "a":
1518         return {g:1,
1519             c:"if (results[" + currentGroup + "] == 'am') {\n"
1520                 + "if (h == 12) { h = 0; }\n"
1521                 + "} else { if (h < 12) { h += 12; }}",
1522             s:"(am|pm)"};
1523     case "A":
1524         return {g:1,
1525             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1526                 + "if (h == 12) { h = 0; }\n"
1527                 + "} else { if (h < 12) { h += 12; }}",
1528             s:"(AM|PM)"};
1529     case "g":
1530     case "G":
1531         return {g:1,
1532             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1533             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1534     case "h":
1535     case "H":
1536         return {g:1,
1537             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1538             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1539     case "i":
1540         return {g:1,
1541             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1542             s:"(\\d{2})"};
1543     case "s":
1544         return {g:1,
1545             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1546             s:"(\\d{2})"};
1547     case "O":
1548         return {g:1,
1549             c:[
1550                 "o = results[", currentGroup, "];\n",
1551                 "var sn = o.substring(0,1);\n", // get + / - sign
1552                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1553                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1554                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1555                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1556             ].join(""),
1557             s:"([+\-]\\d{2,4})"};
1558     
1559     
1560     case "P":
1561         return {g:1,
1562                 c:[
1563                    "o = results[", currentGroup, "];\n",
1564                    "var sn = o.substring(0,1);\n",
1565                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1566                    "var mn = o.substring(4,6) % 60;\n",
1567                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1568                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1569             ].join(""),
1570             s:"([+\-]\\d{4})"};
1571     case "T":
1572         return {g:0,
1573             c:null,
1574             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1575     case "Z":
1576         return {g:1,
1577             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1578                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1579             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1580     default:
1581         return {g:0,
1582             c:null,
1583             s:String.escape(character)};
1584     }
1585 };
1586
1587 /**
1588  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1589  * @return {String} The abbreviated timezone name (e.g. 'CST')
1590  */
1591 Date.prototype.getTimezone = function() {
1592     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1593 };
1594
1595 /**
1596  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1597  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1598  */
1599 Date.prototype.getGMTOffset = function() {
1600     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1601         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1602         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1603 };
1604
1605 /**
1606  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1607  * @return {String} 2-characters representing hours and 2-characters representing minutes
1608  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1609  */
1610 Date.prototype.getGMTColonOffset = function() {
1611         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1612                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1613                 + ":"
1614                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1615 }
1616
1617 /**
1618  * Get the numeric day number of the year, adjusted for leap year.
1619  * @return {Number} 0 through 364 (365 in leap years)
1620  */
1621 Date.prototype.getDayOfYear = function() {
1622     var num = 0;
1623     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1624     for (var i = 0; i < this.getMonth(); ++i) {
1625         num += Date.daysInMonth[i];
1626     }
1627     return num + this.getDate() - 1;
1628 };
1629
1630 /**
1631  * Get the string representation of the numeric week number of the year
1632  * (equivalent to the format specifier 'W').
1633  * @return {String} '00' through '52'
1634  */
1635 Date.prototype.getWeekOfYear = function() {
1636     // Skip to Thursday of this week
1637     var now = this.getDayOfYear() + (4 - this.getDay());
1638     // Find the first Thursday of the year
1639     var jan1 = new Date(this.getFullYear(), 0, 1);
1640     var then = (7 - jan1.getDay() + 4);
1641     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1642 };
1643
1644 /**
1645  * Whether or not the current date is in a leap year.
1646  * @return {Boolean} True if the current date is in a leap year, else false
1647  */
1648 Date.prototype.isLeapYear = function() {
1649     var year = this.getFullYear();
1650     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1651 };
1652
1653 /**
1654  * Get the first day of the current month, adjusted for leap year.  The returned value
1655  * is the numeric day index within the week (0-6) which can be used in conjunction with
1656  * the {@link #monthNames} array to retrieve the textual day name.
1657  * Example:
1658  *<pre><code>
1659 var dt = new Date('1/10/2007');
1660 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1661 </code></pre>
1662  * @return {Number} The day number (0-6)
1663  */
1664 Date.prototype.getFirstDayOfMonth = function() {
1665     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1666     return (day < 0) ? (day + 7) : day;
1667 };
1668
1669 /**
1670  * Get the last day of the current month, adjusted for leap year.  The returned value
1671  * is the numeric day index within the week (0-6) which can be used in conjunction with
1672  * the {@link #monthNames} array to retrieve the textual day name.
1673  * Example:
1674  *<pre><code>
1675 var dt = new Date('1/10/2007');
1676 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1677 </code></pre>
1678  * @return {Number} The day number (0-6)
1679  */
1680 Date.prototype.getLastDayOfMonth = function() {
1681     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1682     return (day < 0) ? (day + 7) : day;
1683 };
1684
1685
1686 /**
1687  * Get the first date of this date's month
1688  * @return {Date}
1689  */
1690 Date.prototype.getFirstDateOfMonth = function() {
1691     return new Date(this.getFullYear(), this.getMonth(), 1);
1692 };
1693
1694 /**
1695  * Get the last date of this date's month
1696  * @return {Date}
1697  */
1698 Date.prototype.getLastDateOfMonth = function() {
1699     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1700 };
1701 /**
1702  * Get the number of days in the current month, adjusted for leap year.
1703  * @return {Number} The number of days in the month
1704  */
1705 Date.prototype.getDaysInMonth = function() {
1706     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1707     return Date.daysInMonth[this.getMonth()];
1708 };
1709
1710 /**
1711  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1712  * @return {String} 'st, 'nd', 'rd' or 'th'
1713  */
1714 Date.prototype.getSuffix = function() {
1715     switch (this.getDate()) {
1716         case 1:
1717         case 21:
1718         case 31:
1719             return "st";
1720         case 2:
1721         case 22:
1722             return "nd";
1723         case 3:
1724         case 23:
1725             return "rd";
1726         default:
1727             return "th";
1728     }
1729 };
1730
1731 // private
1732 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1733
1734 /**
1735  * An array of textual month names.
1736  * Override these values for international dates, for example...
1737  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1738  * @type Array
1739  * @static
1740  */
1741 Date.monthNames =
1742    ["January",
1743     "February",
1744     "March",
1745     "April",
1746     "May",
1747     "June",
1748     "July",
1749     "August",
1750     "September",
1751     "October",
1752     "November",
1753     "December"];
1754
1755 /**
1756  * An array of textual day names.
1757  * Override these values for international dates, for example...
1758  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1759  * @type Array
1760  * @static
1761  */
1762 Date.dayNames =
1763    ["Sunday",
1764     "Monday",
1765     "Tuesday",
1766     "Wednesday",
1767     "Thursday",
1768     "Friday",
1769     "Saturday"];
1770
1771 // private
1772 Date.y2kYear = 50;
1773 // private
1774 Date.monthNumbers = {
1775     Jan:0,
1776     Feb:1,
1777     Mar:2,
1778     Apr:3,
1779     May:4,
1780     Jun:5,
1781     Jul:6,
1782     Aug:7,
1783     Sep:8,
1784     Oct:9,
1785     Nov:10,
1786     Dec:11};
1787
1788 /**
1789  * Creates and returns a new Date instance with the exact same date value as the called instance.
1790  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1791  * variable will also be changed.  When the intention is to create a new variable that will not
1792  * modify the original instance, you should create a clone.
1793  *
1794  * Example of correctly cloning a date:
1795  * <pre><code>
1796 //wrong way:
1797 var orig = new Date('10/1/2006');
1798 var copy = orig;
1799 copy.setDate(5);
1800 document.write(orig);  //returns 'Thu Oct 05 2006'!
1801
1802 //correct way:
1803 var orig = new Date('10/1/2006');
1804 var copy = orig.clone();
1805 copy.setDate(5);
1806 document.write(orig);  //returns 'Thu Oct 01 2006'
1807 </code></pre>
1808  * @return {Date} The new Date instance
1809  */
1810 Date.prototype.clone = function() {
1811         return new Date(this.getTime());
1812 };
1813
1814 /**
1815  * Clears any time information from this date
1816  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1817  @return {Date} this or the clone
1818  */
1819 Date.prototype.clearTime = function(clone){
1820     if(clone){
1821         return this.clone().clearTime();
1822     }
1823     this.setHours(0);
1824     this.setMinutes(0);
1825     this.setSeconds(0);
1826     this.setMilliseconds(0);
1827     return this;
1828 };
1829
1830 // private
1831 // safari setMonth is broken -- check that this is only donw once...
1832 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1833     Date.brokenSetMonth = Date.prototype.setMonth;
1834         Date.prototype.setMonth = function(num){
1835                 if(num <= -1){
1836                         var n = Math.ceil(-num);
1837                         var back_year = Math.ceil(n/12);
1838                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1839                         this.setFullYear(this.getFullYear() - back_year);
1840                         return Date.brokenSetMonth.call(this, month);
1841                 } else {
1842                         return Date.brokenSetMonth.apply(this, arguments);
1843                 }
1844         };
1845 }
1846
1847 /** Date interval constant 
1848 * @static 
1849 * @type String */
1850 Date.MILLI = "ms";
1851 /** Date interval constant 
1852 * @static 
1853 * @type String */
1854 Date.SECOND = "s";
1855 /** Date interval constant 
1856 * @static 
1857 * @type String */
1858 Date.MINUTE = "mi";
1859 /** Date interval constant 
1860 * @static 
1861 * @type String */
1862 Date.HOUR = "h";
1863 /** Date interval constant 
1864 * @static 
1865 * @type String */
1866 Date.DAY = "d";
1867 /** Date interval constant 
1868 * @static 
1869 * @type String */
1870 Date.MONTH = "mo";
1871 /** Date interval constant 
1872 * @static 
1873 * @type String */
1874 Date.YEAR = "y";
1875
1876 /**
1877  * Provides a convenient method of performing basic date arithmetic.  This method
1878  * does not modify the Date instance being called - it creates and returns
1879  * a new Date instance containing the resulting date value.
1880  *
1881  * Examples:
1882  * <pre><code>
1883 //Basic usage:
1884 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1885 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1886
1887 //Negative values will subtract correctly:
1888 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1889 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1890
1891 //You can even chain several calls together in one line!
1892 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1893 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1894  </code></pre>
1895  *
1896  * @param {String} interval   A valid date interval enum value
1897  * @param {Number} value      The amount to add to the current date
1898  * @return {Date} The new Date instance
1899  */
1900 Date.prototype.add = function(interval, value){
1901   var d = this.clone();
1902   if (!interval || value === 0) { return d; }
1903   switch(interval.toLowerCase()){
1904     case Date.MILLI:
1905       d.setMilliseconds(this.getMilliseconds() + value);
1906       break;
1907     case Date.SECOND:
1908       d.setSeconds(this.getSeconds() + value);
1909       break;
1910     case Date.MINUTE:
1911       d.setMinutes(this.getMinutes() + value);
1912       break;
1913     case Date.HOUR:
1914       d.setHours(this.getHours() + value);
1915       break;
1916     case Date.DAY:
1917       d.setDate(this.getDate() + value);
1918       break;
1919     case Date.MONTH:
1920       var day = this.getDate();
1921       if(day > 28){
1922           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1923       }
1924       d.setDate(day);
1925       d.setMonth(this.getMonth() + value);
1926       break;
1927     case Date.YEAR:
1928       d.setFullYear(this.getFullYear() + value);
1929       break;
1930   }
1931   return d;
1932 };
1933 /**
1934  * @class Roo.lib.Dom
1935  * @licence LGPL
1936  * @static
1937  * 
1938  * Dom utils (from YIU afaik)
1939  *
1940  * 
1941  **/
1942 Roo.lib.Dom = {
1943     /**
1944      * Get the view width
1945      * @param {Boolean} full True will get the full document, otherwise it's the view width
1946      * @return {Number} The width
1947      */
1948      
1949     getViewWidth : function(full) {
1950         return full ? this.getDocumentWidth() : this.getViewportWidth();
1951     },
1952     /**
1953      * Get the view height
1954      * @param {Boolean} full True will get the full document, otherwise it's the view height
1955      * @return {Number} The height
1956      */
1957     getViewHeight : function(full) {
1958         return full ? this.getDocumentHeight() : this.getViewportHeight();
1959     },
1960     /**
1961      * Get the Full Document height 
1962      * @return {Number} The height
1963      */
1964     getDocumentHeight: function() {
1965         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1966         return Math.max(scrollHeight, this.getViewportHeight());
1967     },
1968     /**
1969      * Get the Full Document width
1970      * @return {Number} The width
1971      */
1972     getDocumentWidth: function() {
1973         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1974         return Math.max(scrollWidth, this.getViewportWidth());
1975     },
1976     /**
1977      * Get the Window Viewport height
1978      * @return {Number} The height
1979      */
1980     getViewportHeight: function() {
1981         var height = self.innerHeight;
1982         var mode = document.compatMode;
1983
1984         if ((mode || Roo.isIE) && !Roo.isOpera) {
1985             height = (mode == "CSS1Compat") ?
1986                      document.documentElement.clientHeight :
1987                      document.body.clientHeight;
1988         }
1989
1990         return height;
1991     },
1992     /**
1993      * Get the Window Viewport width
1994      * @return {Number} The width
1995      */
1996     getViewportWidth: function() {
1997         var width = self.innerWidth;
1998         var mode = document.compatMode;
1999
2000         if (mode || Roo.isIE) {
2001             width = (mode == "CSS1Compat") ?
2002                     document.documentElement.clientWidth :
2003                     document.body.clientWidth;
2004         }
2005         return width;
2006     },
2007
2008     isAncestor : function(p, c) {
2009         p = Roo.getDom(p);
2010         c = Roo.getDom(c);
2011         if (!p || !c) {
2012             return false;
2013         }
2014
2015         if (p.contains && !Roo.isSafari) {
2016             return p.contains(c);
2017         } else if (p.compareDocumentPosition) {
2018             return !!(p.compareDocumentPosition(c) & 16);
2019         } else {
2020             var parent = c.parentNode;
2021             while (parent) {
2022                 if (parent == p) {
2023                     return true;
2024                 }
2025                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
2026                     return false;
2027                 }
2028                 parent = parent.parentNode;
2029             }
2030             return false;
2031         }
2032     },
2033
2034     getRegion : function(el) {
2035         return Roo.lib.Region.getRegion(el);
2036     },
2037
2038     getY : function(el) {
2039         return this.getXY(el)[1];
2040     },
2041
2042     getX : function(el) {
2043         return this.getXY(el)[0];
2044     },
2045
2046     getXY : function(el) {
2047         var p, pe, b, scroll, bd = document.body;
2048         el = Roo.getDom(el);
2049         var fly = Roo.lib.AnimBase.fly;
2050         if (el.getBoundingClientRect) {
2051             b = el.getBoundingClientRect();
2052             scroll = fly(document).getScroll();
2053             return [b.left + scroll.left, b.top + scroll.top];
2054         }
2055         var x = 0, y = 0;
2056
2057         p = el;
2058
2059         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2060
2061         while (p) {
2062
2063             x += p.offsetLeft;
2064             y += p.offsetTop;
2065
2066             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2067                 hasAbsolute = true;
2068             }
2069
2070             if (Roo.isGecko) {
2071                 pe = fly(p);
2072
2073                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2074                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2075
2076
2077                 x += bl;
2078                 y += bt;
2079
2080
2081                 if (p != el && pe.getStyle('overflow') != 'visible') {
2082                     x += bl;
2083                     y += bt;
2084                 }
2085             }
2086             p = p.offsetParent;
2087         }
2088
2089         if (Roo.isSafari && hasAbsolute) {
2090             x -= bd.offsetLeft;
2091             y -= bd.offsetTop;
2092         }
2093
2094         if (Roo.isGecko && !hasAbsolute) {
2095             var dbd = fly(bd);
2096             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2097             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2098         }
2099
2100         p = el.parentNode;
2101         while (p && p != bd) {
2102             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2103                 x -= p.scrollLeft;
2104                 y -= p.scrollTop;
2105             }
2106             p = p.parentNode;
2107         }
2108         return [x, y];
2109     },
2110  
2111   
2112
2113
2114     setXY : function(el, xy) {
2115         el = Roo.fly(el, '_setXY');
2116         el.position();
2117         var pts = el.translatePoints(xy);
2118         if (xy[0] !== false) {
2119             el.dom.style.left = pts.left + "px";
2120         }
2121         if (xy[1] !== false) {
2122             el.dom.style.top = pts.top + "px";
2123         }
2124     },
2125
2126     setX : function(el, x) {
2127         this.setXY(el, [x, false]);
2128     },
2129
2130     setY : function(el, y) {
2131         this.setXY(el, [false, y]);
2132     }
2133 };
2134 /*
2135  * Portions of this file are based on pieces of Yahoo User Interface Library
2136  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2137  * YUI licensed under the BSD License:
2138  * http://developer.yahoo.net/yui/license.txt
2139  * <script type="text/javascript">
2140  *
2141  */
2142
2143 Roo.lib.Event = function() {
2144     var loadComplete = false;
2145     var listeners = [];
2146     var unloadListeners = [];
2147     var retryCount = 0;
2148     var onAvailStack = [];
2149     var counter = 0;
2150     var lastError = null;
2151
2152     return {
2153         POLL_RETRYS: 200,
2154         POLL_INTERVAL: 20,
2155         EL: 0,
2156         TYPE: 1,
2157         FN: 2,
2158         WFN: 3,
2159         OBJ: 3,
2160         ADJ_SCOPE: 4,
2161         _interval: null,
2162
2163         startInterval: function() {
2164             if (!this._interval) {
2165                 var self = this;
2166                 var callback = function() {
2167                     self._tryPreloadAttach();
2168                 };
2169                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2170
2171             }
2172         },
2173
2174         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2175             onAvailStack.push({ id:         p_id,
2176                 fn:         p_fn,
2177                 obj:        p_obj,
2178                 override:   p_override,
2179                 checkReady: false    });
2180
2181             retryCount = this.POLL_RETRYS;
2182             this.startInterval();
2183         },
2184
2185
2186         addListener: function(el, eventName, fn) {
2187             el = Roo.getDom(el);
2188             if (!el || !fn) {
2189                 return false;
2190             }
2191
2192             if ("unload" == eventName) {
2193                 unloadListeners[unloadListeners.length] =
2194                 [el, eventName, fn];
2195                 return true;
2196             }
2197
2198             var wrappedFn = function(e) {
2199                 return fn(Roo.lib.Event.getEvent(e));
2200             };
2201
2202             var li = [el, eventName, fn, wrappedFn];
2203
2204             var index = listeners.length;
2205             listeners[index] = li;
2206
2207             this.doAdd(el, eventName, wrappedFn, false);
2208             return true;
2209
2210         },
2211
2212
2213         removeListener: function(el, eventName, fn) {
2214             var i, len;
2215
2216             el = Roo.getDom(el);
2217
2218             if(!fn) {
2219                 return this.purgeElement(el, false, eventName);
2220             }
2221
2222
2223             if ("unload" == eventName) {
2224
2225                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2226                     var li = unloadListeners[i];
2227                     if (li &&
2228                         li[0] == el &&
2229                         li[1] == eventName &&
2230                         li[2] == fn) {
2231                         unloadListeners.splice(i, 1);
2232                         return true;
2233                     }
2234                 }
2235
2236                 return false;
2237             }
2238
2239             var cacheItem = null;
2240
2241
2242             var index = arguments[3];
2243
2244             if ("undefined" == typeof index) {
2245                 index = this._getCacheIndex(el, eventName, fn);
2246             }
2247
2248             if (index >= 0) {
2249                 cacheItem = listeners[index];
2250             }
2251
2252             if (!el || !cacheItem) {
2253                 return false;
2254             }
2255
2256             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2257
2258             delete listeners[index][this.WFN];
2259             delete listeners[index][this.FN];
2260             listeners.splice(index, 1);
2261
2262             return true;
2263
2264         },
2265
2266
2267         getTarget: function(ev, resolveTextNode) {
2268             ev = ev.browserEvent || ev;
2269             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2270             var t = ev.target || ev.srcElement;
2271             return this.resolveTextNode(t);
2272         },
2273
2274
2275         resolveTextNode: function(node) {
2276             if (Roo.isSafari && node && 3 == node.nodeType) {
2277                 return node.parentNode;
2278             } else {
2279                 return node;
2280             }
2281         },
2282
2283
2284         getPageX: function(ev) {
2285             ev = ev.browserEvent || ev;
2286             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2287             var x = ev.pageX;
2288             if (!x && 0 !== x) {
2289                 x = ev.clientX || 0;
2290
2291                 if (Roo.isIE) {
2292                     x += this.getScroll()[1];
2293                 }
2294             }
2295
2296             return x;
2297         },
2298
2299
2300         getPageY: function(ev) {
2301             ev = ev.browserEvent || ev;
2302             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2303             var y = ev.pageY;
2304             if (!y && 0 !== y) {
2305                 y = ev.clientY || 0;
2306
2307                 if (Roo.isIE) {
2308                     y += this.getScroll()[0];
2309                 }
2310             }
2311
2312
2313             return y;
2314         },
2315
2316
2317         getXY: function(ev) {
2318             ev = ev.browserEvent || ev;
2319             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2320             return [this.getPageX(ev), this.getPageY(ev)];
2321         },
2322
2323
2324         getRelatedTarget: function(ev) {
2325             ev = ev.browserEvent || ev;
2326             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2327             var t = ev.relatedTarget;
2328             if (!t) {
2329                 if (ev.type == "mouseout") {
2330                     t = ev.toElement;
2331                 } else if (ev.type == "mouseover") {
2332                     t = ev.fromElement;
2333                 }
2334             }
2335
2336             return this.resolveTextNode(t);
2337         },
2338
2339
2340         getTime: function(ev) {
2341             ev = ev.browserEvent || ev;
2342             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2343             if (!ev.time) {
2344                 var t = new Date().getTime();
2345                 try {
2346                     ev.time = t;
2347                 } catch(ex) {
2348                     this.lastError = ex;
2349                     return t;
2350                 }
2351             }
2352
2353             return ev.time;
2354         },
2355
2356
2357         stopEvent: function(ev) {
2358             this.stopPropagation(ev);
2359             this.preventDefault(ev);
2360         },
2361
2362
2363         stopPropagation: function(ev) {
2364             ev = ev.browserEvent || ev;
2365             if (ev.stopPropagation) {
2366                 ev.stopPropagation();
2367             } else {
2368                 ev.cancelBubble = true;
2369             }
2370         },
2371
2372
2373         preventDefault: function(ev) {
2374             ev = ev.browserEvent || ev;
2375             if(ev.preventDefault) {
2376                 ev.preventDefault();
2377             } else {
2378                 ev.returnValue = false;
2379             }
2380         },
2381
2382
2383         getEvent: function(e) {
2384             var ev = e || window.event;
2385             if (!ev) {
2386                 var c = this.getEvent.caller;
2387                 while (c) {
2388                     ev = c.arguments[0];
2389                     if (ev && Event == ev.constructor) {
2390                         break;
2391                     }
2392                     c = c.caller;
2393                 }
2394             }
2395             return ev;
2396         },
2397
2398
2399         getCharCode: function(ev) {
2400             ev = ev.browserEvent || ev;
2401             return ev.charCode || ev.keyCode || 0;
2402         },
2403
2404
2405         _getCacheIndex: function(el, eventName, fn) {
2406             for (var i = 0,len = listeners.length; i < len; ++i) {
2407                 var li = listeners[i];
2408                 if (li &&
2409                     li[this.FN] == fn &&
2410                     li[this.EL] == el &&
2411                     li[this.TYPE] == eventName) {
2412                     return i;
2413                 }
2414             }
2415
2416             return -1;
2417         },
2418
2419
2420         elCache: {},
2421
2422
2423         getEl: function(id) {
2424             return document.getElementById(id);
2425         },
2426
2427
2428         clearCache: function() {
2429         },
2430
2431
2432         _load: function(e) {
2433             loadComplete = true;
2434             var EU = Roo.lib.Event;
2435
2436
2437             if (Roo.isIE) {
2438                 EU.doRemove(window, "load", EU._load);
2439             }
2440         },
2441
2442
2443         _tryPreloadAttach: function() {
2444
2445             if (this.locked) {
2446                 return false;
2447             }
2448
2449             this.locked = true;
2450
2451
2452             var tryAgain = !loadComplete;
2453             if (!tryAgain) {
2454                 tryAgain = (retryCount > 0);
2455             }
2456
2457
2458             var notAvail = [];
2459             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2460                 var item = onAvailStack[i];
2461                 if (item) {
2462                     var el = this.getEl(item.id);
2463
2464                     if (el) {
2465                         if (!item.checkReady ||
2466                             loadComplete ||
2467                             el.nextSibling ||
2468                             (document && document.body)) {
2469
2470                             var scope = el;
2471                             if (item.override) {
2472                                 if (item.override === true) {
2473                                     scope = item.obj;
2474                                 } else {
2475                                     scope = item.override;
2476                                 }
2477                             }
2478                             item.fn.call(scope, item.obj);
2479                             onAvailStack[i] = null;
2480                         }
2481                     } else {
2482                         notAvail.push(item);
2483                     }
2484                 }
2485             }
2486
2487             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2488
2489             if (tryAgain) {
2490
2491                 this.startInterval();
2492             } else {
2493                 clearInterval(this._interval);
2494                 this._interval = null;
2495             }
2496
2497             this.locked = false;
2498
2499             return true;
2500
2501         },
2502
2503
2504         purgeElement: function(el, recurse, eventName) {
2505             var elListeners = this.getListeners(el, eventName);
2506             if (elListeners) {
2507                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2508                     var l = elListeners[i];
2509                     this.removeListener(el, l.type, l.fn);
2510                 }
2511             }
2512
2513             if (recurse && el && el.childNodes) {
2514                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2515                     this.purgeElement(el.childNodes[i], recurse, eventName);
2516                 }
2517             }
2518         },
2519
2520
2521         getListeners: function(el, eventName) {
2522             var results = [], searchLists;
2523             if (!eventName) {
2524                 searchLists = [listeners, unloadListeners];
2525             } else if (eventName == "unload") {
2526                 searchLists = [unloadListeners];
2527             } else {
2528                 searchLists = [listeners];
2529             }
2530
2531             for (var j = 0; j < searchLists.length; ++j) {
2532                 var searchList = searchLists[j];
2533                 if (searchList && searchList.length > 0) {
2534                     for (var i = 0,len = searchList.length; i < len; ++i) {
2535                         var l = searchList[i];
2536                         if (l && l[this.EL] === el &&
2537                             (!eventName || eventName === l[this.TYPE])) {
2538                             results.push({
2539                                 type:   l[this.TYPE],
2540                                 fn:     l[this.FN],
2541                                 obj:    l[this.OBJ],
2542                                 adjust: l[this.ADJ_SCOPE],
2543                                 index:  i
2544                             });
2545                         }
2546                     }
2547                 }
2548             }
2549
2550             return (results.length) ? results : null;
2551         },
2552
2553
2554         _unload: function(e) {
2555
2556             var EU = Roo.lib.Event, i, j, l, len, index;
2557
2558             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2559                 l = unloadListeners[i];
2560                 if (l) {
2561                     var scope = window;
2562                     if (l[EU.ADJ_SCOPE]) {
2563                         if (l[EU.ADJ_SCOPE] === true) {
2564                             scope = l[EU.OBJ];
2565                         } else {
2566                             scope = l[EU.ADJ_SCOPE];
2567                         }
2568                     }
2569                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2570                     unloadListeners[i] = null;
2571                     l = null;
2572                     scope = null;
2573                 }
2574             }
2575
2576             unloadListeners = null;
2577
2578             if (listeners && listeners.length > 0) {
2579                 j = listeners.length;
2580                 while (j) {
2581                     index = j - 1;
2582                     l = listeners[index];
2583                     if (l) {
2584                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2585                                 l[EU.FN], index);
2586                     }
2587                     j = j - 1;
2588                 }
2589                 l = null;
2590
2591                 EU.clearCache();
2592             }
2593
2594             EU.doRemove(window, "unload", EU._unload);
2595
2596         },
2597
2598
2599         getScroll: function() {
2600             var dd = document.documentElement, db = document.body;
2601             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2602                 return [dd.scrollTop, dd.scrollLeft];
2603             } else if (db) {
2604                 return [db.scrollTop, db.scrollLeft];
2605             } else {
2606                 return [0, 0];
2607             }
2608         },
2609
2610
2611         doAdd: function () {
2612             if (window.addEventListener) {
2613                 return function(el, eventName, fn, capture) {
2614                     el.addEventListener(eventName, fn, (capture));
2615                 };
2616             } else if (window.attachEvent) {
2617                 return function(el, eventName, fn, capture) {
2618                     el.attachEvent("on" + eventName, fn);
2619                 };
2620             } else {
2621                 return function() {
2622                 };
2623             }
2624         }(),
2625
2626
2627         doRemove: function() {
2628             if (window.removeEventListener) {
2629                 return function (el, eventName, fn, capture) {
2630                     el.removeEventListener(eventName, fn, (capture));
2631                 };
2632             } else if (window.detachEvent) {
2633                 return function (el, eventName, fn) {
2634                     el.detachEvent("on" + eventName, fn);
2635                 };
2636             } else {
2637                 return function() {
2638                 };
2639             }
2640         }()
2641     };
2642     
2643 }();
2644 (function() {     
2645    
2646     var E = Roo.lib.Event;
2647     E.on = E.addListener;
2648     E.un = E.removeListener;
2649
2650     if (document && document.body) {
2651         E._load();
2652     } else {
2653         E.doAdd(window, "load", E._load);
2654     }
2655     E.doAdd(window, "unload", E._unload);
2656     E._tryPreloadAttach();
2657 })();
2658
2659  
2660
2661 (function() {
2662     /**
2663      * @class Roo.lib.Ajax
2664      *
2665      * provide a simple Ajax request utility functions
2666      * 
2667      * Portions of this file are based on pieces of Yahoo User Interface Library
2668     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2669     * YUI licensed under the BSD License:
2670     * http://developer.yahoo.net/yui/license.txt
2671     * <script type="text/javascript">
2672     *
2673      *
2674      */
2675     Roo.lib.Ajax = {
2676         /**
2677          * @static 
2678          */
2679         request : function(method, uri, cb, data, options) {
2680             if(options){
2681                 var hs = options.headers;
2682                 if(hs){
2683                     for(var h in hs){
2684                         if(hs.hasOwnProperty(h)){
2685                             this.initHeader(h, hs[h], false);
2686                         }
2687                     }
2688                 }
2689                 if(options.xmlData){
2690                     this.initHeader('Content-Type', 'text/xml', false);
2691                     method = 'POST';
2692                     data = options.xmlData;
2693                 }
2694             }
2695
2696             return this.asyncRequest(method, uri, cb, data);
2697         },
2698         /**
2699          * serialize a form
2700          *
2701          * @static
2702          * @param {DomForm} form element
2703          * @return {String} urlencode form output.
2704          */
2705         serializeForm : function(form) {
2706             if(typeof form == 'string') {
2707                 form = (document.getElementById(form) || document.forms[form]);
2708             }
2709
2710             var el, name, val, disabled, data = '', hasSubmit = false;
2711             for (var i = 0; i < form.elements.length; i++) {
2712                 el = form.elements[i];
2713                 disabled = form.elements[i].disabled;
2714                 name = form.elements[i].name;
2715                 val = form.elements[i].value;
2716
2717                 if (!disabled && name){
2718                     switch (el.type)
2719                             {
2720                         case 'select-one':
2721                         case 'select-multiple':
2722                             for (var j = 0; j < el.options.length; j++) {
2723                                 if (el.options[j].selected) {
2724                                     if (Roo.isIE) {
2725                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2726                                     }
2727                                     else {
2728                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2729                                     }
2730                                 }
2731                             }
2732                             break;
2733                         case 'radio':
2734                         case 'checkbox':
2735                             if (el.checked) {
2736                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2737                             }
2738                             break;
2739                         case 'file':
2740
2741                         case undefined:
2742
2743                         case 'reset':
2744
2745                         case 'button':
2746
2747                             break;
2748                         case 'submit':
2749                             if(hasSubmit == false) {
2750                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2751                                 hasSubmit = true;
2752                             }
2753                             break;
2754                         default:
2755                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2756                             break;
2757                     }
2758                 }
2759             }
2760             data = data.substr(0, data.length - 1);
2761             return data;
2762         },
2763
2764         headers:{},
2765
2766         hasHeaders:false,
2767
2768         useDefaultHeader:true,
2769
2770         defaultPostHeader:'application/x-www-form-urlencoded',
2771
2772         useDefaultXhrHeader:true,
2773
2774         defaultXhrHeader:'XMLHttpRequest',
2775
2776         hasDefaultHeaders:true,
2777
2778         defaultHeaders:{},
2779
2780         poll:{},
2781
2782         timeout:{},
2783
2784         pollInterval:50,
2785
2786         transactionId:0,
2787
2788         setProgId:function(id)
2789         {
2790             this.activeX.unshift(id);
2791         },
2792
2793         setDefaultPostHeader:function(b)
2794         {
2795             this.useDefaultHeader = b;
2796         },
2797
2798         setDefaultXhrHeader:function(b)
2799         {
2800             this.useDefaultXhrHeader = b;
2801         },
2802
2803         setPollingInterval:function(i)
2804         {
2805             if (typeof i == 'number' && isFinite(i)) {
2806                 this.pollInterval = i;
2807             }
2808         },
2809
2810         createXhrObject:function(transactionId)
2811         {
2812             var obj,http;
2813             try
2814             {
2815
2816                 http = new XMLHttpRequest();
2817
2818                 obj = { conn:http, tId:transactionId };
2819             }
2820             catch(e)
2821             {
2822                 for (var i = 0; i < this.activeX.length; ++i) {
2823                     try
2824                     {
2825
2826                         http = new ActiveXObject(this.activeX[i]);
2827
2828                         obj = { conn:http, tId:transactionId };
2829                         break;
2830                     }
2831                     catch(e) {
2832                     }
2833                 }
2834             }
2835             finally
2836             {
2837                 return obj;
2838             }
2839         },
2840
2841         getConnectionObject:function()
2842         {
2843             var o;
2844             var tId = this.transactionId;
2845
2846             try
2847             {
2848                 o = this.createXhrObject(tId);
2849                 if (o) {
2850                     this.transactionId++;
2851                 }
2852             }
2853             catch(e) {
2854             }
2855             finally
2856             {
2857                 return o;
2858             }
2859         },
2860
2861         asyncRequest:function(method, uri, callback, postData)
2862         {
2863             var o = this.getConnectionObject();
2864
2865             if (!o) {
2866                 return null;
2867             }
2868             else {
2869                 o.conn.open(method, uri, true);
2870
2871                 if (this.useDefaultXhrHeader) {
2872                     if (!this.defaultHeaders['X-Requested-With']) {
2873                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2874                     }
2875                 }
2876
2877                 if(postData && this.useDefaultHeader){
2878                     this.initHeader('Content-Type', this.defaultPostHeader);
2879                 }
2880
2881                  if (this.hasDefaultHeaders || this.hasHeaders) {
2882                     this.setHeader(o);
2883                 }
2884
2885                 this.handleReadyState(o, callback);
2886                 o.conn.send(postData || null);
2887
2888                 return o;
2889             }
2890         },
2891
2892         handleReadyState:function(o, callback)
2893         {
2894             var oConn = this;
2895
2896             if (callback && callback.timeout) {
2897                 
2898                 this.timeout[o.tId] = window.setTimeout(function() {
2899                     oConn.abort(o, callback, true);
2900                 }, callback.timeout);
2901             }
2902
2903             this.poll[o.tId] = window.setInterval(
2904                     function() {
2905                         if (o.conn && o.conn.readyState == 4) {
2906                             window.clearInterval(oConn.poll[o.tId]);
2907                             delete oConn.poll[o.tId];
2908
2909                             if(callback && callback.timeout) {
2910                                 window.clearTimeout(oConn.timeout[o.tId]);
2911                                 delete oConn.timeout[o.tId];
2912                             }
2913
2914                             oConn.handleTransactionResponse(o, callback);
2915                         }
2916                     }
2917                     , this.pollInterval);
2918         },
2919
2920         handleTransactionResponse:function(o, callback, isAbort)
2921         {
2922
2923             if (!callback) {
2924                 this.releaseObject(o);
2925                 return;
2926             }
2927
2928             var httpStatus, responseObject;
2929
2930             try
2931             {
2932                 if (o.conn.status !== undefined && o.conn.status != 0) {
2933                     httpStatus = o.conn.status;
2934                 }
2935                 else {
2936                     httpStatus = 13030;
2937                 }
2938             }
2939             catch(e) {
2940
2941
2942                 httpStatus = 13030;
2943             }
2944
2945             if (httpStatus >= 200 && httpStatus < 300) {
2946                 responseObject = this.createResponseObject(o, callback.argument);
2947                 if (callback.success) {
2948                     if (!callback.scope) {
2949                         callback.success(responseObject);
2950                     }
2951                     else {
2952
2953
2954                         callback.success.apply(callback.scope, [responseObject]);
2955                     }
2956                 }
2957             }
2958             else {
2959                 switch (httpStatus) {
2960
2961                     case 12002:
2962                     case 12029:
2963                     case 12030:
2964                     case 12031:
2965                     case 12152:
2966                     case 13030:
2967                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2968                         if (callback.failure) {
2969                             if (!callback.scope) {
2970                                 callback.failure(responseObject);
2971                             }
2972                             else {
2973                                 callback.failure.apply(callback.scope, [responseObject]);
2974                             }
2975                         }
2976                         break;
2977                     default:
2978                         responseObject = this.createResponseObject(o, callback.argument);
2979                         if (callback.failure) {
2980                             if (!callback.scope) {
2981                                 callback.failure(responseObject);
2982                             }
2983                             else {
2984                                 callback.failure.apply(callback.scope, [responseObject]);
2985                             }
2986                         }
2987                 }
2988             }
2989
2990             this.releaseObject(o);
2991             responseObject = null;
2992         },
2993
2994         createResponseObject:function(o, callbackArg)
2995         {
2996             var obj = {};
2997             var headerObj = {};
2998
2999             try
3000             {
3001                 var headerStr = o.conn.getAllResponseHeaders();
3002                 var header = headerStr.split('\n');
3003                 for (var i = 0; i < header.length; i++) {
3004                     var delimitPos = header[i].indexOf(':');
3005                     if (delimitPos != -1) {
3006                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
3007                     }
3008                 }
3009             }
3010             catch(e) {
3011             }
3012
3013             obj.tId = o.tId;
3014             obj.status = o.conn.status;
3015             obj.statusText = o.conn.statusText;
3016             obj.getResponseHeader = headerObj;
3017             obj.getAllResponseHeaders = headerStr;
3018             obj.responseText = o.conn.responseText;
3019             obj.responseXML = o.conn.responseXML;
3020
3021             if (typeof callbackArg !== undefined) {
3022                 obj.argument = callbackArg;
3023             }
3024
3025             return obj;
3026         },
3027
3028         createExceptionObject:function(tId, callbackArg, isAbort)
3029         {
3030             var COMM_CODE = 0;
3031             var COMM_ERROR = 'communication failure';
3032             var ABORT_CODE = -1;
3033             var ABORT_ERROR = 'transaction aborted';
3034
3035             var obj = {};
3036
3037             obj.tId = tId;
3038             if (isAbort) {
3039                 obj.status = ABORT_CODE;
3040                 obj.statusText = ABORT_ERROR;
3041             }
3042             else {
3043                 obj.status = COMM_CODE;
3044                 obj.statusText = COMM_ERROR;
3045             }
3046
3047             if (callbackArg) {
3048                 obj.argument = callbackArg;
3049             }
3050
3051             return obj;
3052         },
3053
3054         initHeader:function(label, value, isDefault)
3055         {
3056             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3057
3058             if (headerObj[label] === undefined) {
3059                 headerObj[label] = value;
3060             }
3061             else {
3062
3063
3064                 headerObj[label] = value + "," + headerObj[label];
3065             }
3066
3067             if (isDefault) {
3068                 this.hasDefaultHeaders = true;
3069             }
3070             else {
3071                 this.hasHeaders = true;
3072             }
3073         },
3074
3075
3076         setHeader:function(o)
3077         {
3078             if (this.hasDefaultHeaders) {
3079                 for (var prop in this.defaultHeaders) {
3080                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3081                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3082                     }
3083                 }
3084             }
3085
3086             if (this.hasHeaders) {
3087                 for (var prop in this.headers) {
3088                     if (this.headers.hasOwnProperty(prop)) {
3089                         o.conn.setRequestHeader(prop, this.headers[prop]);
3090                     }
3091                 }
3092                 this.headers = {};
3093                 this.hasHeaders = false;
3094             }
3095         },
3096
3097         resetDefaultHeaders:function() {
3098             delete this.defaultHeaders;
3099             this.defaultHeaders = {};
3100             this.hasDefaultHeaders = false;
3101         },
3102
3103         abort:function(o, callback, isTimeout)
3104         {
3105             if(this.isCallInProgress(o)) {
3106                 o.conn.abort();
3107                 window.clearInterval(this.poll[o.tId]);
3108                 delete this.poll[o.tId];
3109                 if (isTimeout) {
3110                     delete this.timeout[o.tId];
3111                 }
3112
3113                 this.handleTransactionResponse(o, callback, true);
3114
3115                 return true;
3116             }
3117             else {
3118                 return false;
3119             }
3120         },
3121
3122
3123         isCallInProgress:function(o)
3124         {
3125             if (o && o.conn) {
3126                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3127             }
3128             else {
3129
3130                 return false;
3131             }
3132         },
3133
3134
3135         releaseObject:function(o)
3136         {
3137
3138             o.conn = null;
3139
3140             o = null;
3141         },
3142
3143         activeX:[
3144         'MSXML2.XMLHTTP.3.0',
3145         'MSXML2.XMLHTTP',
3146         'Microsoft.XMLHTTP'
3147         ]
3148
3149
3150     };
3151 })();/*
3152  * Portions of this file are based on pieces of Yahoo User Interface Library
3153  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3154  * YUI licensed under the BSD License:
3155  * http://developer.yahoo.net/yui/license.txt
3156  * <script type="text/javascript">
3157  *
3158  */
3159
3160 Roo.lib.Region = function(t, r, b, l) {
3161     this.top = t;
3162     this[1] = t;
3163     this.right = r;
3164     this.bottom = b;
3165     this.left = l;
3166     this[0] = l;
3167 };
3168
3169
3170 Roo.lib.Region.prototype = {
3171     contains : function(region) {
3172         return ( region.left >= this.left &&
3173                  region.right <= this.right &&
3174                  region.top >= this.top &&
3175                  region.bottom <= this.bottom    );
3176
3177     },
3178
3179     getArea : function() {
3180         return ( (this.bottom - this.top) * (this.right - this.left) );
3181     },
3182
3183     intersect : function(region) {
3184         var t = Math.max(this.top, region.top);
3185         var r = Math.min(this.right, region.right);
3186         var b = Math.min(this.bottom, region.bottom);
3187         var l = Math.max(this.left, region.left);
3188
3189         if (b >= t && r >= l) {
3190             return new Roo.lib.Region(t, r, b, l);
3191         } else {
3192             return null;
3193         }
3194     },
3195     union : function(region) {
3196         var t = Math.min(this.top, region.top);
3197         var r = Math.max(this.right, region.right);
3198         var b = Math.max(this.bottom, region.bottom);
3199         var l = Math.min(this.left, region.left);
3200
3201         return new Roo.lib.Region(t, r, b, l);
3202     },
3203
3204     adjust : function(t, l, b, r) {
3205         this.top += t;
3206         this.left += l;
3207         this.right += r;
3208         this.bottom += b;
3209         return this;
3210     }
3211 };
3212
3213 Roo.lib.Region.getRegion = function(el) {
3214     var p = Roo.lib.Dom.getXY(el);
3215
3216     var t = p[1];
3217     var r = p[0] + el.offsetWidth;
3218     var b = p[1] + el.offsetHeight;
3219     var l = p[0];
3220
3221     return new Roo.lib.Region(t, r, b, l);
3222 };
3223 /*
3224  * Portions of this file are based on pieces of Yahoo User Interface Library
3225  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3226  * YUI licensed under the BSD License:
3227  * http://developer.yahoo.net/yui/license.txt
3228  * <script type="text/javascript">
3229  *
3230  */
3231 //@@dep Roo.lib.Region
3232
3233
3234 Roo.lib.Point = function(x, y) {
3235     if (x instanceof Array) {
3236         y = x[1];
3237         x = x[0];
3238     }
3239     this.x = this.right = this.left = this[0] = x;
3240     this.y = this.top = this.bottom = this[1] = y;
3241 };
3242
3243 Roo.lib.Point.prototype = new Roo.lib.Region();
3244 /*
3245  * Portions of this file are based on pieces of Yahoo User Interface Library
3246  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3247  * YUI licensed under the BSD License:
3248  * http://developer.yahoo.net/yui/license.txt
3249  * <script type="text/javascript">
3250  *
3251  */
3252  
3253 (function() {   
3254
3255     Roo.lib.Anim = {
3256         scroll : function(el, args, duration, easing, cb, scope) {
3257             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3258         },
3259
3260         motion : function(el, args, duration, easing, cb, scope) {
3261             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3262         },
3263
3264         color : function(el, args, duration, easing, cb, scope) {
3265             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3266         },
3267
3268         run : function(el, args, duration, easing, cb, scope, type) {
3269             type = type || Roo.lib.AnimBase;
3270             if (typeof easing == "string") {
3271                 easing = Roo.lib.Easing[easing];
3272             }
3273             var anim = new type(el, args, duration, easing);
3274             anim.animateX(function() {
3275                 Roo.callback(cb, scope);
3276             });
3277             return anim;
3278         }
3279     };
3280 })();/*
3281  * Portions of this file are based on pieces of Yahoo User Interface Library
3282  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3283  * YUI licensed under the BSD License:
3284  * http://developer.yahoo.net/yui/license.txt
3285  * <script type="text/javascript">
3286  *
3287  */
3288
3289 (function() {    
3290     var libFlyweight;
3291     
3292     function fly(el) {
3293         if (!libFlyweight) {
3294             libFlyweight = new Roo.Element.Flyweight();
3295         }
3296         libFlyweight.dom = el;
3297         return libFlyweight;
3298     }
3299
3300     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3301     
3302    
3303     
3304     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3305         if (el) {
3306             this.init(el, attributes, duration, method);
3307         }
3308     };
3309
3310     Roo.lib.AnimBase.fly = fly;
3311     
3312     
3313     
3314     Roo.lib.AnimBase.prototype = {
3315
3316         toString: function() {
3317             var el = this.getEl();
3318             var id = el.id || el.tagName;
3319             return ("Anim " + id);
3320         },
3321
3322         patterns: {
3323             noNegatives:        /width|height|opacity|padding/i,
3324             offsetAttribute:  /^((width|height)|(top|left))$/,
3325             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3326             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3327         },
3328
3329
3330         doMethod: function(attr, start, end) {
3331             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3332         },
3333
3334
3335         setAttribute: function(attr, val, unit) {
3336             if (this.patterns.noNegatives.test(attr)) {
3337                 val = (val > 0) ? val : 0;
3338             }
3339
3340             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3341         },
3342
3343
3344         getAttribute: function(attr) {
3345             var el = this.getEl();
3346             var val = fly(el).getStyle(attr);
3347
3348             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3349                 return parseFloat(val);
3350             }
3351
3352             var a = this.patterns.offsetAttribute.exec(attr) || [];
3353             var pos = !!( a[3] );
3354             var box = !!( a[2] );
3355
3356
3357             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3358                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3359             } else {
3360                 val = 0;
3361             }
3362
3363             return val;
3364         },
3365
3366
3367         getDefaultUnit: function(attr) {
3368             if (this.patterns.defaultUnit.test(attr)) {
3369                 return 'px';
3370             }
3371
3372             return '';
3373         },
3374
3375         animateX : function(callback, scope) {
3376             var f = function() {
3377                 this.onComplete.removeListener(f);
3378                 if (typeof callback == "function") {
3379                     callback.call(scope || this, this);
3380                 }
3381             };
3382             this.onComplete.addListener(f, this);
3383             this.animate();
3384         },
3385
3386
3387         setRuntimeAttribute: function(attr) {
3388             var start;
3389             var end;
3390             var attributes = this.attributes;
3391
3392             this.runtimeAttributes[attr] = {};
3393
3394             var isset = function(prop) {
3395                 return (typeof prop !== 'undefined');
3396             };
3397
3398             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3399                 return false;
3400             }
3401
3402             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3403
3404
3405             if (isset(attributes[attr]['to'])) {
3406                 end = attributes[attr]['to'];
3407             } else if (isset(attributes[attr]['by'])) {
3408                 if (start.constructor == Array) {
3409                     end = [];
3410                     for (var i = 0, len = start.length; i < len; ++i) {
3411                         end[i] = start[i] + attributes[attr]['by'][i];
3412                     }
3413                 } else {
3414                     end = start + attributes[attr]['by'];
3415                 }
3416             }
3417
3418             this.runtimeAttributes[attr].start = start;
3419             this.runtimeAttributes[attr].end = end;
3420
3421
3422             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3423         },
3424
3425
3426         init: function(el, attributes, duration, method) {
3427
3428             var isAnimated = false;
3429
3430
3431             var startTime = null;
3432
3433
3434             var actualFrames = 0;
3435
3436
3437             el = Roo.getDom(el);
3438
3439
3440             this.attributes = attributes || {};
3441
3442
3443             this.duration = duration || 1;
3444
3445
3446             this.method = method || Roo.lib.Easing.easeNone;
3447
3448
3449             this.useSeconds = true;
3450
3451
3452             this.currentFrame = 0;
3453
3454
3455             this.totalFrames = Roo.lib.AnimMgr.fps;
3456
3457
3458             this.getEl = function() {
3459                 return el;
3460             };
3461
3462
3463             this.isAnimated = function() {
3464                 return isAnimated;
3465             };
3466
3467
3468             this.getStartTime = function() {
3469                 return startTime;
3470             };
3471
3472             this.runtimeAttributes = {};
3473
3474
3475             this.animate = function() {
3476                 if (this.isAnimated()) {
3477                     return false;
3478                 }
3479
3480                 this.currentFrame = 0;
3481
3482                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3483
3484                 Roo.lib.AnimMgr.registerElement(this);
3485             };
3486
3487
3488             this.stop = function(finish) {
3489                 if (finish) {
3490                     this.currentFrame = this.totalFrames;
3491                     this._onTween.fire();
3492                 }
3493                 Roo.lib.AnimMgr.stop(this);
3494             };
3495
3496             var onStart = function() {
3497                 this.onStart.fire();
3498
3499                 this.runtimeAttributes = {};
3500                 for (var attr in this.attributes) {
3501                     this.setRuntimeAttribute(attr);
3502                 }
3503
3504                 isAnimated = true;
3505                 actualFrames = 0;
3506                 startTime = new Date();
3507             };
3508
3509
3510             var onTween = function() {
3511                 var data = {
3512                     duration: new Date() - this.getStartTime(),
3513                     currentFrame: this.currentFrame
3514                 };
3515
3516                 data.toString = function() {
3517                     return (
3518                             'duration: ' + data.duration +
3519                             ', currentFrame: ' + data.currentFrame
3520                             );
3521                 };
3522
3523                 this.onTween.fire(data);
3524
3525                 var runtimeAttributes = this.runtimeAttributes;
3526
3527                 for (var attr in runtimeAttributes) {
3528                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3529                 }
3530
3531                 actualFrames += 1;
3532             };
3533
3534             var onComplete = function() {
3535                 var actual_duration = (new Date() - startTime) / 1000 ;
3536
3537                 var data = {
3538                     duration: actual_duration,
3539                     frames: actualFrames,
3540                     fps: actualFrames / actual_duration
3541                 };
3542
3543                 data.toString = function() {
3544                     return (
3545                             'duration: ' + data.duration +
3546                             ', frames: ' + data.frames +
3547                             ', fps: ' + data.fps
3548                             );
3549                 };
3550
3551                 isAnimated = false;
3552                 actualFrames = 0;
3553                 this.onComplete.fire(data);
3554             };
3555
3556
3557             this._onStart = new Roo.util.Event(this);
3558             this.onStart = new Roo.util.Event(this);
3559             this.onTween = new Roo.util.Event(this);
3560             this._onTween = new Roo.util.Event(this);
3561             this.onComplete = new Roo.util.Event(this);
3562             this._onComplete = new Roo.util.Event(this);
3563             this._onStart.addListener(onStart);
3564             this._onTween.addListener(onTween);
3565             this._onComplete.addListener(onComplete);
3566         }
3567     };
3568 })();
3569 /*
3570  * Portions of this file are based on pieces of Yahoo User Interface Library
3571  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3572  * YUI licensed under the BSD License:
3573  * http://developer.yahoo.net/yui/license.txt
3574  * <script type="text/javascript">
3575  *
3576  */
3577
3578 Roo.lib.AnimMgr = new function() {
3579
3580     var thread = null;
3581
3582
3583     var queue = [];
3584
3585
3586     var tweenCount = 0;
3587
3588
3589     this.fps = 1000;
3590
3591
3592     this.delay = 1;
3593
3594
3595     this.registerElement = function(tween) {
3596         queue[queue.length] = tween;
3597         tweenCount += 1;
3598         tween._onStart.fire();
3599         this.start();
3600     };
3601
3602
3603     this.unRegister = function(tween, index) {
3604         tween._onComplete.fire();
3605         index = index || getIndex(tween);
3606         if (index != -1) {
3607             queue.splice(index, 1);
3608         }
3609
3610         tweenCount -= 1;
3611         if (tweenCount <= 0) {
3612             this.stop();
3613         }
3614     };
3615
3616
3617     this.start = function() {
3618         if (thread === null) {
3619             thread = setInterval(this.run, this.delay);
3620         }
3621     };
3622
3623
3624     this.stop = function(tween) {
3625         if (!tween) {
3626             clearInterval(thread);
3627
3628             for (var i = 0, len = queue.length; i < len; ++i) {
3629                 if (queue[0].isAnimated()) {
3630                     this.unRegister(queue[0], 0);
3631                 }
3632             }
3633
3634             queue = [];
3635             thread = null;
3636             tweenCount = 0;
3637         }
3638         else {
3639             this.unRegister(tween);
3640         }
3641     };
3642
3643
3644     this.run = function() {
3645         for (var i = 0, len = queue.length; i < len; ++i) {
3646             var tween = queue[i];
3647             if (!tween || !tween.isAnimated()) {
3648                 continue;
3649             }
3650
3651             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3652             {
3653                 tween.currentFrame += 1;
3654
3655                 if (tween.useSeconds) {
3656                     correctFrame(tween);
3657                 }
3658                 tween._onTween.fire();
3659             }
3660             else {
3661                 Roo.lib.AnimMgr.stop(tween, i);
3662             }
3663         }
3664     };
3665
3666     var getIndex = function(anim) {
3667         for (var i = 0, len = queue.length; i < len; ++i) {
3668             if (queue[i] == anim) {
3669                 return i;
3670             }
3671         }
3672         return -1;
3673     };
3674
3675
3676     var correctFrame = function(tween) {
3677         var frames = tween.totalFrames;
3678         var frame = tween.currentFrame;
3679         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3680         var elapsed = (new Date() - tween.getStartTime());
3681         var tweak = 0;
3682
3683         if (elapsed < tween.duration * 1000) {
3684             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3685         } else {
3686             tweak = frames - (frame + 1);
3687         }
3688         if (tweak > 0 && isFinite(tweak)) {
3689             if (tween.currentFrame + tweak >= frames) {
3690                 tweak = frames - (frame + 1);
3691             }
3692
3693             tween.currentFrame += tweak;
3694         }
3695     };
3696 };
3697
3698     /*
3699  * Portions of this file are based on pieces of Yahoo User Interface Library
3700  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3701  * YUI licensed under the BSD License:
3702  * http://developer.yahoo.net/yui/license.txt
3703  * <script type="text/javascript">
3704  *
3705  */
3706 Roo.lib.Bezier = new function() {
3707
3708         this.getPosition = function(points, t) {
3709             var n = points.length;
3710             var tmp = [];
3711
3712             for (var i = 0; i < n; ++i) {
3713                 tmp[i] = [points[i][0], points[i][1]];
3714             }
3715
3716             for (var j = 1; j < n; ++j) {
3717                 for (i = 0; i < n - j; ++i) {
3718                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3719                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3720                 }
3721             }
3722
3723             return [ tmp[0][0], tmp[0][1] ];
3724
3725         };
3726     }; 
3727
3728 /**
3729  * @class Roo.lib.Color
3730  * @constructor
3731  * An abstract Color implementation. Concrete Color implementations should use
3732  * an instance of this function as their prototype, and implement the getRGB and
3733  * getHSL functions. getRGB should return an object representing the RGB
3734  * components of this Color, with the red, green, and blue components in the
3735  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3736  * return an object representing the HSL components of this Color, with the hue
3737  * component in the range [0,360), the saturation and lightness components in
3738  * the range [0,100], and the alpha component in the range [0,1].
3739  *
3740  *
3741  * Color.js
3742  *
3743  * Functions for Color handling and processing.
3744  *
3745  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3746  *
3747  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3748  * rights to this program, with the intention of it becoming part of the public
3749  * domain. Because this program is released into the public domain, it comes with
3750  * no warranty either expressed or implied, to the extent permitted by law.
3751  * 
3752  * For more free and public domain JavaScript code by the same author, visit:
3753  * http://www.safalra.com/web-design/javascript/
3754  * 
3755  */
3756 Roo.lib.Color = function() { }
3757
3758
3759 Roo.apply(Roo.lib.Color.prototype, {
3760   
3761   rgb : null,
3762   hsv : null,
3763   hsl : null,
3764   
3765   /**
3766    * getIntegerRGB
3767    * @return {Object} an object representing the RGBA components of this Color. The red,
3768    * green, and blue components are converted to integers in the range [0,255].
3769    * The alpha is a value in the range [0,1].
3770    */
3771   getIntegerRGB : function(){
3772
3773     // get the RGB components of this Color
3774     var rgb = this.getRGB();
3775
3776     // return the integer components
3777     return {
3778       'r' : Math.round(rgb.r),
3779       'g' : Math.round(rgb.g),
3780       'b' : Math.round(rgb.b),
3781       'a' : rgb.a
3782     };
3783
3784   },
3785
3786   /**
3787    * getPercentageRGB
3788    * @return {Object} an object representing the RGBA components of this Color. The red,
3789    * green, and blue components are converted to numbers in the range [0,100].
3790    * The alpha is a value in the range [0,1].
3791    */
3792   getPercentageRGB : function(){
3793
3794     // get the RGB components of this Color
3795     var rgb = this.getRGB();
3796
3797     // return the percentage components
3798     return {
3799       'r' : 100 * rgb.r / 255,
3800       'g' : 100 * rgb.g / 255,
3801       'b' : 100 * rgb.b / 255,
3802       'a' : rgb.a
3803     };
3804
3805   },
3806
3807   /**
3808    * getCSSHexadecimalRGB
3809    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3810    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3811    * are two-digit hexadecimal numbers.
3812    */
3813   getCSSHexadecimalRGB : function()
3814   {
3815
3816     // get the integer RGB components
3817     var rgb = this.getIntegerRGB();
3818
3819     // determine the hexadecimal equivalents
3820     var r16 = rgb.r.toString(16);
3821     var g16 = rgb.g.toString(16);
3822     var b16 = rgb.b.toString(16);
3823
3824     // return the CSS RGB Color value
3825     return '#'
3826         + (r16.length == 2 ? r16 : '0' + r16)
3827         + (g16.length == 2 ? g16 : '0' + g16)
3828         + (b16.length == 2 ? b16 : '0' + b16);
3829
3830   },
3831
3832   /**
3833    * getCSSIntegerRGB
3834    * @return {String} a string representing this Color as a CSS integer RGB Color
3835    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3836    * are integers in the range [0,255].
3837    */
3838   getCSSIntegerRGB : function(){
3839
3840     // get the integer RGB components
3841     var rgb = this.getIntegerRGB();
3842
3843     // return the CSS RGB Color value
3844     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3845
3846   },
3847
3848   /**
3849    * getCSSIntegerRGBA
3850    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3851    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3852    * b are integers in the range [0,255] and a is in the range [0,1].
3853    */
3854   getCSSIntegerRGBA : function(){
3855
3856     // get the integer RGB components
3857     var rgb = this.getIntegerRGB();
3858
3859     // return the CSS integer RGBA Color value
3860     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3861
3862   },
3863
3864   /**
3865    * getCSSPercentageRGB
3866    * @return {String} a string representing this Color as a CSS percentage RGB Color
3867    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3868    * b are in the range [0,100].
3869    */
3870   getCSSPercentageRGB : function(){
3871
3872     // get the percentage RGB components
3873     var rgb = this.getPercentageRGB();
3874
3875     // return the CSS RGB Color value
3876     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3877
3878   },
3879
3880   /**
3881    * getCSSPercentageRGBA
3882    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3883    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3884    * and b are in the range [0,100] and a is in the range [0,1].
3885    */
3886   getCSSPercentageRGBA : function(){
3887
3888     // get the percentage RGB components
3889     var rgb = this.getPercentageRGB();
3890
3891     // return the CSS percentage RGBA Color value
3892     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3893
3894   },
3895
3896   /**
3897    * getCSSHSL
3898    * @return {String} a string representing this Color as a CSS HSL Color value - that
3899    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3900    * s and l are in the range [0,100].
3901    */
3902   getCSSHSL : function(){
3903
3904     // get the HSL components
3905     var hsl = this.getHSL();
3906
3907     // return the CSS HSL Color value
3908     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3909
3910   },
3911
3912   /**
3913    * getCSSHSLA
3914    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3915    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3916    * s and l are in the range [0,100], and a is in the range [0,1].
3917    */
3918   getCSSHSLA : function(){
3919
3920     // get the HSL components
3921     var hsl = this.getHSL();
3922
3923     // return the CSS HSL Color value
3924     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3925
3926   },
3927
3928   /**
3929    * Sets the Color of the specified node to this Color. This functions sets
3930    * the CSS 'color' property for the node. The parameter is:
3931    * 
3932    * @param {DomElement} node - the node whose Color should be set
3933    */
3934   setNodeColor : function(node){
3935
3936     // set the Color of the node
3937     node.style.color = this.getCSSHexadecimalRGB();
3938
3939   },
3940
3941   /**
3942    * Sets the background Color of the specified node to this Color. This
3943    * functions sets the CSS 'background-color' property for the node. The
3944    * parameter is:
3945    *
3946    * @param {DomElement} node - the node whose background Color should be set
3947    */
3948   setNodeBackgroundColor : function(node){
3949
3950     // set the background Color of the node
3951     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3952
3953   },
3954   // convert between formats..
3955   toRGB: function()
3956   {
3957     var r = this.getIntegerRGB();
3958     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3959     
3960   },
3961   toHSL : function()
3962   {
3963      var hsl = this.getHSL();
3964   // return the CSS HSL Color value
3965     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3966     
3967   },
3968   
3969   toHSV : function()
3970   {
3971     var rgb = this.toRGB();
3972     var hsv = rgb.getHSV();
3973    // return the CSS HSL Color value
3974     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3975     
3976   },
3977   
3978   // modify  v = 0 ... 1 (eg. 0.5)
3979   saturate : function(v)
3980   {
3981       var rgb = this.toRGB();
3982       var hsv = rgb.getHSV();
3983       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3984       
3985   
3986   },
3987   
3988    
3989   /**
3990    * getRGB
3991    * @return {Object} the RGB and alpha components of this Color as an object with r,
3992    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3993    * the range [0,1].
3994    */
3995   getRGB: function(){
3996    
3997     // return the RGB components
3998     return {
3999       'r' : this.rgb.r,
4000       'g' : this.rgb.g,
4001       'b' : this.rgb.b,
4002       'a' : this.alpha
4003     };
4004
4005   },
4006
4007   /**
4008    * getHSV
4009    * @return {Object} the HSV and alpha components of this Color as an object with h,
4010    * s, v, and a properties. h is in the range [0,360), s and v are in the range
4011    * [0,100], and a is in the range [0,1].
4012    */
4013   getHSV : function()
4014   {
4015     
4016     // calculate the HSV components if necessary
4017     if (this.hsv == null) {
4018       this.calculateHSV();
4019     }
4020
4021     // return the HSV components
4022     return {
4023       'h' : this.hsv.h,
4024       's' : this.hsv.s,
4025       'v' : this.hsv.v,
4026       'a' : this.alpha
4027     };
4028
4029   },
4030
4031   /**
4032    * getHSL
4033    * @return {Object} the HSL and alpha components of this Color as an object with h,
4034    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4035    * [0,100], and a is in the range [0,1].
4036    */
4037   getHSL : function(){
4038     
4039      
4040     // calculate the HSV components if necessary
4041     if (this.hsl == null) { this.calculateHSL(); }
4042
4043     // return the HSL components
4044     return {
4045       'h' : this.hsl.h,
4046       's' : this.hsl.s,
4047       'l' : this.hsl.l,
4048       'a' : this.alpha
4049     };
4050
4051   }
4052   
4053
4054 });
4055
4056
4057 /**
4058  * @class Roo.lib.RGBColor
4059  * @extends Roo.lib.Color
4060  * Creates a Color specified in the RGB Color space, with an optional alpha
4061  * component. The parameters are:
4062  * @constructor
4063  * 
4064
4065  * @param {Number} r - the red component, clipped to the range [0,255]
4066  * @param {Number} g - the green component, clipped to the range [0,255]
4067  * @param {Number} b - the blue component, clipped to the range [0,255]
4068  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4069  *     optional and defaults to 1
4070  */
4071 Roo.lib.RGBColor = function (r, g, b, a){
4072
4073   // store the alpha component after clipping it if necessary
4074   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4075
4076   // store the RGB components after clipping them if necessary
4077   this.rgb =
4078       {
4079         'r' : Math.max(0, Math.min(255, r)),
4080         'g' : Math.max(0, Math.min(255, g)),
4081         'b' : Math.max(0, Math.min(255, b))
4082       };
4083
4084   // initialise the HSV and HSL components to null
4085   
4086
4087   /* 
4088    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4089    * range [0,360). The parameters are:
4090    *
4091    * maximum - the maximum of the RGB component values
4092    * range   - the range of the RGB component values
4093    */
4094    
4095
4096 }
4097 // this does an 'exteds'
4098 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4099
4100   
4101     getHue  : function(maximum, range)
4102     {
4103       var rgb = this.rgb;
4104        
4105       // check whether the range is zero
4106       if (range == 0){
4107   
4108         // set the hue to zero (any hue is acceptable as the Color is grey)
4109         var hue = 0;
4110   
4111       }else{
4112   
4113         // determine which of the components has the highest value and set the hue
4114         switch (maximum){
4115   
4116           // red has the highest value
4117           case rgb.r:
4118             var hue = (rgb.g - rgb.b) / range * 60;
4119             if (hue < 0) { hue += 360; }
4120             break;
4121   
4122           // green has the highest value
4123           case rgb.g:
4124             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4125             break;
4126   
4127           // blue has the highest value
4128           case rgb.b:
4129             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4130             break;
4131   
4132         }
4133   
4134       }
4135   
4136       // return the hue
4137       return hue;
4138   
4139     },
4140
4141   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4142    * be returned be the getHSV function.
4143    */
4144    calculateHSV : function(){
4145     var rgb = this.rgb;
4146     // get the maximum and range of the RGB component values
4147     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4148     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4149
4150     // store the HSV components
4151     this.hsv =
4152         {
4153           'h' : this.getHue(maximum, range),
4154           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4155           'v' : maximum / 2.55
4156         };
4157
4158   },
4159
4160   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4161    * be returned be the getHSL function.
4162    */
4163    calculateHSL : function(){
4164     var rgb = this.rgb;
4165     // get the maximum and range of the RGB component values
4166     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4167     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4168
4169     // determine the lightness in the range [0,1]
4170     var l = maximum / 255 - range / 510;
4171
4172     // store the HSL components
4173     this.hsl =
4174         {
4175           'h' : this.getHue(maximum, range),
4176           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4177           'l' : 100 * l
4178         };
4179
4180   }
4181
4182 });
4183
4184 /**
4185  * @class Roo.lib.HSVColor
4186  * @extends Roo.lib.Color
4187  * Creates a Color specified in the HSV Color space, with an optional alpha
4188  * component. The parameters are:
4189  * @constructor
4190  *
4191  * @param {Number} h - the hue component, wrapped to the range [0,360)
4192  * @param {Number} s - the saturation component, clipped to the range [0,100]
4193  * @param {Number} v - the value component, clipped to the range [0,100]
4194  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4195  *     optional and defaults to 1
4196  */
4197 Roo.lib.HSVColor = function (h, s, v, a){
4198
4199   // store the alpha component after clipping it if necessary
4200   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4201
4202   // store the HSV components after clipping or wrapping them if necessary
4203   this.hsv =
4204       {
4205         'h' : (h % 360 + 360) % 360,
4206         's' : Math.max(0, Math.min(100, s)),
4207         'v' : Math.max(0, Math.min(100, v))
4208       };
4209
4210   // initialise the RGB and HSL components to null
4211   this.rgb = null;
4212   this.hsl = null;
4213 }
4214
4215 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4216   /* Calculates and stores the RGB components of this HSVColor so that they can
4217    * be returned be the getRGB function.
4218    */
4219   calculateRGB: function ()
4220   {
4221     var hsv = this.hsv;
4222     // check whether the saturation is zero
4223     if (hsv.s == 0){
4224
4225       // set the Color to the appropriate shade of grey
4226       var r = hsv.v;
4227       var g = hsv.v;
4228       var b = hsv.v;
4229
4230     }else{
4231
4232       // set some temporary values
4233       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4234       var p  = hsv.v * (1 - hsv.s / 100);
4235       var q  = hsv.v * (1 - hsv.s / 100 * f);
4236       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4237
4238       // set the RGB Color components to their temporary values
4239       switch (Math.floor(hsv.h / 60)){
4240         case 0: var r = hsv.v; var g = t; var b = p; break;
4241         case 1: var r = q; var g = hsv.v; var b = p; break;
4242         case 2: var r = p; var g = hsv.v; var b = t; break;
4243         case 3: var r = p; var g = q; var b = hsv.v; break;
4244         case 4: var r = t; var g = p; var b = hsv.v; break;
4245         case 5: var r = hsv.v; var g = p; var b = q; break;
4246       }
4247
4248     }
4249
4250     // store the RGB components
4251     this.rgb =
4252         {
4253           'r' : r * 2.55,
4254           'g' : g * 2.55,
4255           'b' : b * 2.55
4256         };
4257
4258   },
4259
4260   /* Calculates and stores the HSL components of this HSVColor so that they can
4261    * be returned be the getHSL function.
4262    */
4263   calculateHSL : function (){
4264
4265     var hsv = this.hsv;
4266     // determine the lightness in the range [0,100]
4267     var l = (2 - hsv.s / 100) * hsv.v / 2;
4268
4269     // store the HSL components
4270     this.hsl =
4271         {
4272           'h' : hsv.h,
4273           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4274           'l' : l
4275         };
4276
4277     // correct a division-by-zero error
4278     if (isNaN(hsl.s)) { hsl.s = 0; }
4279
4280   } 
4281  
4282
4283 });
4284  
4285
4286 /**
4287  * @class Roo.lib.HSLColor
4288  * @extends Roo.lib.Color
4289  *
4290  * @constructor
4291  * Creates a Color specified in the HSL Color space, with an optional alpha
4292  * component. The parameters are:
4293  *
4294  * @param {Number} h - the hue component, wrapped to the range [0,360)
4295  * @param {Number} s - the saturation component, clipped to the range [0,100]
4296  * @param {Number} l - the lightness component, clipped to the range [0,100]
4297  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4298  *     optional and defaults to 1
4299  */
4300
4301 Roo.lib.HSLColor = function(h, s, l, a){
4302
4303   // store the alpha component after clipping it if necessary
4304   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4305
4306   // store the HSL components after clipping or wrapping them if necessary
4307   this.hsl =
4308       {
4309         'h' : (h % 360 + 360) % 360,
4310         's' : Math.max(0, Math.min(100, s)),
4311         'l' : Math.max(0, Math.min(100, l))
4312       };
4313
4314   // initialise the RGB and HSV components to null
4315 }
4316
4317 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4318
4319   /* Calculates and stores the RGB components of this HSLColor so that they can
4320    * be returned be the getRGB function.
4321    */
4322   calculateRGB: function (){
4323
4324     // check whether the saturation is zero
4325     if (this.hsl.s == 0){
4326
4327       // store the RGB components representing the appropriate shade of grey
4328       this.rgb =
4329           {
4330             'r' : this.hsl.l * 2.55,
4331             'g' : this.hsl.l * 2.55,
4332             'b' : this.hsl.l * 2.55
4333           };
4334
4335     }else{
4336
4337       // set some temporary values
4338       var p = this.hsl.l < 50
4339             ? this.hsl.l * (1 + hsl.s / 100)
4340             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4341       var q = 2 * hsl.l - p;
4342
4343       // initialise the RGB components
4344       this.rgb =
4345           {
4346             'r' : (h + 120) / 60 % 6,
4347             'g' : h / 60,
4348             'b' : (h + 240) / 60 % 6
4349           };
4350
4351       // loop over the RGB components
4352       for (var key in this.rgb){
4353
4354         // ensure that the property is not inherited from the root object
4355         if (this.rgb.hasOwnProperty(key)){
4356
4357           // set the component to its value in the range [0,100]
4358           if (this.rgb[key] < 1){
4359             this.rgb[key] = q + (p - q) * this.rgb[key];
4360           }else if (this.rgb[key] < 3){
4361             this.rgb[key] = p;
4362           }else if (this.rgb[key] < 4){
4363             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4364           }else{
4365             this.rgb[key] = q;
4366           }
4367
4368           // set the component to its value in the range [0,255]
4369           this.rgb[key] *= 2.55;
4370
4371         }
4372
4373       }
4374
4375     }
4376
4377   },
4378
4379   /* Calculates and stores the HSV components of this HSLColor so that they can
4380    * be returned be the getHSL function.
4381    */
4382    calculateHSV : function(){
4383
4384     // set a temporary value
4385     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4386
4387     // store the HSV components
4388     this.hsv =
4389         {
4390           'h' : this.hsl.h,
4391           's' : 200 * t / (this.hsl.l + t),
4392           'v' : t + this.hsl.l
4393         };
4394
4395     // correct a division-by-zero error
4396     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4397
4398   }
4399  
4400
4401 });
4402 /*
4403  * Portions of this file are based on pieces of Yahoo User Interface Library
4404  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4405  * YUI licensed under the BSD License:
4406  * http://developer.yahoo.net/yui/license.txt
4407  * <script type="text/javascript">
4408  *
4409  */
4410 (function() {
4411
4412     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4413         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4414     };
4415
4416     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4417
4418     var fly = Roo.lib.AnimBase.fly;
4419     var Y = Roo.lib;
4420     var superclass = Y.ColorAnim.superclass;
4421     var proto = Y.ColorAnim.prototype;
4422
4423     proto.toString = function() {
4424         var el = this.getEl();
4425         var id = el.id || el.tagName;
4426         return ("ColorAnim " + id);
4427     };
4428
4429     proto.patterns.color = /color$/i;
4430     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4431     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4432     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4433     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4434
4435
4436     proto.parseColor = function(s) {
4437         if (s.length == 3) {
4438             return s;
4439         }
4440
4441         var c = this.patterns.hex.exec(s);
4442         if (c && c.length == 4) {
4443             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4444         }
4445
4446         c = this.patterns.rgb.exec(s);
4447         if (c && c.length == 4) {
4448             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4449         }
4450
4451         c = this.patterns.hex3.exec(s);
4452         if (c && c.length == 4) {
4453             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4454         }
4455
4456         return null;
4457     };
4458     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4459     proto.getAttribute = function(attr) {
4460         var el = this.getEl();
4461         if (this.patterns.color.test(attr)) {
4462             var val = fly(el).getStyle(attr);
4463
4464             if (this.patterns.transparent.test(val)) {
4465                 var parent = el.parentNode;
4466                 val = fly(parent).getStyle(attr);
4467
4468                 while (parent && this.patterns.transparent.test(val)) {
4469                     parent = parent.parentNode;
4470                     val = fly(parent).getStyle(attr);
4471                     if (parent.tagName.toUpperCase() == 'HTML') {
4472                         val = '#fff';
4473                     }
4474                 }
4475             }
4476         } else {
4477             val = superclass.getAttribute.call(this, attr);
4478         }
4479
4480         return val;
4481     };
4482     proto.getAttribute = function(attr) {
4483         var el = this.getEl();
4484         if (this.patterns.color.test(attr)) {
4485             var val = fly(el).getStyle(attr);
4486
4487             if (this.patterns.transparent.test(val)) {
4488                 var parent = el.parentNode;
4489                 val = fly(parent).getStyle(attr);
4490
4491                 while (parent && this.patterns.transparent.test(val)) {
4492                     parent = parent.parentNode;
4493                     val = fly(parent).getStyle(attr);
4494                     if (parent.tagName.toUpperCase() == 'HTML') {
4495                         val = '#fff';
4496                     }
4497                 }
4498             }
4499         } else {
4500             val = superclass.getAttribute.call(this, attr);
4501         }
4502
4503         return val;
4504     };
4505
4506     proto.doMethod = function(attr, start, end) {
4507         var val;
4508
4509         if (this.patterns.color.test(attr)) {
4510             val = [];
4511             for (var i = 0, len = start.length; i < len; ++i) {
4512                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4513             }
4514
4515             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4516         }
4517         else {
4518             val = superclass.doMethod.call(this, attr, start, end);
4519         }
4520
4521         return val;
4522     };
4523
4524     proto.setRuntimeAttribute = function(attr) {
4525         superclass.setRuntimeAttribute.call(this, attr);
4526
4527         if (this.patterns.color.test(attr)) {
4528             var attributes = this.attributes;
4529             var start = this.parseColor(this.runtimeAttributes[attr].start);
4530             var end = this.parseColor(this.runtimeAttributes[attr].end);
4531
4532             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4533                 end = this.parseColor(attributes[attr].by);
4534
4535                 for (var i = 0, len = start.length; i < len; ++i) {
4536                     end[i] = start[i] + end[i];
4537                 }
4538             }
4539
4540             this.runtimeAttributes[attr].start = start;
4541             this.runtimeAttributes[attr].end = end;
4542         }
4543     };
4544 })();
4545
4546 /*
4547  * Portions of this file are based on pieces of Yahoo User Interface Library
4548  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4549  * YUI licensed under the BSD License:
4550  * http://developer.yahoo.net/yui/license.txt
4551  * <script type="text/javascript">
4552  *
4553  */
4554 Roo.lib.Easing = {
4555
4556
4557     easeNone: function (t, b, c, d) {
4558         return c * t / d + b;
4559     },
4560
4561
4562     easeIn: function (t, b, c, d) {
4563         return c * (t /= d) * t + b;
4564     },
4565
4566
4567     easeOut: function (t, b, c, d) {
4568         return -c * (t /= d) * (t - 2) + b;
4569     },
4570
4571
4572     easeBoth: function (t, b, c, d) {
4573         if ((t /= d / 2) < 1) {
4574             return c / 2 * t * t + b;
4575         }
4576
4577         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4578     },
4579
4580
4581     easeInStrong: function (t, b, c, d) {
4582         return c * (t /= d) * t * t * t + b;
4583     },
4584
4585
4586     easeOutStrong: function (t, b, c, d) {
4587         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4588     },
4589
4590
4591     easeBothStrong: function (t, b, c, d) {
4592         if ((t /= d / 2) < 1) {
4593             return c / 2 * t * t * t * t + b;
4594         }
4595
4596         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4597     },
4598
4599
4600
4601     elasticIn: function (t, b, c, d, a, p) {
4602         if (t == 0) {
4603             return b;
4604         }
4605         if ((t /= d) == 1) {
4606             return b + c;
4607         }
4608         if (!p) {
4609             p = d * .3;
4610         }
4611
4612         if (!a || a < Math.abs(c)) {
4613             a = c;
4614             var s = p / 4;
4615         }
4616         else {
4617             var s = p / (2 * Math.PI) * Math.asin(c / a);
4618         }
4619
4620         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4621     },
4622
4623
4624     elasticOut: function (t, b, c, d, a, p) {
4625         if (t == 0) {
4626             return b;
4627         }
4628         if ((t /= d) == 1) {
4629             return b + c;
4630         }
4631         if (!p) {
4632             p = d * .3;
4633         }
4634
4635         if (!a || a < Math.abs(c)) {
4636             a = c;
4637             var s = p / 4;
4638         }
4639         else {
4640             var s = p / (2 * Math.PI) * Math.asin(c / a);
4641         }
4642
4643         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4644     },
4645
4646
4647     elasticBoth: function (t, b, c, d, a, p) {
4648         if (t == 0) {
4649             return b;
4650         }
4651
4652         if ((t /= d / 2) == 2) {
4653             return b + c;
4654         }
4655
4656         if (!p) {
4657             p = d * (.3 * 1.5);
4658         }
4659
4660         if (!a || a < Math.abs(c)) {
4661             a = c;
4662             var s = p / 4;
4663         }
4664         else {
4665             var s = p / (2 * Math.PI) * Math.asin(c / a);
4666         }
4667
4668         if (t < 1) {
4669             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4670                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4671         }
4672         return a * Math.pow(2, -10 * (t -= 1)) *
4673                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4674     },
4675
4676
4677
4678     backIn: function (t, b, c, d, s) {
4679         if (typeof s == 'undefined') {
4680             s = 1.70158;
4681         }
4682         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4683     },
4684
4685
4686     backOut: function (t, b, c, d, s) {
4687         if (typeof s == 'undefined') {
4688             s = 1.70158;
4689         }
4690         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4691     },
4692
4693
4694     backBoth: function (t, b, c, d, s) {
4695         if (typeof s == 'undefined') {
4696             s = 1.70158;
4697         }
4698
4699         if ((t /= d / 2 ) < 1) {
4700             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4701         }
4702         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4703     },
4704
4705
4706     bounceIn: function (t, b, c, d) {
4707         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4708     },
4709
4710
4711     bounceOut: function (t, b, c, d) {
4712         if ((t /= d) < (1 / 2.75)) {
4713             return c * (7.5625 * t * t) + b;
4714         } else if (t < (2 / 2.75)) {
4715             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4716         } else if (t < (2.5 / 2.75)) {
4717             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4718         }
4719         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4720     },
4721
4722
4723     bounceBoth: function (t, b, c, d) {
4724         if (t < d / 2) {
4725             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4726         }
4727         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4728     }
4729 };/*
4730  * Portions of this file are based on pieces of Yahoo User Interface Library
4731  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4732  * YUI licensed under the BSD License:
4733  * http://developer.yahoo.net/yui/license.txt
4734  * <script type="text/javascript">
4735  *
4736  */
4737     (function() {
4738         Roo.lib.Motion = function(el, attributes, duration, method) {
4739             if (el) {
4740                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4741             }
4742         };
4743
4744         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4745
4746
4747         var Y = Roo.lib;
4748         var superclass = Y.Motion.superclass;
4749         var proto = Y.Motion.prototype;
4750
4751         proto.toString = function() {
4752             var el = this.getEl();
4753             var id = el.id || el.tagName;
4754             return ("Motion " + id);
4755         };
4756
4757         proto.patterns.points = /^points$/i;
4758
4759         proto.setAttribute = function(attr, val, unit) {
4760             if (this.patterns.points.test(attr)) {
4761                 unit = unit || 'px';
4762                 superclass.setAttribute.call(this, 'left', val[0], unit);
4763                 superclass.setAttribute.call(this, 'top', val[1], unit);
4764             } else {
4765                 superclass.setAttribute.call(this, attr, val, unit);
4766             }
4767         };
4768
4769         proto.getAttribute = function(attr) {
4770             if (this.patterns.points.test(attr)) {
4771                 var val = [
4772                         superclass.getAttribute.call(this, 'left'),
4773                         superclass.getAttribute.call(this, 'top')
4774                         ];
4775             } else {
4776                 val = superclass.getAttribute.call(this, attr);
4777             }
4778
4779             return val;
4780         };
4781
4782         proto.doMethod = function(attr, start, end) {
4783             var val = null;
4784
4785             if (this.patterns.points.test(attr)) {
4786                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4787                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4788             } else {
4789                 val = superclass.doMethod.call(this, attr, start, end);
4790             }
4791             return val;
4792         };
4793
4794         proto.setRuntimeAttribute = function(attr) {
4795             if (this.patterns.points.test(attr)) {
4796                 var el = this.getEl();
4797                 var attributes = this.attributes;
4798                 var start;
4799                 var control = attributes['points']['control'] || [];
4800                 var end;
4801                 var i, len;
4802
4803                 if (control.length > 0 && !(control[0] instanceof Array)) {
4804                     control = [control];
4805                 } else {
4806                     var tmp = [];
4807                     for (i = 0,len = control.length; i < len; ++i) {
4808                         tmp[i] = control[i];
4809                     }
4810                     control = tmp;
4811                 }
4812
4813                 Roo.fly(el).position();
4814
4815                 if (isset(attributes['points']['from'])) {
4816                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4817                 }
4818                 else {
4819                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4820                 }
4821
4822                 start = this.getAttribute('points');
4823
4824
4825                 if (isset(attributes['points']['to'])) {
4826                     end = translateValues.call(this, attributes['points']['to'], start);
4827
4828                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4829                     for (i = 0,len = control.length; i < len; ++i) {
4830                         control[i] = translateValues.call(this, control[i], start);
4831                     }
4832
4833
4834                 } else if (isset(attributes['points']['by'])) {
4835                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4836
4837                     for (i = 0,len = control.length; i < len; ++i) {
4838                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4839                     }
4840                 }
4841
4842                 this.runtimeAttributes[attr] = [start];
4843
4844                 if (control.length > 0) {
4845                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4846                 }
4847
4848                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4849             }
4850             else {
4851                 superclass.setRuntimeAttribute.call(this, attr);
4852             }
4853         };
4854
4855         var translateValues = function(val, start) {
4856             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4857             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4858
4859             return val;
4860         };
4861
4862         var isset = function(prop) {
4863             return (typeof prop !== 'undefined');
4864         };
4865     })();
4866 /*
4867  * Portions of this file are based on pieces of Yahoo User Interface Library
4868  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4869  * YUI licensed under the BSD License:
4870  * http://developer.yahoo.net/yui/license.txt
4871  * <script type="text/javascript">
4872  *
4873  */
4874     (function() {
4875         Roo.lib.Scroll = function(el, attributes, duration, method) {
4876             if (el) {
4877                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4878             }
4879         };
4880
4881         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4882
4883
4884         var Y = Roo.lib;
4885         var superclass = Y.Scroll.superclass;
4886         var proto = Y.Scroll.prototype;
4887
4888         proto.toString = function() {
4889             var el = this.getEl();
4890             var id = el.id || el.tagName;
4891             return ("Scroll " + id);
4892         };
4893
4894         proto.doMethod = function(attr, start, end) {
4895             var val = null;
4896
4897             if (attr == 'scroll') {
4898                 val = [
4899                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4900                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4901                         ];
4902
4903             } else {
4904                 val = superclass.doMethod.call(this, attr, start, end);
4905             }
4906             return val;
4907         };
4908
4909         proto.getAttribute = function(attr) {
4910             var val = null;
4911             var el = this.getEl();
4912
4913             if (attr == 'scroll') {
4914                 val = [ el.scrollLeft, el.scrollTop ];
4915             } else {
4916                 val = superclass.getAttribute.call(this, attr);
4917             }
4918
4919             return val;
4920         };
4921
4922         proto.setAttribute = function(attr, val, unit) {
4923             var el = this.getEl();
4924
4925             if (attr == 'scroll') {
4926                 el.scrollLeft = val[0];
4927                 el.scrollTop = val[1];
4928             } else {
4929                 superclass.setAttribute.call(this, attr, val, unit);
4930             }
4931         };
4932     })();
4933 /**
4934  * Originally based of this code... - refactored for Roo...
4935  * https://github.com/aaalsaleh/undo-manager
4936  
4937  * undo-manager.js
4938  * @author  Abdulrahman Alsaleh 
4939  * @copyright 2015 Abdulrahman Alsaleh 
4940  * @license  MIT License (c) 
4941  *
4942  * Hackily modifyed by alan@roojs.com
4943  *
4944  *
4945  *  
4946  *
4947  *  TOTALLY UNTESTED...
4948  *
4949  *  Documentation to be done....
4950  */
4951  
4952
4953 /**
4954 * @class Roo.lib.UndoManager
4955 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4956 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4957
4958  * Usage:
4959  * <pre><code>
4960
4961
4962 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4963  
4964 </code></pre>
4965
4966 * For more information see this blog post with examples:
4967 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4968      - Create Elements using DOM, HTML fragments and Templates</a>. 
4969 * @constructor
4970 * @param {Number} limit how far back to go ... use 1000?
4971 * @param {Object} scope usually use document..
4972 */
4973
4974 Roo.lib.UndoManager = function (limit, undoScopeHost)
4975 {
4976     this.stack = [];
4977     this.limit = limit;
4978     this.scope = undoScopeHost;
4979     this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4980     if (this.fireEvent) {
4981         this.bindEvents();
4982     }
4983     this.reset();
4984     
4985 };
4986         
4987 Roo.lib.UndoManager.prototype = {
4988     
4989     limit : false,
4990     stack : false,
4991     scope :  false,
4992     fireEvent : false,
4993     position : 0,
4994     length : 0,
4995     
4996     
4997      /**
4998      * To push and execute a transaction, the method undoManager.transact
4999      * must be called by passing a transaction object as the first argument, and a merge
5000      * flag as the second argument. A transaction object has the following properties:
5001      *
5002      * Usage:
5003 <pre><code>
5004 undoManager.transact({
5005     label: 'Typing',
5006     execute: function() { ... },
5007     undo: function() { ... },
5008     // redo same as execute
5009     redo: function() { this.execute(); }
5010 }, false);
5011
5012 // merge transaction
5013 undoManager.transact({
5014     label: 'Typing',
5015     execute: function() { ... },  // this will be run...
5016     undo: function() { ... }, // what to do when undo is run.
5017     // redo same as execute
5018     redo: function() { this.execute(); }
5019 }, true); 
5020 </code></pre> 
5021      *
5022      * 
5023      * @param {Object} transaction The transaction to add to the stack.
5024      * @return {String} The HTML fragment
5025      */
5026     
5027     
5028     transact : function (transaction, merge)
5029     {
5030         if (arguments.length < 2) {
5031             throw new TypeError('Not enough arguments to UndoManager.transact.');
5032         }
5033
5034         transaction.execute();
5035
5036         this.stack.splice(0, this.position);
5037         if (merge && this.length) {
5038             this.stack[0].push(transaction);
5039         } else {
5040             this.stack.unshift([transaction]);
5041         }
5042     
5043         this.position = 0;
5044
5045         if (this.limit && this.stack.length > this.limit) {
5046             this.length = this.stack.length = this.limit;
5047         } else {
5048             this.length = this.stack.length;
5049         }
5050
5051         if (this.fireEvent) {
5052             this.scope.dispatchEvent(
5053                 new CustomEvent('DOMTransaction', {
5054                     detail: {
5055                         transactions: this.stack[0].slice()
5056                     },
5057                     bubbles: true,
5058                     cancelable: false
5059                 })
5060             );
5061         }
5062         
5063         //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5064       
5065         
5066     },
5067
5068     undo : function ()
5069     {
5070         //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5071         
5072         if (this.position < this.length) {
5073             for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5074                 this.stack[this.position][i].undo();
5075             }
5076             this.position++;
5077
5078             if (this.fireEvent) {
5079                 this.scope.dispatchEvent(
5080                     new CustomEvent('undo', {
5081                         detail: {
5082                             transactions: this.stack[this.position - 1].slice()
5083                         },
5084                         bubbles: true,
5085                         cancelable: false
5086                     })
5087                 );
5088             }
5089         }
5090     },
5091
5092     redo : function ()
5093     {
5094         if (this.position > 0) {
5095             for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5096                 this.stack[this.position - 1][i].redo();
5097             }
5098             this.position--;
5099
5100             if (this.fireEvent) {
5101                 this.scope.dispatchEvent(
5102                     new CustomEvent('redo', {
5103                         detail: {
5104                             transactions: this.stack[this.position].slice()
5105                         },
5106                         bubbles: true,
5107                         cancelable: false
5108                     })
5109                 );
5110             }
5111         }
5112     },
5113
5114     item : function (index)
5115     {
5116         if (index >= 0 && index < this.length) {
5117             return this.stack[index].slice();
5118         }
5119         return null;
5120     },
5121
5122     clearUndo : function () {
5123         this.stack.length = this.length = this.position;
5124     },
5125
5126     clearRedo : function () {
5127         this.stack.splice(0, this.position);
5128         this.position = 0;
5129         this.length = this.stack.length;
5130     },
5131     /**
5132      * Reset the undo - probaly done on load to clear all history.
5133      */
5134     reset : function()
5135     {
5136         this.stack = [];
5137         this.position = 0;
5138         this.length = 0;
5139         this.current_html = this.scope.innerHTML;
5140         if (this.timer !== false) {
5141             clearTimeout(this.timer);
5142         }
5143         this.timer = false;
5144         this.merge = false;
5145         this.addEvent();
5146         
5147     },
5148     current_html : '',
5149     timer : false,
5150     merge : false,
5151     
5152     
5153     // this will handle the undo/redo on the element.?
5154     bindEvents : function()
5155     {
5156         var el  = this.scope;
5157         el.undoManager = this;
5158         
5159         
5160         this.scope.addEventListener('keydown', function(e) {
5161             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5162                 if (e.shiftKey) {
5163                     el.undoManager.redo(); // Ctrl/Command + Shift + Z
5164                 } else {
5165                     el.undoManager.undo(); // Ctrl/Command + Z
5166                 }
5167         
5168                 e.preventDefault();
5169             }
5170         });
5171         /// ignore keyup..
5172         this.scope.addEventListener('keyup', function(e) {
5173             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5174                 e.preventDefault();
5175             }
5176         });
5177         
5178         
5179         
5180         var t = this;
5181         
5182         el.addEventListener('input', function(e) {
5183             if(el.innerHTML == t.current_html) {
5184                 return;
5185             }
5186             // only record events every second.
5187             if (t.timer !== false) {
5188                clearTimeout(t.timer);
5189                t.timer = false;
5190             }
5191             t.timer = setTimeout(function() { t.merge = false; }, 1000);
5192             
5193             t.addEvent(t.merge);
5194             t.merge = true; // ignore changes happening every second..
5195         });
5196         },
5197     /**
5198      * Manually add an event.
5199      * Normall called without arguements - and it will just get added to the stack.
5200      * 
5201      */
5202     
5203     addEvent : function(merge)
5204     {
5205         //Roo.log("undomanager +" + (merge ? 'Y':'n'));
5206         // not sure if this should clear the timer 
5207         merge = typeof(merge) == 'undefined' ? false : merge; 
5208         
5209         this.scope.undoManager.transact({
5210             scope : this.scope,
5211             oldHTML: this.current_html,
5212             newHTML: this.scope.innerHTML,
5213             // nothing to execute (content already changed when input is fired)
5214             execute: function() { },
5215             undo: function() {
5216                 this.scope.innerHTML = this.current_html = this.oldHTML;
5217             },
5218             redo: function() {
5219                 this.scope.innerHTML = this.current_html = this.newHTML;
5220             }
5221         }, false); //merge);
5222         
5223         this.merge = merge;
5224         
5225         this.current_html = this.scope.innerHTML;
5226     }
5227     
5228     
5229      
5230     
5231     
5232     
5233 };
5234 /**
5235  * @class Roo.lib.Range
5236  * @constructor
5237  * This is a toolkit, normally used to copy features into a Dom Range element
5238  * Roo.lib.Range.wrap(x);
5239  *
5240  *
5241  *
5242  */
5243 Roo.lib.Range = function() { };
5244
5245 /**
5246  * Wrap a Dom Range object, to give it new features...
5247  * @static
5248  * @param {Range} the range to wrap
5249  */
5250 Roo.lib.Range.wrap = function(r) {
5251     return Roo.apply(r, Roo.lib.Range.prototype);
5252 };
5253 /**
5254  * find a parent node eg. LI / OL
5255  * @param {string|Array} node name or array of nodenames
5256  * @return {DomElement|false}
5257  */
5258 Roo.apply(Roo.lib.Range.prototype,
5259 {
5260     
5261     closest : function(str)
5262     {
5263         if (typeof(str) != 'string') {
5264             // assume it's a array.
5265             for(var i = 0;i < str.length;i++) {
5266                 var r = this.closest(str[i]);
5267                 if (r !== false) {
5268                     return r;
5269                 }
5270                 
5271             }
5272             return false;
5273         }
5274         str = str.toLowerCase();
5275         var n = this.commonAncestorContainer; // might not be a node
5276         while (n.nodeType != 1) {
5277             n = n.parentNode;
5278         }
5279         
5280         if (n.nodeName.toLowerCase() == str ) {
5281             return n;
5282         }
5283         if (n.nodeName.toLowerCase() == 'body') {
5284             return false;
5285         }
5286             
5287         return n.closest(str) || false;
5288         
5289     },
5290     cloneRange : function()
5291     {
5292         return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
5293     }
5294 });/**
5295  * @class Roo.lib.Selection
5296  * @constructor
5297  * This is a toolkit, normally used to copy features into a Dom Selection element
5298  * Roo.lib.Selection.wrap(x);
5299  *
5300  *
5301  *
5302  */
5303 Roo.lib.Selection = function() { };
5304
5305 /**
5306  * Wrap a Dom Range object, to give it new features...
5307  * @static
5308  * @param {Range} the range to wrap
5309  */
5310 Roo.lib.Selection.wrap = function(r, doc) {
5311     Roo.apply(r, Roo.lib.Selection.prototype);
5312     r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
5313     return r;
5314 };
5315 /**
5316  * find a parent node eg. LI / OL
5317  * @param {string|Array} node name or array of nodenames
5318  * @return {DomElement|false}
5319  */
5320 Roo.apply(Roo.lib.Selection.prototype,
5321 {
5322     /**
5323      * the owner document
5324      */
5325     ownerDocument : false,
5326     
5327     getRangeAt : function(n)
5328     {
5329         return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
5330     },
5331     
5332     /**
5333      * insert node at selection 
5334      * @param {DomElement|string} node
5335      * @param {string} cursor (after|in|none) where to place the cursor after inserting.
5336      */
5337     insertNode: function(node, cursor)
5338     {
5339         if (typeof(node) == 'string') {
5340             node = this.ownerDocument.createElement(node);
5341             if (cursor == 'in') {
5342                 node.innerHTML = '&nbsp;';
5343             }
5344         }
5345         
5346         var range = this.getRangeAt(0);
5347         
5348         if (this.type != 'Caret') {
5349             range.deleteContents();
5350         }
5351         var sn = node.childNodes[0]; // select the contents.
5352
5353         
5354         
5355         range.insertNode(node);
5356         if (cursor == 'after') {
5357             node.insertAdjacentHTML('afterend', '&nbsp;');
5358             sn = node.nextSibling;
5359         }
5360         
5361         if (cursor == 'none') {
5362             return;
5363         }
5364         
5365         this.cursorText(sn);
5366     },
5367     
5368     cursorText : function(n)
5369     {
5370        
5371         //var range = this.getRangeAt(0);
5372         range = Roo.lib.Range.wrap(new Range());
5373         //range.selectNode(n);
5374         
5375         var ix = Array.from(n.parentNode.childNodes).indexOf(n);
5376         range.setStart(n.parentNode,ix);
5377         range.setEnd(n.parentNode,ix+1);
5378         //range.collapse(false);
5379          
5380         this.removeAllRanges();
5381         this.addRange(range);
5382         
5383         Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
5384     },
5385     cursorAfter : function(n)
5386     {
5387         if (!n.nextSibling || n.nextSibling.nodeValue != '&nbsp;') {
5388             n.insertAdjacentHTML('afterend', '&nbsp;');
5389         }
5390         this.cursorText (n.nextSibling);
5391     }
5392         
5393     
5394 });/*
5395  * Based on:
5396  * Ext JS Library 1.1.1
5397  * Copyright(c) 2006-2007, Ext JS, LLC.
5398  *
5399  * Originally Released Under LGPL - original licence link has changed is not relivant.
5400  *
5401  * Fork - LGPL
5402  * <script type="text/javascript">
5403  */
5404
5405
5406 // nasty IE9 hack - what a pile of crap that is..
5407
5408  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5409     Range.prototype.createContextualFragment = function (html) {
5410         var doc = window.document;
5411         var container = doc.createElement("div");
5412         container.innerHTML = html;
5413         var frag = doc.createDocumentFragment(), n;
5414         while ((n = container.firstChild)) {
5415             frag.appendChild(n);
5416         }
5417         return frag;
5418     };
5419 }
5420
5421 /**
5422  * @class Roo.DomHelper
5423  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5424  * 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>.
5425  * @static
5426  */
5427 Roo.DomHelper = function(){
5428     var tempTableEl = null;
5429     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5430     var tableRe = /^table|tbody|tr|td$/i;
5431     var xmlns = {};
5432     // build as innerHTML where available
5433     /** @ignore */
5434     var createHtml = function(o){
5435         if(typeof o == 'string'){
5436             return o;
5437         }
5438         var b = "";
5439         if(!o.tag){
5440             o.tag = "div";
5441         }
5442         b += "<" + o.tag;
5443         for(var attr in o){
5444             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5445             if(attr == "style"){
5446                 var s = o["style"];
5447                 if(typeof s == "function"){
5448                     s = s.call();
5449                 }
5450                 if(typeof s == "string"){
5451                     b += ' style="' + s + '"';
5452                 }else if(typeof s == "object"){
5453                     b += ' style="';
5454                     for(var key in s){
5455                         if(typeof s[key] != "function"){
5456                             b += key + ":" + s[key] + ";";
5457                         }
5458                     }
5459                     b += '"';
5460                 }
5461             }else{
5462                 if(attr == "cls"){
5463                     b += ' class="' + o["cls"] + '"';
5464                 }else if(attr == "htmlFor"){
5465                     b += ' for="' + o["htmlFor"] + '"';
5466                 }else{
5467                     b += " " + attr + '="' + o[attr] + '"';
5468                 }
5469             }
5470         }
5471         if(emptyTags.test(o.tag)){
5472             b += "/>";
5473         }else{
5474             b += ">";
5475             var cn = o.children || o.cn;
5476             if(cn){
5477                 //http://bugs.kde.org/show_bug.cgi?id=71506
5478                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5479                     for(var i = 0, len = cn.length; i < len; i++) {
5480                         b += createHtml(cn[i], b);
5481                     }
5482                 }else{
5483                     b += createHtml(cn, b);
5484                 }
5485             }
5486             if(o.html){
5487                 b += o.html;
5488             }
5489             b += "</" + o.tag + ">";
5490         }
5491         return b;
5492     };
5493
5494     // build as dom
5495     /** @ignore */
5496     var createDom = function(o, parentNode){
5497          
5498         // defininition craeted..
5499         var ns = false;
5500         if (o.ns && o.ns != 'html') {
5501                
5502             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5503                 xmlns[o.ns] = o.xmlns;
5504                 ns = o.xmlns;
5505             }
5506             if (typeof(xmlns[o.ns]) == 'undefined') {
5507                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5508             }
5509             ns = xmlns[o.ns];
5510         }
5511         
5512         
5513         if (typeof(o) == 'string') {
5514             return parentNode.appendChild(document.createTextNode(o));
5515         }
5516         o.tag = o.tag || div;
5517         if (o.ns && Roo.isIE) {
5518             ns = false;
5519             o.tag = o.ns + ':' + o.tag;
5520             
5521         }
5522         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5523         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5524         for(var attr in o){
5525             
5526             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5527                     attr == "style" || typeof o[attr] == "function") { continue; }
5528                     
5529             if(attr=="cls" && Roo.isIE){
5530                 el.className = o["cls"];
5531             }else{
5532                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5533                 else { 
5534                     el[attr] = o[attr];
5535                 }
5536             }
5537         }
5538         Roo.DomHelper.applyStyles(el, o.style);
5539         var cn = o.children || o.cn;
5540         if(cn){
5541             //http://bugs.kde.org/show_bug.cgi?id=71506
5542              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5543                 for(var i = 0, len = cn.length; i < len; i++) {
5544                     createDom(cn[i], el);
5545                 }
5546             }else{
5547                 createDom(cn, el);
5548             }
5549         }
5550         if(o.html){
5551             el.innerHTML = o.html;
5552         }
5553         if(parentNode){
5554            parentNode.appendChild(el);
5555         }
5556         return el;
5557     };
5558
5559     var ieTable = function(depth, s, h, e){
5560         tempTableEl.innerHTML = [s, h, e].join('');
5561         var i = -1, el = tempTableEl;
5562         while(++i < depth && el.firstChild){
5563             el = el.firstChild;
5564         }
5565         return el;
5566     };
5567
5568     // kill repeat to save bytes
5569     var ts = '<table>',
5570         te = '</table>',
5571         tbs = ts+'<tbody>',
5572         tbe = '</tbody>'+te,
5573         trs = tbs + '<tr>',
5574         tre = '</tr>'+tbe;
5575
5576     /**
5577      * @ignore
5578      * Nasty code for IE's broken table implementation
5579      */
5580     var insertIntoTable = function(tag, where, el, html){
5581         if(!tempTableEl){
5582             tempTableEl = document.createElement('div');
5583         }
5584         var node;
5585         var before = null;
5586         if(tag == 'td'){
5587             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5588                 return;
5589             }
5590             if(where == 'beforebegin'){
5591                 before = el;
5592                 el = el.parentNode;
5593             } else{
5594                 before = el.nextSibling;
5595                 el = el.parentNode;
5596             }
5597             node = ieTable(4, trs, html, tre);
5598         }
5599         else if(tag == 'tr'){
5600             if(where == 'beforebegin'){
5601                 before = el;
5602                 el = el.parentNode;
5603                 node = ieTable(3, tbs, html, tbe);
5604             } else if(where == 'afterend'){
5605                 before = el.nextSibling;
5606                 el = el.parentNode;
5607                 node = ieTable(3, tbs, html, tbe);
5608             } else{ // INTO a TR
5609                 if(where == 'afterbegin'){
5610                     before = el.firstChild;
5611                 }
5612                 node = ieTable(4, trs, html, tre);
5613             }
5614         } else if(tag == 'tbody'){
5615             if(where == 'beforebegin'){
5616                 before = el;
5617                 el = el.parentNode;
5618                 node = ieTable(2, ts, html, te);
5619             } else if(where == 'afterend'){
5620                 before = el.nextSibling;
5621                 el = el.parentNode;
5622                 node = ieTable(2, ts, html, te);
5623             } else{
5624                 if(where == 'afterbegin'){
5625                     before = el.firstChild;
5626                 }
5627                 node = ieTable(3, tbs, html, tbe);
5628             }
5629         } else{ // TABLE
5630             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5631                 return;
5632             }
5633             if(where == 'afterbegin'){
5634                 before = el.firstChild;
5635             }
5636             node = ieTable(2, ts, html, te);
5637         }
5638         el.insertBefore(node, before);
5639         return node;
5640     };
5641     
5642     // this is a bit like the react update code...
5643     // 
5644     
5645     var updateNode = function(from, to)
5646     {
5647         // should we handle non-standard elements?
5648         Roo.log(["UpdateNode" , from, to]);
5649         if (from.nodeType != to.nodeType) {
5650             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5651             from.parentNode.replaceChild(to, from);
5652         }
5653         
5654         if (from.nodeType == 3) {
5655             // assume it's text?!
5656             if (from.data == to.data) {
5657                 return;
5658             }
5659             from.data = to.data;
5660             return;
5661         }
5662         if (!from.parentNode) {
5663             // not sure why this is happening?
5664             return;
5665         }
5666         // assume 'to' doesnt have '1/3 nodetypes!
5667         // not sure why, by from, parent node might not exist?
5668         if (from.nodeType !=1 || from.tagName != to.tagName) {
5669             Roo.log(["ReplaceChild" , from, to ]);
5670             
5671             from.parentNode.replaceChild(to, from);
5672             return;
5673         }
5674         // compare attributes
5675         var ar = Array.from(from.attributes);
5676         for(var i = 0; i< ar.length;i++) {
5677             if (to.hasAttribute(ar[i].name)) {
5678                 continue;
5679             }
5680             if (ar[i].name == 'id') { // always keep ids?
5681                continue;
5682             }
5683             //if (ar[i].name == 'style') {
5684             //   throw "style removed?";
5685             //}
5686             Roo.log("removeAttribute" + ar[i].name);
5687             from.removeAttribute(ar[i].name);
5688         }
5689         ar = to.attributes;
5690         for(var i = 0; i< ar.length;i++) {
5691             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5692                 Roo.log("skipAttribute " + ar[i].name  + '=' + to.getAttribute(ar[i].name));
5693                 continue;
5694             }
5695             Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5696             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5697         }
5698         // children
5699         var far = Array.from(from.childNodes);
5700         var tar = Array.from(to.childNodes);
5701         // if the lengths are different.. then it's probably a editable content change, rather than
5702         // a change of the block definition..
5703         
5704         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5705          /*if (from.innerHTML == to.innerHTML) {
5706             return;
5707         }
5708         if (far.length != tar.length) {
5709             from.innerHTML = to.innerHTML;
5710             return;
5711         }
5712         */
5713         
5714         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5715             if (i >= far.length) {
5716                 from.appendChild(tar[i]);
5717                 Roo.log(["add", tar[i]]);
5718                 
5719             } else if ( i  >= tar.length) {
5720                 from.removeChild(far[i]);
5721                 Roo.log(["remove", far[i]]);
5722             } else {
5723                 
5724                 updateNode(far[i], tar[i]);
5725             }    
5726         }
5727         
5728         
5729         
5730         
5731     };
5732     
5733     
5734
5735     return {
5736         /** True to force the use of DOM instead of html fragments @type Boolean */
5737         useDom : false,
5738     
5739         /**
5740          * Returns the markup for the passed Element(s) config
5741          * @param {Object} o The Dom object spec (and children)
5742          * @return {String}
5743          */
5744         markup : function(o){
5745             return createHtml(o);
5746         },
5747     
5748         /**
5749          * Applies a style specification to an element
5750          * @param {String/HTMLElement} el The element to apply styles to
5751          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5752          * a function which returns such a specification.
5753          */
5754         applyStyles : function(el, styles){
5755             if(styles){
5756                el = Roo.fly(el);
5757                if(typeof styles == "string"){
5758                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5759                    var matches;
5760                    while ((matches = re.exec(styles)) != null){
5761                        el.setStyle(matches[1], matches[2]);
5762                    }
5763                }else if (typeof styles == "object"){
5764                    for (var style in styles){
5765                       el.setStyle(style, styles[style]);
5766                    }
5767                }else if (typeof styles == "function"){
5768                     Roo.DomHelper.applyStyles(el, styles.call());
5769                }
5770             }
5771         },
5772     
5773         /**
5774          * Inserts an HTML fragment into the Dom
5775          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5776          * @param {HTMLElement} el The context element
5777          * @param {String} html The HTML fragmenet
5778          * @return {HTMLElement} The new node
5779          */
5780         insertHtml : function(where, el, html){
5781             where = where.toLowerCase();
5782             if(el.insertAdjacentHTML){
5783                 if(tableRe.test(el.tagName)){
5784                     var rs;
5785                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5786                         return rs;
5787                     }
5788                 }
5789                 switch(where){
5790                     case "beforebegin":
5791                         el.insertAdjacentHTML('BeforeBegin', html);
5792                         return el.previousSibling;
5793                     case "afterbegin":
5794                         el.insertAdjacentHTML('AfterBegin', html);
5795                         return el.firstChild;
5796                     case "beforeend":
5797                         el.insertAdjacentHTML('BeforeEnd', html);
5798                         return el.lastChild;
5799                     case "afterend":
5800                         el.insertAdjacentHTML('AfterEnd', html);
5801                         return el.nextSibling;
5802                 }
5803                 throw 'Illegal insertion point -> "' + where + '"';
5804             }
5805             var range = el.ownerDocument.createRange();
5806             var frag;
5807             switch(where){
5808                  case "beforebegin":
5809                     range.setStartBefore(el);
5810                     frag = range.createContextualFragment(html);
5811                     el.parentNode.insertBefore(frag, el);
5812                     return el.previousSibling;
5813                  case "afterbegin":
5814                     if(el.firstChild){
5815                         range.setStartBefore(el.firstChild);
5816                         frag = range.createContextualFragment(html);
5817                         el.insertBefore(frag, el.firstChild);
5818                         return el.firstChild;
5819                     }else{
5820                         el.innerHTML = html;
5821                         return el.firstChild;
5822                     }
5823                 case "beforeend":
5824                     if(el.lastChild){
5825                         range.setStartAfter(el.lastChild);
5826                         frag = range.createContextualFragment(html);
5827                         el.appendChild(frag);
5828                         return el.lastChild;
5829                     }else{
5830                         el.innerHTML = html;
5831                         return el.lastChild;
5832                     }
5833                 case "afterend":
5834                     range.setStartAfter(el);
5835                     frag = range.createContextualFragment(html);
5836                     el.parentNode.insertBefore(frag, el.nextSibling);
5837                     return el.nextSibling;
5838                 }
5839                 throw 'Illegal insertion point -> "' + where + '"';
5840         },
5841     
5842         /**
5843          * Creates new Dom element(s) and inserts them before el
5844          * @param {String/HTMLElement/Element} el The context element
5845          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5846          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5847          * @return {HTMLElement/Roo.Element} The new node
5848          */
5849         insertBefore : function(el, o, returnElement){
5850             return this.doInsert(el, o, returnElement, "beforeBegin");
5851         },
5852     
5853         /**
5854          * Creates new Dom element(s) and inserts them after el
5855          * @param {String/HTMLElement/Element} el The context element
5856          * @param {Object} o The Dom object spec (and children)
5857          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5858          * @return {HTMLElement/Roo.Element} The new node
5859          */
5860         insertAfter : function(el, o, returnElement){
5861             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5862         },
5863     
5864         /**
5865          * Creates new Dom element(s) and inserts them as the first child of el
5866          * @param {String/HTMLElement/Element} el The context element
5867          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5868          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5869          * @return {HTMLElement/Roo.Element} The new node
5870          */
5871         insertFirst : function(el, o, returnElement){
5872             return this.doInsert(el, o, returnElement, "afterBegin");
5873         },
5874     
5875         // private
5876         doInsert : function(el, o, returnElement, pos, sibling){
5877             el = Roo.getDom(el);
5878             var newNode;
5879             if(this.useDom || o.ns){
5880                 newNode = createDom(o, null);
5881                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5882             }else{
5883                 var html = createHtml(o);
5884                 newNode = this.insertHtml(pos, el, html);
5885             }
5886             return returnElement ? Roo.get(newNode, true) : newNode;
5887         },
5888     
5889         /**
5890          * Creates new Dom element(s) and appends them to el
5891          * @param {String/HTMLElement/Element} el The context element
5892          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5893          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5894          * @return {HTMLElement/Roo.Element} The new node
5895          */
5896         append : function(el, o, returnElement){
5897             el = Roo.getDom(el);
5898             var newNode;
5899             if(this.useDom || o.ns){
5900                 newNode = createDom(o, null);
5901                 el.appendChild(newNode);
5902             }else{
5903                 var html = createHtml(o);
5904                 newNode = this.insertHtml("beforeEnd", el, html);
5905             }
5906             return returnElement ? Roo.get(newNode, true) : newNode;
5907         },
5908     
5909         /**
5910          * Creates new Dom element(s) and overwrites the contents of el with them
5911          * @param {String/HTMLElement/Element} el The context element
5912          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5913          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5914          * @return {HTMLElement/Roo.Element} The new node
5915          */
5916         overwrite : function(el, o, returnElement)
5917         {
5918             el = Roo.getDom(el);
5919             if (o.ns) {
5920               
5921                 while (el.childNodes.length) {
5922                     el.removeChild(el.firstChild);
5923                 }
5924                 createDom(o, el);
5925             } else {
5926                 el.innerHTML = createHtml(o);   
5927             }
5928             
5929             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5930         },
5931     
5932         /**
5933          * Creates a new Roo.DomHelper.Template from the Dom object spec
5934          * @param {Object} o The Dom object spec (and children)
5935          * @return {Roo.DomHelper.Template} The new template
5936          */
5937         createTemplate : function(o){
5938             var html = createHtml(o);
5939             return new Roo.Template(html);
5940         },
5941          /**
5942          * Updates the first element with the spec from the o (replacing if necessary)
5943          * This iterates through the children, and updates attributes / children etc..
5944          * @param {String/HTMLElement/Element} el The context element
5945          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5946          */
5947         
5948         update : function(el, o)
5949         {
5950             updateNode(Roo.getDom(el), createDom(o));
5951             
5952         }
5953         
5954         
5955     };
5956 }();
5957 /*
5958  * Based on:
5959  * Ext JS Library 1.1.1
5960  * Copyright(c) 2006-2007, Ext JS, LLC.
5961  *
5962  * Originally Released Under LGPL - original licence link has changed is not relivant.
5963  *
5964  * Fork - LGPL
5965  * <script type="text/javascript">
5966  */
5967  
5968 /**
5969 * @class Roo.Template
5970 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5971 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5972 * Usage:
5973 <pre><code>
5974 var t = new Roo.Template({
5975     html :  '&lt;div name="{id}"&gt;' + 
5976         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5977         '&lt;/div&gt;',
5978     myformat: function (value, allValues) {
5979         return 'XX' + value;
5980     }
5981 });
5982 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5983 </code></pre>
5984 * For more information see this blog post with examples:
5985 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5986      - Create Elements using DOM, HTML fragments and Templates</a>. 
5987 * @constructor
5988 * @param {Object} cfg - Configuration object.
5989 */
5990 Roo.Template = function(cfg){
5991     // BC!
5992     if(cfg instanceof Array){
5993         cfg = cfg.join("");
5994     }else if(arguments.length > 1){
5995         cfg = Array.prototype.join.call(arguments, "");
5996     }
5997     
5998     
5999     if (typeof(cfg) == 'object') {
6000         Roo.apply(this,cfg)
6001     } else {
6002         // bc
6003         this.html = cfg;
6004     }
6005     if (this.url) {
6006         this.load();
6007     }
6008     
6009 };
6010 Roo.Template.prototype = {
6011     
6012     /**
6013      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
6014      */
6015     onLoad : false,
6016     
6017     
6018     /**
6019      * @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..
6020      *                    it should be fixed so that template is observable...
6021      */
6022     url : false,
6023     /**
6024      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
6025      */
6026     html : '',
6027     
6028     
6029     compiled : false,
6030     loaded : false,
6031     /**
6032      * Returns an HTML fragment of this template with the specified values applied.
6033      * @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'})
6034      * @return {String} The HTML fragment
6035      */
6036     
6037    
6038     
6039     applyTemplate : function(values){
6040         //Roo.log(["applyTemplate", values]);
6041         try {
6042            
6043             if(this.compiled){
6044                 return this.compiled(values);
6045             }
6046             var useF = this.disableFormats !== true;
6047             var fm = Roo.util.Format, tpl = this;
6048             var fn = function(m, name, format, args){
6049                 if(format && useF){
6050                     if(format.substr(0, 5) == "this."){
6051                         return tpl.call(format.substr(5), values[name], values);
6052                     }else{
6053                         if(args){
6054                             // quoted values are required for strings in compiled templates, 
6055                             // but for non compiled we need to strip them
6056                             // quoted reversed for jsmin
6057                             var re = /^\s*['"](.*)["']\s*$/;
6058                             args = args.split(',');
6059                             for(var i = 0, len = args.length; i < len; i++){
6060                                 args[i] = args[i].replace(re, "$1");
6061                             }
6062                             args = [values[name]].concat(args);
6063                         }else{
6064                             args = [values[name]];
6065                         }
6066                         return fm[format].apply(fm, args);
6067                     }
6068                 }else{
6069                     return values[name] !== undefined ? values[name] : "";
6070                 }
6071             };
6072             return this.html.replace(this.re, fn);
6073         } catch (e) {
6074             Roo.log(e);
6075             throw e;
6076         }
6077          
6078     },
6079     
6080     loading : false,
6081       
6082     load : function ()
6083     {
6084          
6085         if (this.loading) {
6086             return;
6087         }
6088         var _t = this;
6089         
6090         this.loading = true;
6091         this.compiled = false;
6092         
6093         var cx = new Roo.data.Connection();
6094         cx.request({
6095             url : this.url,
6096             method : 'GET',
6097             success : function (response) {
6098                 _t.loading = false;
6099                 _t.url = false;
6100                 
6101                 _t.set(response.responseText,true);
6102                 _t.loaded = true;
6103                 if (_t.onLoad) {
6104                     _t.onLoad();
6105                 }
6106              },
6107             failure : function(response) {
6108                 Roo.log("Template failed to load from " + _t.url);
6109                 _t.loading = false;
6110             }
6111         });
6112     },
6113
6114     /**
6115      * Sets the HTML used as the template and optionally compiles it.
6116      * @param {String} html
6117      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
6118      * @return {Roo.Template} this
6119      */
6120     set : function(html, compile){
6121         this.html = html;
6122         this.compiled = false;
6123         if(compile){
6124             this.compile();
6125         }
6126         return this;
6127     },
6128     
6129     /**
6130      * True to disable format functions (defaults to false)
6131      * @type Boolean
6132      */
6133     disableFormats : false,
6134     
6135     /**
6136     * The regular expression used to match template variables 
6137     * @type RegExp
6138     * @property 
6139     */
6140     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
6141     
6142     /**
6143      * Compiles the template into an internal function, eliminating the RegEx overhead.
6144      * @return {Roo.Template} this
6145      */
6146     compile : function(){
6147         var fm = Roo.util.Format;
6148         var useF = this.disableFormats !== true;
6149         var sep = Roo.isGecko ? "+" : ",";
6150         var fn = function(m, name, format, args){
6151             if(format && useF){
6152                 args = args ? ',' + args : "";
6153                 if(format.substr(0, 5) != "this."){
6154                     format = "fm." + format + '(';
6155                 }else{
6156                     format = 'this.call("'+ format.substr(5) + '", ';
6157                     args = ", values";
6158                 }
6159             }else{
6160                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
6161             }
6162             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
6163         };
6164         var body;
6165         // branched to use + in gecko and [].join() in others
6166         if(Roo.isGecko){
6167             body = "this.compiled = function(values){ return '" +
6168                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
6169                     "';};";
6170         }else{
6171             body = ["this.compiled = function(values){ return ['"];
6172             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
6173             body.push("'].join('');};");
6174             body = body.join('');
6175         }
6176         /**
6177          * eval:var:values
6178          * eval:var:fm
6179          */
6180         eval(body);
6181         return this;
6182     },
6183     
6184     // private function used to call members
6185     call : function(fnName, value, allValues){
6186         return this[fnName](value, allValues);
6187     },
6188     
6189     /**
6190      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
6191      * @param {String/HTMLElement/Roo.Element} el The context element
6192      * @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'})
6193      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6194      * @return {HTMLElement/Roo.Element} The new node or Element
6195      */
6196     insertFirst: function(el, values, returnElement){
6197         return this.doInsert('afterBegin', el, values, returnElement);
6198     },
6199
6200     /**
6201      * Applies the supplied values to the template and inserts the new node(s) before el.
6202      * @param {String/HTMLElement/Roo.Element} el The context element
6203      * @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'})
6204      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6205      * @return {HTMLElement/Roo.Element} The new node or Element
6206      */
6207     insertBefore: function(el, values, returnElement){
6208         return this.doInsert('beforeBegin', el, values, returnElement);
6209     },
6210
6211     /**
6212      * Applies the supplied values to the template and inserts the new node(s) after el.
6213      * @param {String/HTMLElement/Roo.Element} el The context element
6214      * @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'})
6215      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6216      * @return {HTMLElement/Roo.Element} The new node or Element
6217      */
6218     insertAfter : function(el, values, returnElement){
6219         return this.doInsert('afterEnd', el, values, returnElement);
6220     },
6221     
6222     /**
6223      * Applies the supplied values to the template and appends the new node(s) to el.
6224      * @param {String/HTMLElement/Roo.Element} el The context element
6225      * @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'})
6226      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6227      * @return {HTMLElement/Roo.Element} The new node or Element
6228      */
6229     append : function(el, values, returnElement){
6230         return this.doInsert('beforeEnd', el, values, returnElement);
6231     },
6232
6233     doInsert : function(where, el, values, returnEl){
6234         el = Roo.getDom(el);
6235         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6236         return returnEl ? Roo.get(newNode, true) : newNode;
6237     },
6238
6239     /**
6240      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6241      * @param {String/HTMLElement/Roo.Element} el The context element
6242      * @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'})
6243      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6244      * @return {HTMLElement/Roo.Element} The new node or Element
6245      */
6246     overwrite : function(el, values, returnElement){
6247         el = Roo.getDom(el);
6248         el.innerHTML = this.applyTemplate(values);
6249         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6250     }
6251 };
6252 /**
6253  * Alias for {@link #applyTemplate}
6254  * @method
6255  */
6256 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6257
6258 // backwards compat
6259 Roo.DomHelper.Template = Roo.Template;
6260
6261 /**
6262  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6263  * @param {String/HTMLElement} el A DOM element or its id
6264  * @returns {Roo.Template} The created template
6265  * @static
6266  */
6267 Roo.Template.from = function(el){
6268     el = Roo.getDom(el);
6269     return new Roo.Template(el.value || el.innerHTML);
6270 };/*
6271  * Based on:
6272  * Ext JS Library 1.1.1
6273  * Copyright(c) 2006-2007, Ext JS, LLC.
6274  *
6275  * Originally Released Under LGPL - original licence link has changed is not relivant.
6276  *
6277  * Fork - LGPL
6278  * <script type="text/javascript">
6279  */
6280  
6281
6282 /*
6283  * This is code is also distributed under MIT license for use
6284  * with jQuery and prototype JavaScript libraries.
6285  */
6286 /**
6287  * @class Roo.DomQuery
6288 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).
6289 <p>
6290 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>
6291
6292 <p>
6293 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.
6294 </p>
6295 <h4>Element Selectors:</h4>
6296 <ul class="list">
6297     <li> <b>*</b> any element</li>
6298     <li> <b>E</b> an element with the tag E</li>
6299     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6300     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6301     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6302     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6303 </ul>
6304 <h4>Attribute Selectors:</h4>
6305 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6306 <ul class="list">
6307     <li> <b>E[foo]</b> has an attribute "foo"</li>
6308     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6309     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6310     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6311     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6312     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6313     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6314 </ul>
6315 <h4>Pseudo Classes:</h4>
6316 <ul class="list">
6317     <li> <b>E:first-child</b> E is the first child of its parent</li>
6318     <li> <b>E:last-child</b> E is the last child of its parent</li>
6319     <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>
6320     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6321     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6322     <li> <b>E:only-child</b> E is the only child of its parent</li>
6323     <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>
6324     <li> <b>E:first</b> the first E in the resultset</li>
6325     <li> <b>E:last</b> the last E in the resultset</li>
6326     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6327     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6328     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6329     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6330     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6331     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6332     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6333     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6334     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6335 </ul>
6336 <h4>CSS Value Selectors:</h4>
6337 <ul class="list">
6338     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6339     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6340     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6341     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6342     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6343     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6344 </ul>
6345  * @static
6346  */
6347 Roo.DomQuery = function(){
6348     var cache = {}, simpleCache = {}, valueCache = {};
6349     var nonSpace = /\S/;
6350     var trimRe = /^\s+|\s+$/g;
6351     var tplRe = /\{(\d+)\}/g;
6352     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6353     var tagTokenRe = /^(#)?([\w-\*]+)/;
6354     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6355
6356     function child(p, index){
6357         var i = 0;
6358         var n = p.firstChild;
6359         while(n){
6360             if(n.nodeType == 1){
6361                if(++i == index){
6362                    return n;
6363                }
6364             }
6365             n = n.nextSibling;
6366         }
6367         return null;
6368     };
6369
6370     function next(n){
6371         while((n = n.nextSibling) && n.nodeType != 1);
6372         return n;
6373     };
6374
6375     function prev(n){
6376         while((n = n.previousSibling) && n.nodeType != 1);
6377         return n;
6378     };
6379
6380     function children(d){
6381         var n = d.firstChild, ni = -1;
6382             while(n){
6383                 var nx = n.nextSibling;
6384                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6385                     d.removeChild(n);
6386                 }else{
6387                     n.nodeIndex = ++ni;
6388                 }
6389                 n = nx;
6390             }
6391             return this;
6392         };
6393
6394     function byClassName(c, a, v){
6395         if(!v){
6396             return c;
6397         }
6398         var r = [], ri = -1, cn;
6399         for(var i = 0, ci; ci = c[i]; i++){
6400             
6401             
6402             if((' '+
6403                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6404                  +' ').indexOf(v) != -1){
6405                 r[++ri] = ci;
6406             }
6407         }
6408         return r;
6409     };
6410
6411     function attrValue(n, attr){
6412         if(!n.tagName && typeof n.length != "undefined"){
6413             n = n[0];
6414         }
6415         if(!n){
6416             return null;
6417         }
6418         if(attr == "for"){
6419             return n.htmlFor;
6420         }
6421         if(attr == "class" || attr == "className"){
6422             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6423         }
6424         return n.getAttribute(attr) || n[attr];
6425
6426     };
6427
6428     function getNodes(ns, mode, tagName){
6429         var result = [], ri = -1, cs;
6430         if(!ns){
6431             return result;
6432         }
6433         tagName = tagName || "*";
6434         if(typeof ns.getElementsByTagName != "undefined"){
6435             ns = [ns];
6436         }
6437         if(!mode){
6438             for(var i = 0, ni; ni = ns[i]; i++){
6439                 cs = ni.getElementsByTagName(tagName);
6440                 for(var j = 0, ci; ci = cs[j]; j++){
6441                     result[++ri] = ci;
6442                 }
6443             }
6444         }else if(mode == "/" || mode == ">"){
6445             var utag = tagName.toUpperCase();
6446             for(var i = 0, ni, cn; ni = ns[i]; i++){
6447                 cn = ni.children || ni.childNodes;
6448                 for(var j = 0, cj; cj = cn[j]; j++){
6449                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
6450                         result[++ri] = cj;
6451                     }
6452                 }
6453             }
6454         }else if(mode == "+"){
6455             var utag = tagName.toUpperCase();
6456             for(var i = 0, n; n = ns[i]; i++){
6457                 while((n = n.nextSibling) && n.nodeType != 1);
6458                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6459                     result[++ri] = n;
6460                 }
6461             }
6462         }else if(mode == "~"){
6463             for(var i = 0, n; n = ns[i]; i++){
6464                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6465                 if(n){
6466                     result[++ri] = n;
6467                 }
6468             }
6469         }
6470         return result;
6471     };
6472
6473     function concat(a, b){
6474         if(b.slice){
6475             return a.concat(b);
6476         }
6477         for(var i = 0, l = b.length; i < l; i++){
6478             a[a.length] = b[i];
6479         }
6480         return a;
6481     }
6482
6483     function byTag(cs, tagName){
6484         if(cs.tagName || cs == document){
6485             cs = [cs];
6486         }
6487         if(!tagName){
6488             return cs;
6489         }
6490         var r = [], ri = -1;
6491         tagName = tagName.toLowerCase();
6492         for(var i = 0, ci; ci = cs[i]; i++){
6493             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6494                 r[++ri] = ci;
6495             }
6496         }
6497         return r;
6498     };
6499
6500     function byId(cs, attr, id){
6501         if(cs.tagName || cs == document){
6502             cs = [cs];
6503         }
6504         if(!id){
6505             return cs;
6506         }
6507         var r = [], ri = -1;
6508         for(var i = 0,ci; ci = cs[i]; i++){
6509             if(ci && ci.id == id){
6510                 r[++ri] = ci;
6511                 return r;
6512             }
6513         }
6514         return r;
6515     };
6516
6517     function byAttribute(cs, attr, value, op, custom){
6518         var r = [], ri = -1, st = custom=="{";
6519         var f = Roo.DomQuery.operators[op];
6520         for(var i = 0, ci; ci = cs[i]; i++){
6521             var a;
6522             if(st){
6523                 a = Roo.DomQuery.getStyle(ci, attr);
6524             }
6525             else if(attr == "class" || attr == "className"){
6526                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6527             }else if(attr == "for"){
6528                 a = ci.htmlFor;
6529             }else if(attr == "href"){
6530                 a = ci.getAttribute("href", 2);
6531             }else{
6532                 a = ci.getAttribute(attr);
6533             }
6534             if((f && f(a, value)) || (!f && a)){
6535                 r[++ri] = ci;
6536             }
6537         }
6538         return r;
6539     };
6540
6541     function byPseudo(cs, name, value){
6542         return Roo.DomQuery.pseudos[name](cs, value);
6543     };
6544
6545     // This is for IE MSXML which does not support expandos.
6546     // IE runs the same speed using setAttribute, however FF slows way down
6547     // and Safari completely fails so they need to continue to use expandos.
6548     var isIE = window.ActiveXObject ? true : false;
6549
6550     // this eval is stop the compressor from
6551     // renaming the variable to something shorter
6552     
6553     /** eval:var:batch */
6554     var batch = 30803; 
6555
6556     var key = 30803;
6557
6558     function nodupIEXml(cs){
6559         var d = ++key;
6560         cs[0].setAttribute("_nodup", d);
6561         var r = [cs[0]];
6562         for(var i = 1, len = cs.length; i < len; i++){
6563             var c = cs[i];
6564             if(!c.getAttribute("_nodup") != d){
6565                 c.setAttribute("_nodup", d);
6566                 r[r.length] = c;
6567             }
6568         }
6569         for(var i = 0, len = cs.length; i < len; i++){
6570             cs[i].removeAttribute("_nodup");
6571         }
6572         return r;
6573     }
6574
6575     function nodup(cs){
6576         if(!cs){
6577             return [];
6578         }
6579         var len = cs.length, c, i, r = cs, cj, ri = -1;
6580         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6581             return cs;
6582         }
6583         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6584             return nodupIEXml(cs);
6585         }
6586         var d = ++key;
6587         cs[0]._nodup = d;
6588         for(i = 1; c = cs[i]; i++){
6589             if(c._nodup != d){
6590                 c._nodup = d;
6591             }else{
6592                 r = [];
6593                 for(var j = 0; j < i; j++){
6594                     r[++ri] = cs[j];
6595                 }
6596                 for(j = i+1; cj = cs[j]; j++){
6597                     if(cj._nodup != d){
6598                         cj._nodup = d;
6599                         r[++ri] = cj;
6600                     }
6601                 }
6602                 return r;
6603             }
6604         }
6605         return r;
6606     }
6607
6608     function quickDiffIEXml(c1, c2){
6609         var d = ++key;
6610         for(var i = 0, len = c1.length; i < len; i++){
6611             c1[i].setAttribute("_qdiff", d);
6612         }
6613         var r = [];
6614         for(var i = 0, len = c2.length; i < len; i++){
6615             if(c2[i].getAttribute("_qdiff") != d){
6616                 r[r.length] = c2[i];
6617             }
6618         }
6619         for(var i = 0, len = c1.length; i < len; i++){
6620            c1[i].removeAttribute("_qdiff");
6621         }
6622         return r;
6623     }
6624
6625     function quickDiff(c1, c2){
6626         var len1 = c1.length;
6627         if(!len1){
6628             return c2;
6629         }
6630         if(isIE && c1[0].selectSingleNode){
6631             return quickDiffIEXml(c1, c2);
6632         }
6633         var d = ++key;
6634         for(var i = 0; i < len1; i++){
6635             c1[i]._qdiff = d;
6636         }
6637         var r = [];
6638         for(var i = 0, len = c2.length; i < len; i++){
6639             if(c2[i]._qdiff != d){
6640                 r[r.length] = c2[i];
6641             }
6642         }
6643         return r;
6644     }
6645
6646     function quickId(ns, mode, root, id){
6647         if(ns == root){
6648            var d = root.ownerDocument || root;
6649            return d.getElementById(id);
6650         }
6651         ns = getNodes(ns, mode, "*");
6652         return byId(ns, null, id);
6653     }
6654
6655     return {
6656         getStyle : function(el, name){
6657             return Roo.fly(el).getStyle(name);
6658         },
6659         /**
6660          * Compiles a selector/xpath query into a reusable function. The returned function
6661          * takes one parameter "root" (optional), which is the context node from where the query should start.
6662          * @param {String} selector The selector/xpath query
6663          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6664          * @return {Function}
6665          */
6666         compile : function(path, type){
6667             type = type || "select";
6668             
6669             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6670             var q = path, mode, lq;
6671             var tk = Roo.DomQuery.matchers;
6672             var tklen = tk.length;
6673             var mm;
6674
6675             // accept leading mode switch
6676             var lmode = q.match(modeRe);
6677             if(lmode && lmode[1]){
6678                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6679                 q = q.replace(lmode[1], "");
6680             }
6681             // strip leading slashes
6682             while(path.substr(0, 1)=="/"){
6683                 path = path.substr(1);
6684             }
6685
6686             while(q && lq != q){
6687                 lq = q;
6688                 var tm = q.match(tagTokenRe);
6689                 if(type == "select"){
6690                     if(tm){
6691                         if(tm[1] == "#"){
6692                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6693                         }else{
6694                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6695                         }
6696                         q = q.replace(tm[0], "");
6697                     }else if(q.substr(0, 1) != '@'){
6698                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6699                     }
6700                 }else{
6701                     if(tm){
6702                         if(tm[1] == "#"){
6703                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6704                         }else{
6705                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6706                         }
6707                         q = q.replace(tm[0], "");
6708                     }
6709                 }
6710                 while(!(mm = q.match(modeRe))){
6711                     var matched = false;
6712                     for(var j = 0; j < tklen; j++){
6713                         var t = tk[j];
6714                         var m = q.match(t.re);
6715                         if(m){
6716                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6717                                                     return m[i];
6718                                                 });
6719                             q = q.replace(m[0], "");
6720                             matched = true;
6721                             break;
6722                         }
6723                     }
6724                     // prevent infinite loop on bad selector
6725                     if(!matched){
6726                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6727                     }
6728                 }
6729                 if(mm[1]){
6730                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6731                     q = q.replace(mm[1], "");
6732                 }
6733             }
6734             fn[fn.length] = "return nodup(n);\n}";
6735             
6736              /** 
6737               * list of variables that need from compression as they are used by eval.
6738              *  eval:var:batch 
6739              *  eval:var:nodup
6740              *  eval:var:byTag
6741              *  eval:var:ById
6742              *  eval:var:getNodes
6743              *  eval:var:quickId
6744              *  eval:var:mode
6745              *  eval:var:root
6746              *  eval:var:n
6747              *  eval:var:byClassName
6748              *  eval:var:byPseudo
6749              *  eval:var:byAttribute
6750              *  eval:var:attrValue
6751              * 
6752              **/ 
6753             eval(fn.join(""));
6754             return f;
6755         },
6756
6757         /**
6758          * Selects a group of elements.
6759          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6760          * @param {Node} root (optional) The start of the query (defaults to document).
6761          * @return {Array}
6762          */
6763         select : function(path, root, type){
6764             if(!root || root == document){
6765                 root = document;
6766             }
6767             if(typeof root == "string"){
6768                 root = document.getElementById(root);
6769             }
6770             var paths = path.split(",");
6771             var results = [];
6772             for(var i = 0, len = paths.length; i < len; i++){
6773                 var p = paths[i].replace(trimRe, "");
6774                 if(!cache[p]){
6775                     cache[p] = Roo.DomQuery.compile(p);
6776                     if(!cache[p]){
6777                         throw p + " is not a valid selector";
6778                     }
6779                 }
6780                 var result = cache[p](root);
6781                 if(result && result != document){
6782                     results = results.concat(result);
6783                 }
6784             }
6785             if(paths.length > 1){
6786                 return nodup(results);
6787             }
6788             return results;
6789         },
6790
6791         /**
6792          * Selects a single element.
6793          * @param {String} selector The selector/xpath query
6794          * @param {Node} root (optional) The start of the query (defaults to document).
6795          * @return {Element}
6796          */
6797         selectNode : function(path, root){
6798             return Roo.DomQuery.select(path, root)[0];
6799         },
6800
6801         /**
6802          * Selects the value of a node, optionally replacing null with the defaultValue.
6803          * @param {String} selector The selector/xpath query
6804          * @param {Node} root (optional) The start of the query (defaults to document).
6805          * @param {String} defaultValue
6806          */
6807         selectValue : function(path, root, defaultValue){
6808             path = path.replace(trimRe, "");
6809             if(!valueCache[path]){
6810                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6811             }
6812             var n = valueCache[path](root);
6813             n = n[0] ? n[0] : n;
6814             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6815             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6816         },
6817
6818         /**
6819          * Selects the value of a node, parsing integers and floats.
6820          * @param {String} selector The selector/xpath query
6821          * @param {Node} root (optional) The start of the query (defaults to document).
6822          * @param {Number} defaultValue
6823          * @return {Number}
6824          */
6825         selectNumber : function(path, root, defaultValue){
6826             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6827             return parseFloat(v);
6828         },
6829
6830         /**
6831          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6832          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6833          * @param {String} selector The simple selector to test
6834          * @return {Boolean}
6835          */
6836         is : function(el, ss){
6837             if(typeof el == "string"){
6838                 el = document.getElementById(el);
6839             }
6840             var isArray = (el instanceof Array);
6841             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6842             return isArray ? (result.length == el.length) : (result.length > 0);
6843         },
6844
6845         /**
6846          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6847          * @param {Array} el An array of elements to filter
6848          * @param {String} selector The simple selector to test
6849          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6850          * the selector instead of the ones that match
6851          * @return {Array}
6852          */
6853         filter : function(els, ss, nonMatches){
6854             ss = ss.replace(trimRe, "");
6855             if(!simpleCache[ss]){
6856                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6857             }
6858             var result = simpleCache[ss](els);
6859             return nonMatches ? quickDiff(result, els) : result;
6860         },
6861
6862         /**
6863          * Collection of matching regular expressions and code snippets.
6864          */
6865         matchers : [{
6866                 re: /^\.([\w-]+)/,
6867                 select: 'n = byClassName(n, null, " {1} ");'
6868             }, {
6869                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6870                 select: 'n = byPseudo(n, "{1}", "{2}");'
6871             },{
6872                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6873                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6874             }, {
6875                 re: /^#([\w-]+)/,
6876                 select: 'n = byId(n, null, "{1}");'
6877             },{
6878                 re: /^@([\w-]+)/,
6879                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6880             }
6881         ],
6882
6883         /**
6884          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6885          * 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;.
6886          */
6887         operators : {
6888             "=" : function(a, v){
6889                 return a == v;
6890             },
6891             "!=" : function(a, v){
6892                 return a != v;
6893             },
6894             "^=" : function(a, v){
6895                 return a && a.substr(0, v.length) == v;
6896             },
6897             "$=" : function(a, v){
6898                 return a && a.substr(a.length-v.length) == v;
6899             },
6900             "*=" : function(a, v){
6901                 return a && a.indexOf(v) !== -1;
6902             },
6903             "%=" : function(a, v){
6904                 return (a % v) == 0;
6905             },
6906             "|=" : function(a, v){
6907                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6908             },
6909             "~=" : function(a, v){
6910                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6911             }
6912         },
6913
6914         /**
6915          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6916          * and the argument (if any) supplied in the selector.
6917          */
6918         pseudos : {
6919             "first-child" : function(c){
6920                 var r = [], ri = -1, n;
6921                 for(var i = 0, ci; ci = n = c[i]; i++){
6922                     while((n = n.previousSibling) && n.nodeType != 1);
6923                     if(!n){
6924                         r[++ri] = ci;
6925                     }
6926                 }
6927                 return r;
6928             },
6929
6930             "last-child" : function(c){
6931                 var r = [], ri = -1, n;
6932                 for(var i = 0, ci; ci = n = c[i]; i++){
6933                     while((n = n.nextSibling) && n.nodeType != 1);
6934                     if(!n){
6935                         r[++ri] = ci;
6936                     }
6937                 }
6938                 return r;
6939             },
6940
6941             "nth-child" : function(c, a) {
6942                 var r = [], ri = -1;
6943                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6944                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6945                 for(var i = 0, n; n = c[i]; i++){
6946                     var pn = n.parentNode;
6947                     if (batch != pn._batch) {
6948                         var j = 0;
6949                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6950                             if(cn.nodeType == 1){
6951                                cn.nodeIndex = ++j;
6952                             }
6953                         }
6954                         pn._batch = batch;
6955                     }
6956                     if (f == 1) {
6957                         if (l == 0 || n.nodeIndex == l){
6958                             r[++ri] = n;
6959                         }
6960                     } else if ((n.nodeIndex + l) % f == 0){
6961                         r[++ri] = n;
6962                     }
6963                 }
6964
6965                 return r;
6966             },
6967
6968             "only-child" : function(c){
6969                 var r = [], ri = -1;;
6970                 for(var i = 0, ci; ci = c[i]; i++){
6971                     if(!prev(ci) && !next(ci)){
6972                         r[++ri] = ci;
6973                     }
6974                 }
6975                 return r;
6976             },
6977
6978             "empty" : function(c){
6979                 var r = [], ri = -1;
6980                 for(var i = 0, ci; ci = c[i]; i++){
6981                     var cns = ci.childNodes, j = 0, cn, empty = true;
6982                     while(cn = cns[j]){
6983                         ++j;
6984                         if(cn.nodeType == 1 || cn.nodeType == 3){
6985                             empty = false;
6986                             break;
6987                         }
6988                     }
6989                     if(empty){
6990                         r[++ri] = ci;
6991                     }
6992                 }
6993                 return r;
6994             },
6995
6996             "contains" : function(c, v){
6997                 var r = [], ri = -1;
6998                 for(var i = 0, ci; ci = c[i]; i++){
6999                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
7000                         r[++ri] = ci;
7001                     }
7002                 }
7003                 return r;
7004             },
7005
7006             "nodeValue" : function(c, v){
7007                 var r = [], ri = -1;
7008                 for(var i = 0, ci; ci = c[i]; i++){
7009                     if(ci.firstChild && ci.firstChild.nodeValue == v){
7010                         r[++ri] = ci;
7011                     }
7012                 }
7013                 return r;
7014             },
7015
7016             "checked" : function(c){
7017                 var r = [], ri = -1;
7018                 for(var i = 0, ci; ci = c[i]; i++){
7019                     if(ci.checked == true){
7020                         r[++ri] = ci;
7021                     }
7022                 }
7023                 return r;
7024             },
7025
7026             "not" : function(c, ss){
7027                 return Roo.DomQuery.filter(c, ss, true);
7028             },
7029
7030             "odd" : function(c){
7031                 return this["nth-child"](c, "odd");
7032             },
7033
7034             "even" : function(c){
7035                 return this["nth-child"](c, "even");
7036             },
7037
7038             "nth" : function(c, a){
7039                 return c[a-1] || [];
7040             },
7041
7042             "first" : function(c){
7043                 return c[0] || [];
7044             },
7045
7046             "last" : function(c){
7047                 return c[c.length-1] || [];
7048             },
7049
7050             "has" : function(c, ss){
7051                 var s = Roo.DomQuery.select;
7052                 var r = [], ri = -1;
7053                 for(var i = 0, ci; ci = c[i]; i++){
7054                     if(s(ss, ci).length > 0){
7055                         r[++ri] = ci;
7056                     }
7057                 }
7058                 return r;
7059             },
7060
7061             "next" : function(c, ss){
7062                 var is = Roo.DomQuery.is;
7063                 var r = [], ri = -1;
7064                 for(var i = 0, ci; ci = c[i]; i++){
7065                     var n = next(ci);
7066                     if(n && is(n, ss)){
7067                         r[++ri] = ci;
7068                     }
7069                 }
7070                 return r;
7071             },
7072
7073             "prev" : function(c, ss){
7074                 var is = Roo.DomQuery.is;
7075                 var r = [], ri = -1;
7076                 for(var i = 0, ci; ci = c[i]; i++){
7077                     var n = prev(ci);
7078                     if(n && is(n, ss)){
7079                         r[++ri] = ci;
7080                     }
7081                 }
7082                 return r;
7083             }
7084         }
7085     };
7086 }();
7087
7088 /**
7089  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
7090  * @param {String} path The selector/xpath query
7091  * @param {Node} root (optional) The start of the query (defaults to document).
7092  * @return {Array}
7093  * @member Roo
7094  * @method query
7095  */
7096 Roo.query = Roo.DomQuery.select;
7097 /*
7098  * Based on:
7099  * Ext JS Library 1.1.1
7100  * Copyright(c) 2006-2007, Ext JS, LLC.
7101  *
7102  * Originally Released Under LGPL - original licence link has changed is not relivant.
7103  *
7104  * Fork - LGPL
7105  * <script type="text/javascript">
7106  */
7107
7108 /**
7109  * @class Roo.util.Observable
7110  * Base class that provides a common interface for publishing events. Subclasses are expected to
7111  * to have a property "events" with all the events defined.<br>
7112  * For example:
7113  * <pre><code>
7114  Employee = function(name){
7115     this.name = name;
7116     this.addEvents({
7117         "fired" : true,
7118         "quit" : true
7119     });
7120  }
7121  Roo.extend(Employee, Roo.util.Observable);
7122 </code></pre>
7123  * @param {Object} config properties to use (incuding events / listeners)
7124  */
7125
7126 Roo.util.Observable = function(cfg){
7127     console.log("UTIL OBSERVABLE CONSTRUCTOR");
7128     
7129     cfg = cfg|| {};
7130     this.addEvents(cfg.events || {});
7131     if (cfg.events) {
7132         delete cfg.events; // make sure
7133     }
7134      
7135     Roo.apply(this, cfg);
7136     
7137     if(this.listeners){
7138         this.on(this.listeners);
7139         delete this.listeners;
7140     }
7141 };
7142 Roo.util.Observable.prototype = {
7143     /** 
7144  * @cfg {Object} listeners  list of events and functions to call for this object, 
7145  * For example :
7146  * <pre><code>
7147     listeners :  { 
7148        'click' : function(e) {
7149            ..... 
7150         } ,
7151         .... 
7152     } 
7153   </code></pre>
7154  */
7155     
7156     
7157     /**
7158      * Fires the specified event with the passed parameters (minus the event name).
7159      * @param {String} eventName
7160      * @param {Object...} args Variable number of parameters are passed to handlers
7161      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
7162      */
7163     fireEvent : function(){
7164         var ce = this.events[arguments[0].toLowerCase()];
7165         if(typeof ce == "object"){
7166             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
7167         }else{
7168             return true;
7169         }
7170     },
7171
7172     // private
7173     filterOptRe : /^(?:scope|delay|buffer|single)$/,
7174
7175     /**
7176      * Appends an event handler to this component
7177      * @param {String}   eventName The type of event to listen for
7178      * @param {Function} handler The method the event invokes
7179      * @param {Object}   scope (optional) The scope in which to execute the handler
7180      * function. The handler function's "this" context.
7181      * @param {Object}   options (optional) An object containing handler configuration
7182      * properties. This may contain any of the following properties:<ul>
7183      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7184      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7185      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7186      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7187      * by the specified number of milliseconds. If the event fires again within that time, the original
7188      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7189      * </ul><br>
7190      * <p>
7191      * <b>Combining Options</b><br>
7192      * Using the options argument, it is possible to combine different types of listeners:<br>
7193      * <br>
7194      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
7195                 <pre><code>
7196                 el.on('click', this.onClick, this, {
7197                         single: true,
7198                 delay: 100,
7199                 forumId: 4
7200                 });
7201                 </code></pre>
7202      * <p>
7203      * <b>Attaching multiple handlers in 1 call</b><br>
7204      * The method also allows for a single argument to be passed which is a config object containing properties
7205      * which specify multiple handlers.
7206      * <pre><code>
7207                 el.on({
7208                         'click': {
7209                         fn: this.onClick,
7210                         scope: this,
7211                         delay: 100
7212                 }, 
7213                 'mouseover': {
7214                         fn: this.onMouseOver,
7215                         scope: this
7216                 },
7217                 'mouseout': {
7218                         fn: this.onMouseOut,
7219                         scope: this
7220                 }
7221                 });
7222                 </code></pre>
7223      * <p>
7224      * Or a shorthand syntax which passes the same scope object to all handlers:
7225         <pre><code>
7226                 el.on({
7227                         'click': this.onClick,
7228                 'mouseover': this.onMouseOver,
7229                 'mouseout': this.onMouseOut,
7230                 scope: this
7231                 });
7232                 </code></pre>
7233      */
7234     addListener : function(eventName, fn, scope, o){
7235         if(typeof eventName == "object"){
7236             o = eventName;
7237             for(var e in o){
7238                 if(this.filterOptRe.test(e)){
7239                     continue;
7240                 }
7241                 if(typeof o[e] == "function"){
7242                     // shared options
7243                     this.addListener(e, o[e], o.scope,  o);
7244                 }else{
7245                     // individual options
7246                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
7247                 }
7248             }
7249             return;
7250         }
7251         o = (!o || typeof o == "boolean") ? {} : o;
7252         eventName = eventName.toLowerCase();
7253         var ce = this.events[eventName] || true;
7254         if(typeof ce == "boolean"){
7255             ce = new Roo.util.Event(this, eventName);
7256             this.events[eventName] = ce;
7257         }
7258         ce.addListener(fn, scope, o);
7259     },
7260
7261     /**
7262      * Removes a listener
7263      * @param {String}   eventName     The type of event to listen for
7264      * @param {Function} handler        The handler to remove
7265      * @param {Object}   scope  (optional) The scope (this object) for the handler
7266      */
7267     removeListener : function(eventName, fn, scope){
7268         var ce = this.events[eventName.toLowerCase()];
7269         if(typeof ce == "object"){
7270             ce.removeListener(fn, scope);
7271         }
7272     },
7273
7274     /**
7275      * Removes all listeners for this object
7276      */
7277     purgeListeners : function(){
7278         for(var evt in this.events){
7279             if(typeof this.events[evt] == "object"){
7280                  this.events[evt].clearListeners();
7281             }
7282         }
7283     },
7284
7285     relayEvents : function(o, events){
7286         var createHandler = function(ename){
7287             return function(){
7288                  
7289                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
7290             };
7291         };
7292         for(var i = 0, len = events.length; i < len; i++){
7293             var ename = events[i];
7294             if(!this.events[ename]){
7295                 this.events[ename] = true;
7296             };
7297             o.on(ename, createHandler(ename), this);
7298         }
7299     },
7300
7301     /**
7302      * Used to define events on this Observable
7303      * @param {Object} object The object with the events defined
7304      */
7305     addEvents : function(o){
7306         if(!this.events){
7307             this.events = {};
7308         }
7309         Roo.applyIf(this.events, o);
7310     },
7311
7312     /**
7313      * Checks to see if this object has any listeners for a specified event
7314      * @param {String} eventName The name of the event to check for
7315      * @return {Boolean} True if the event is being listened for, else false
7316      */
7317     hasListener : function(eventName){
7318         var e = this.events[eventName];
7319         return typeof e == "object" && e.listeners.length > 0;
7320     }
7321 };
7322 /**
7323  * Appends an event handler to this element (shorthand for addListener)
7324  * @param {String}   eventName     The type of event to listen for
7325  * @param {Function} handler        The method the event invokes
7326  * @param {Object}   scope (optional) The scope in which to execute the handler
7327  * function. The handler function's "this" context.
7328  * @param {Object}   options  (optional)
7329  * @method
7330  */
7331 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
7332 /**
7333  * Removes a listener (shorthand for removeListener)
7334  * @param {String}   eventName     The type of event to listen for
7335  * @param {Function} handler        The handler to remove
7336  * @param {Object}   scope  (optional) The scope (this object) for the handler
7337  * @method
7338  */
7339 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
7340
7341 /**
7342  * Starts capture on the specified Observable. All events will be passed
7343  * to the supplied function with the event name + standard signature of the event
7344  * <b>before</b> the event is fired. If the supplied function returns false,
7345  * the event will not fire.
7346  * @param {Observable} o The Observable to capture
7347  * @param {Function} fn The function to call
7348  * @param {Object} scope (optional) The scope (this object) for the fn
7349  * @static
7350  */
7351 Roo.util.Observable.capture = function(o, fn, scope){
7352     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
7353 };
7354
7355 /**
7356  * Removes <b>all</b> added captures from the Observable.
7357  * @param {Observable} o The Observable to release
7358  * @static
7359  */
7360 Roo.util.Observable.releaseCapture = function(o){
7361     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
7362 };
7363
7364 (function(){
7365
7366     var createBuffered = function(h, o, scope){
7367         var task = new Roo.util.DelayedTask();
7368         return function(){
7369             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
7370         };
7371     };
7372
7373     var createSingle = function(h, e, fn, scope){
7374         return function(){
7375             e.removeListener(fn, scope);
7376             return h.apply(scope, arguments);
7377         };
7378     };
7379
7380     var createDelayed = function(h, o, scope){
7381         return function(){
7382             var args = Array.prototype.slice.call(arguments, 0);
7383             setTimeout(function(){
7384                 h.apply(scope, args);
7385             }, o.delay || 10);
7386         };
7387     };
7388
7389     Roo.util.Event = function(obj, name){
7390         this.name = name;
7391         this.obj = obj;
7392         this.listeners = [];
7393     };
7394
7395     Roo.util.Event.prototype = {
7396         addListener : function(fn, scope, options){
7397             var o = options || {};
7398             scope = scope || this.obj;
7399             if(!this.isListening(fn, scope)){
7400                 var l = {fn: fn, scope: scope, options: o};
7401                 var h = fn;
7402                 if(o.delay){
7403                     h = createDelayed(h, o, scope);
7404                 }
7405                 if(o.single){
7406                     h = createSingle(h, this, fn, scope);
7407                 }
7408                 if(o.buffer){
7409                     h = createBuffered(h, o, scope);
7410                 }
7411                 l.fireFn = h;
7412                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
7413                     this.listeners.push(l);
7414                 }else{
7415                     this.listeners = this.listeners.slice(0);
7416                     this.listeners.push(l);
7417                 }
7418             }
7419         },
7420
7421         findListener : function(fn, scope){
7422             scope = scope || this.obj;
7423             var ls = this.listeners;
7424             for(var i = 0, len = ls.length; i < len; i++){
7425                 var l = ls[i];
7426                 if(l.fn == fn && l.scope == scope){
7427                     return i;
7428                 }
7429             }
7430             return -1;
7431         },
7432
7433         isListening : function(fn, scope){
7434             return this.findListener(fn, scope) != -1;
7435         },
7436
7437         removeListener : function(fn, scope){
7438             var index;
7439             if((index = this.findListener(fn, scope)) != -1){
7440                 if(!this.firing){
7441                     this.listeners.splice(index, 1);
7442                 }else{
7443                     this.listeners = this.listeners.slice(0);
7444                     this.listeners.splice(index, 1);
7445                 }
7446                 return true;
7447             }
7448             return false;
7449         },
7450
7451         clearListeners : function(){
7452             this.listeners = [];
7453         },
7454
7455         fire : function(){
7456             var ls = this.listeners, scope, len = ls.length;
7457             if(len > 0){
7458                 this.firing = true;
7459                 var args = Array.prototype.slice.call(arguments, 0);                
7460                 for(var i = 0; i < len; i++){
7461                     var l = ls[i];
7462                     if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
7463                         this.firing = false;
7464                         return false;
7465                     }
7466                 }
7467                 this.firing = false;
7468             }
7469             return true;
7470         }
7471     };
7472 })();/*
7473  * RooJS Library 
7474  * Copyright(c) 2007-2017, Roo J Solutions Ltd
7475  *
7476  * Licence LGPL 
7477  *
7478  */
7479  
7480 /**
7481  * @class Roo.Document
7482  * @extends Roo.util.Observable
7483  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
7484  * 
7485  * @param {Object} config the methods and properties of the 'base' class for the application.
7486  * 
7487  *  Generic Page handler - implement this to start your app..
7488  * 
7489  * eg.
7490  *  MyProject = new Roo.Document({
7491         events : {
7492             'load' : true // your events..
7493         },
7494         listeners : {
7495             'ready' : function() {
7496                 // fired on Roo.onReady()
7497             }
7498         }
7499  * 
7500  */
7501 Roo.Document = function(cfg) {
7502      
7503     this.addEvents({ 
7504         'ready' : true
7505     });
7506     Roo.util.Observable.call(this,cfg);
7507     
7508     var _this = this;
7509     
7510     Roo.onReady(function() {
7511         _this.fireEvent('ready');
7512     },null,false);
7513     
7514     
7515 }
7516
7517 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
7518  * Based on:
7519  * Ext JS Library 1.1.1
7520  * Copyright(c) 2006-2007, Ext JS, LLC.
7521  *
7522  * Originally Released Under LGPL - original licence link has changed is not relivant.
7523  *
7524  * Fork - LGPL
7525  * <script type="text/javascript">
7526  */
7527
7528 /**
7529  * @class Roo.EventManager
7530  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
7531  * several useful events directly.
7532  * See {@link Roo.EventObject} for more details on normalized event objects.
7533  * @static
7534  */
7535 Roo.EventManager = function(){
7536     var docReadyEvent, docReadyProcId, docReadyState = false;
7537     var resizeEvent, resizeTask, textEvent, textSize;
7538     var E = Roo.lib.Event;
7539     var D = Roo.lib.Dom;
7540
7541     
7542     
7543
7544     var fireDocReady = function(){
7545         if(!docReadyState){
7546             docReadyState = true;
7547             Roo.isReady = true;
7548             if(docReadyProcId){
7549                 clearInterval(docReadyProcId);
7550             }
7551             if(Roo.isGecko || Roo.isOpera) {
7552                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7553             }
7554             if(Roo.isIE){
7555                 var defer = document.getElementById("ie-deferred-loader");
7556                 if(defer){
7557                     defer.onreadystatechange = null;
7558                     defer.parentNode.removeChild(defer);
7559                 }
7560             }
7561             if(docReadyEvent){
7562                 docReadyEvent.fire();
7563                 docReadyEvent.clearListeners();
7564             }
7565         }
7566     };
7567     
7568     var initDocReady = function(){
7569         docReadyEvent = new Roo.util.Event();
7570         if(Roo.isGecko || Roo.isOpera) {
7571             document.addEventListener("DOMContentLoaded", fireDocReady, false);
7572         }else if(Roo.isIE){
7573             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7574             var defer = document.getElementById("ie-deferred-loader");
7575             defer.onreadystatechange = function(){
7576                 if(this.readyState == "complete"){
7577                     fireDocReady();
7578                 }
7579             };
7580         }else if(Roo.isSafari){ 
7581             docReadyProcId = setInterval(function(){
7582                 var rs = document.readyState;
7583                 if(rs == "complete") {
7584                     fireDocReady();     
7585                  }
7586             }, 10);
7587         }
7588         // no matter what, make sure it fires on load
7589         E.on(window, "load", fireDocReady);
7590     };
7591
7592     var createBuffered = function(h, o){
7593         var task = new Roo.util.DelayedTask(h);
7594         return function(e){
7595             // create new event object impl so new events don't wipe out properties
7596             e = new Roo.EventObjectImpl(e);
7597             task.delay(o.buffer, h, null, [e]);
7598         };
7599     };
7600
7601     var createSingle = function(h, el, ename, fn){
7602         return function(e){
7603             Roo.EventManager.removeListener(el, ename, fn);
7604             h(e);
7605         };
7606     };
7607
7608     var createDelayed = function(h, o){
7609         return function(e){
7610             // create new event object impl so new events don't wipe out properties
7611             e = new Roo.EventObjectImpl(e);
7612             setTimeout(function(){
7613                 h(e);
7614             }, o.delay || 10);
7615         };
7616     };
7617     var transitionEndVal = false;
7618     
7619     var transitionEnd = function()
7620     {
7621         if (transitionEndVal) {
7622             return transitionEndVal;
7623         }
7624         var el = document.createElement('div');
7625
7626         var transEndEventNames = {
7627             WebkitTransition : 'webkitTransitionEnd',
7628             MozTransition    : 'transitionend',
7629             OTransition      : 'oTransitionEnd otransitionend',
7630             transition       : 'transitionend'
7631         };
7632     
7633         for (var name in transEndEventNames) {
7634             if (el.style[name] !== undefined) {
7635                 transitionEndVal = transEndEventNames[name];
7636                 return  transitionEndVal ;
7637             }
7638         }
7639     }
7640     
7641   
7642
7643     var listen = function(element, ename, opt, fn, scope)
7644     {
7645         var o = (!opt || typeof opt == "boolean") ? {} : opt;
7646         fn = fn || o.fn; scope = scope || o.scope;
7647         var el = Roo.getDom(element);
7648         
7649         
7650         if(!el){
7651             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7652         }
7653         
7654         if (ename == 'transitionend') {
7655             ename = transitionEnd();
7656         }
7657         var h = function(e){
7658             e = Roo.EventObject.setEvent(e);
7659             var t;
7660             if(o.delegate){
7661                 t = e.getTarget(o.delegate, el);
7662                 if(!t){
7663                     return;
7664                 }
7665             }else{
7666                 t = e.target;
7667             }
7668             if(o.stopEvent === true){
7669                 e.stopEvent();
7670             }
7671             if(o.preventDefault === true){
7672                e.preventDefault();
7673             }
7674             if(o.stopPropagation === true){
7675                 e.stopPropagation();
7676             }
7677
7678             if(o.normalized === false){
7679                 e = e.browserEvent;
7680             }
7681
7682             fn.call(scope || el, e, t, o);
7683         };
7684         if(o.delay){
7685             h = createDelayed(h, o);
7686         }
7687         if(o.single){
7688             h = createSingle(h, el, ename, fn);
7689         }
7690         if(o.buffer){
7691             h = createBuffered(h, o);
7692         }
7693         
7694         fn._handlers = fn._handlers || [];
7695         
7696         
7697         fn._handlers.push([Roo.id(el), ename, h]);
7698         
7699         
7700          
7701         E.on(el, ename, h); // this adds the actuall listener to the object..
7702         
7703         
7704         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7705             el.addEventListener("DOMMouseScroll", h, false);
7706             E.on(window, 'unload', function(){
7707                 el.removeEventListener("DOMMouseScroll", h, false);
7708             });
7709         }
7710         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7711             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7712         }
7713         return h;
7714     };
7715
7716     var stopListening = function(el, ename, fn){
7717         var id = Roo.id(el), hds = fn._handlers, hd = fn;
7718         if(hds){
7719             for(var i = 0, len = hds.length; i < len; i++){
7720                 var h = hds[i];
7721                 if(h[0] == id && h[1] == ename){
7722                     hd = h[2];
7723                     hds.splice(i, 1);
7724                     break;
7725                 }
7726             }
7727         }
7728         E.un(el, ename, hd);
7729         el = Roo.getDom(el);
7730         if(ename == "mousewheel" && el.addEventListener){
7731             el.removeEventListener("DOMMouseScroll", hd, false);
7732         }
7733         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7734             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7735         }
7736     };
7737
7738     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7739     
7740     var pub = {
7741         
7742         
7743         /** 
7744          * Fix for doc tools
7745          * @scope Roo.EventManager
7746          */
7747         
7748         
7749         /** 
7750          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7751          * object with a Roo.EventObject
7752          * @param {Function} fn        The method the event invokes
7753          * @param {Object}   scope    An object that becomes the scope of the handler
7754          * @param {boolean}  override If true, the obj passed in becomes
7755          *                             the execution scope of the listener
7756          * @return {Function} The wrapped function
7757          * @deprecated
7758          */
7759         wrap : function(fn, scope, override){
7760             return function(e){
7761                 Roo.EventObject.setEvent(e);
7762                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7763             };
7764         },
7765         
7766         /**
7767      * Appends an event handler to an element (shorthand for addListener)
7768      * @param {String/HTMLElement}   element        The html element or id to assign the
7769      * @param {String}   eventName The type of event to listen for
7770      * @param {Function} handler The method the event invokes
7771      * @param {Object}   scope (optional) The scope in which to execute the handler
7772      * function. The handler function's "this" context.
7773      * @param {Object}   options (optional) An object containing handler configuration
7774      * properties. This may contain any of the following properties:<ul>
7775      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7776      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7777      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7778      * <li>preventDefault {Boolean} True to prevent the default action</li>
7779      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7780      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7781      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7782      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7783      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7784      * by the specified number of milliseconds. If the event fires again within that time, the original
7785      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7786      * </ul><br>
7787      * <p>
7788      * <b>Combining Options</b><br>
7789      * Using the options argument, it is possible to combine different types of listeners:<br>
7790      * <br>
7791      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7792      * Code:<pre><code>
7793 el.on('click', this.onClick, this, {
7794     single: true,
7795     delay: 100,
7796     stopEvent : true,
7797     forumId: 4
7798 });</code></pre>
7799      * <p>
7800      * <b>Attaching multiple handlers in 1 call</b><br>
7801       * The method also allows for a single argument to be passed which is a config object containing properties
7802      * which specify multiple handlers.
7803      * <p>
7804      * Code:<pre><code>
7805 el.on({
7806     'click' : {
7807         fn: this.onClick
7808         scope: this,
7809         delay: 100
7810     },
7811     'mouseover' : {
7812         fn: this.onMouseOver
7813         scope: this
7814     },
7815     'mouseout' : {
7816         fn: this.onMouseOut
7817         scope: this
7818     }
7819 });</code></pre>
7820      * <p>
7821      * Or a shorthand syntax:<br>
7822      * Code:<pre><code>
7823 el.on({
7824     'click' : this.onClick,
7825     'mouseover' : this.onMouseOver,
7826     'mouseout' : this.onMouseOut
7827     scope: this
7828 });</code></pre>
7829      */
7830         addListener : function(element, eventName, fn, scope, options){
7831             if(typeof eventName == "object"){
7832                 var o = eventName;
7833                 for(var e in o){
7834                     if(propRe.test(e)){
7835                         continue;
7836                     }
7837                     if(typeof o[e] == "function"){
7838                         // shared options
7839                         listen(element, e, o, o[e], o.scope);
7840                     }else{
7841                         // individual options
7842                         listen(element, e, o[e]);
7843                     }
7844                 }
7845                 return;
7846             }
7847             return listen(element, eventName, options, fn, scope);
7848         },
7849         
7850         /**
7851          * Removes an event handler
7852          *
7853          * @param {String/HTMLElement}   element        The id or html element to remove the 
7854          *                             event from
7855          * @param {String}   eventName     The type of event
7856          * @param {Function} fn
7857          * @return {Boolean} True if a listener was actually removed
7858          */
7859         removeListener : function(element, eventName, fn){
7860             return stopListening(element, eventName, fn);
7861         },
7862         
7863         /**
7864          * Fires when the document is ready (before onload and before images are loaded). Can be 
7865          * accessed shorthanded Roo.onReady().
7866          * @param {Function} fn        The method the event invokes
7867          * @param {Object}   scope    An  object that becomes the scope of the handler
7868          * @param {boolean}  options
7869          */
7870         onDocumentReady : function(fn, scope, options){
7871             if(docReadyState){ // if it already fired
7872                 docReadyEvent.addListener(fn, scope, options);
7873                 docReadyEvent.fire();
7874                 docReadyEvent.clearListeners();
7875                 return;
7876             }
7877             if(!docReadyEvent){
7878                 initDocReady();
7879             }
7880             docReadyEvent.addListener(fn, scope, options);
7881         },
7882         
7883         /**
7884          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7885          * @param {Function} fn        The method the event invokes
7886          * @param {Object}   scope    An object that becomes the scope of the handler
7887          * @param {boolean}  options
7888          */
7889         onWindowResize : function(fn, scope, options)
7890         {
7891             if(!resizeEvent){
7892                 resizeEvent = new Roo.util.Event();
7893                 resizeTask = new Roo.util.DelayedTask(function(){
7894                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7895                 });
7896                 E.on(window, "resize", function()
7897                 {
7898                     if (Roo.isIE) {
7899                         resizeTask.delay(50);
7900                     } else {
7901                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7902                     }
7903                 });
7904             }
7905             resizeEvent.addListener(fn, scope, options);
7906         },
7907
7908         /**
7909          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7910          * @param {Function} fn        The method the event invokes
7911          * @param {Object}   scope    An object that becomes the scope of the handler
7912          * @param {boolean}  options
7913          */
7914         onTextResize : function(fn, scope, options){
7915             if(!textEvent){
7916                 textEvent = new Roo.util.Event();
7917                 var textEl = new Roo.Element(document.createElement('div'));
7918                 textEl.dom.className = 'x-text-resize';
7919                 textEl.dom.innerHTML = 'X';
7920                 textEl.appendTo(document.body);
7921                 textSize = textEl.dom.offsetHeight;
7922                 setInterval(function(){
7923                     if(textEl.dom.offsetHeight != textSize){
7924                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7925                     }
7926                 }, this.textResizeInterval);
7927             }
7928             textEvent.addListener(fn, scope, options);
7929         },
7930
7931         /**
7932          * Removes the passed window resize listener.
7933          * @param {Function} fn        The method the event invokes
7934          * @param {Object}   scope    The scope of handler
7935          */
7936         removeResizeListener : function(fn, scope){
7937             if(resizeEvent){
7938                 resizeEvent.removeListener(fn, scope);
7939             }
7940         },
7941
7942         // private
7943         fireResize : function(){
7944             if(resizeEvent){
7945                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7946             }   
7947         },
7948         /**
7949          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7950          */
7951         ieDeferSrc : false,
7952         /**
7953          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7954          */
7955         textResizeInterval : 50
7956     };
7957     
7958     /**
7959      * Fix for doc tools
7960      * @scopeAlias pub=Roo.EventManager
7961      */
7962     
7963      /**
7964      * Appends an event handler to an element (shorthand for addListener)
7965      * @param {String/HTMLElement}   element        The html element or id to assign the
7966      * @param {String}   eventName The type of event to listen for
7967      * @param {Function} handler The method the event invokes
7968      * @param {Object}   scope (optional) The scope in which to execute the handler
7969      * function. The handler function's "this" context.
7970      * @param {Object}   options (optional) An object containing handler configuration
7971      * properties. This may contain any of the following properties:<ul>
7972      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7973      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7974      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7975      * <li>preventDefault {Boolean} True to prevent the default action</li>
7976      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7977      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7978      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7979      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7980      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7981      * by the specified number of milliseconds. If the event fires again within that time, the original
7982      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7983      * </ul><br>
7984      * <p>
7985      * <b>Combining Options</b><br>
7986      * Using the options argument, it is possible to combine different types of listeners:<br>
7987      * <br>
7988      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7989      * Code:<pre><code>
7990 el.on('click', this.onClick, this, {
7991     single: true,
7992     delay: 100,
7993     stopEvent : true,
7994     forumId: 4
7995 });</code></pre>
7996      * <p>
7997      * <b>Attaching multiple handlers in 1 call</b><br>
7998       * The method also allows for a single argument to be passed which is a config object containing properties
7999      * which specify multiple handlers.
8000      * <p>
8001      * Code:<pre><code>
8002 el.on({
8003     'click' : {
8004         fn: this.onClick
8005         scope: this,
8006         delay: 100
8007     },
8008     'mouseover' : {
8009         fn: this.onMouseOver
8010         scope: this
8011     },
8012     'mouseout' : {
8013         fn: this.onMouseOut
8014         scope: this
8015     }
8016 });</code></pre>
8017      * <p>
8018      * Or a shorthand syntax:<br>
8019      * Code:<pre><code>
8020 el.on({
8021     'click' : this.onClick,
8022     'mouseover' : this.onMouseOver,
8023     'mouseout' : this.onMouseOut
8024     scope: this
8025 });</code></pre>
8026      */
8027     pub.on = pub.addListener;
8028     pub.un = pub.removeListener;
8029
8030     pub.stoppedMouseDownEvent = new Roo.util.Event();
8031     return pub;
8032 }();
8033 /**
8034   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
8035   * @param {Function} fn        The method the event invokes
8036   * @param {Object}   scope    An  object that becomes the scope of the handler
8037   * @param {boolean}  override If true, the obj passed in becomes
8038   *                             the execution scope of the listener
8039   * @member Roo
8040   * @method onReady
8041  */
8042 Roo.onReady = Roo.EventManager.onDocumentReady;
8043
8044 Roo.onReady(function(){
8045     var bd = Roo.get(document.body);
8046     if(!bd){ return; }
8047
8048     var cls = [
8049             Roo.isIE ? "roo-ie"
8050             : Roo.isIE11 ? "roo-ie11"
8051             : Roo.isEdge ? "roo-edge"
8052             : Roo.isGecko ? "roo-gecko"
8053             : Roo.isOpera ? "roo-opera"
8054             : Roo.isSafari ? "roo-safari" : ""];
8055
8056     if(Roo.isMac){
8057         cls.push("roo-mac");
8058     }
8059     if(Roo.isLinux){
8060         cls.push("roo-linux");
8061     }
8062     if(Roo.isIOS){
8063         cls.push("roo-ios");
8064     }
8065     if(Roo.isTouch){
8066         cls.push("roo-touch");
8067     }
8068     if(Roo.isBorderBox){
8069         cls.push('roo-border-box');
8070     }
8071     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
8072         var p = bd.dom.parentNode;
8073         if(p){
8074             p.className += ' roo-strict';
8075         }
8076     }
8077     bd.addClass(cls.join(' '));
8078 });
8079
8080 /**
8081  * @class Roo.EventObject
8082  * EventObject exposes the Yahoo! UI Event functionality directly on the object
8083  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
8084  * Example:
8085  * <pre><code>
8086  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
8087     e.preventDefault();
8088     var target = e.getTarget();
8089     ...
8090  }
8091  var myDiv = Roo.get("myDiv");
8092  myDiv.on("click", handleClick);
8093  //or
8094  Roo.EventManager.on("myDiv", 'click', handleClick);
8095  Roo.EventManager.addListener("myDiv", 'click', handleClick);
8096  </code></pre>
8097  * @static
8098  */
8099 Roo.EventObject = function(){
8100     
8101     var E = Roo.lib.Event;
8102     
8103     // safari keypress events for special keys return bad keycodes
8104     var safariKeys = {
8105         63234 : 37, // left
8106         63235 : 39, // right
8107         63232 : 38, // up
8108         63233 : 40, // down
8109         63276 : 33, // page up
8110         63277 : 34, // page down
8111         63272 : 46, // delete
8112         63273 : 36, // home
8113         63275 : 35  // end
8114     };
8115
8116     // normalize button clicks
8117     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
8118                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
8119
8120     Roo.EventObjectImpl = function(e){
8121         if(e){
8122             this.setEvent(e.browserEvent || e);
8123         }
8124     };
8125     Roo.EventObjectImpl.prototype = {
8126         /**
8127          * Used to fix doc tools.
8128          * @scope Roo.EventObject.prototype
8129          */
8130             
8131
8132         
8133         
8134         /** The normal browser event */
8135         browserEvent : null,
8136         /** The button pressed in a mouse event */
8137         button : -1,
8138         /** True if the shift key was down during the event */
8139         shiftKey : false,
8140         /** True if the control key was down during the event */
8141         ctrlKey : false,
8142         /** True if the alt key was down during the event */
8143         altKey : false,
8144
8145         /** Key constant 
8146         * @type Number */
8147         BACKSPACE : 8,
8148         /** Key constant 
8149         * @type Number */
8150         TAB : 9,
8151         /** Key constant 
8152         * @type Number */
8153         RETURN : 13,
8154         /** Key constant 
8155         * @type Number */
8156         ENTER : 13,
8157         /** Key constant 
8158         * @type Number */
8159         SHIFT : 16,
8160         /** Key constant 
8161         * @type Number */
8162         CONTROL : 17,
8163         /** Key constant 
8164         * @type Number */
8165         ESC : 27,
8166         /** Key constant 
8167         * @type Number */
8168         SPACE : 32,
8169         /** Key constant 
8170         * @type Number */
8171         PAGEUP : 33,
8172         /** Key constant 
8173         * @type Number */
8174         PAGEDOWN : 34,
8175         /** Key constant 
8176         * @type Number */
8177         END : 35,
8178         /** Key constant 
8179         * @type Number */
8180         HOME : 36,
8181         /** Key constant 
8182         * @type Number */
8183         LEFT : 37,
8184         /** Key constant 
8185         * @type Number */
8186         UP : 38,
8187         /** Key constant 
8188         * @type Number */
8189         RIGHT : 39,
8190         /** Key constant 
8191         * @type Number */
8192         DOWN : 40,
8193         /** Key constant 
8194         * @type Number */
8195         DELETE : 46,
8196         /** Key constant 
8197         * @type Number */
8198         F5 : 116,
8199
8200            /** @private */
8201         setEvent : function(e){
8202             if(e == this || (e && e.browserEvent)){ // already wrapped
8203                 return e;
8204             }
8205             this.browserEvent = e;
8206             if(e){
8207                 // normalize buttons
8208                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
8209                 if(e.type == 'click' && this.button == -1){
8210                     this.button = 0;
8211                 }
8212                 this.type = e.type;
8213                 this.shiftKey = e.shiftKey;
8214                 // mac metaKey behaves like ctrlKey
8215                 this.ctrlKey = e.ctrlKey || e.metaKey;
8216                 this.altKey = e.altKey;
8217                 // in getKey these will be normalized for the mac
8218                 this.keyCode = e.keyCode;
8219                 // keyup warnings on firefox.
8220                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
8221                 // cache the target for the delayed and or buffered events
8222                 this.target = E.getTarget(e);
8223                 // same for XY
8224                 this.xy = E.getXY(e);
8225             }else{
8226                 this.button = -1;
8227                 this.shiftKey = false;
8228                 this.ctrlKey = false;
8229                 this.altKey = false;
8230                 this.keyCode = 0;
8231                 this.charCode =0;
8232                 this.target = null;
8233                 this.xy = [0, 0];
8234             }
8235             return this;
8236         },
8237
8238         /**
8239          * Stop the event (preventDefault and stopPropagation)
8240          */
8241         stopEvent : function(){
8242             if(this.browserEvent){
8243                 if(this.browserEvent.type == 'mousedown'){
8244                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8245                 }
8246                 E.stopEvent(this.browserEvent);
8247             }
8248         },
8249
8250         /**
8251          * Prevents the browsers default handling of the event.
8252          */
8253         preventDefault : function(){
8254             if(this.browserEvent){
8255                 E.preventDefault(this.browserEvent);
8256             }
8257         },
8258
8259         /** @private */
8260         isNavKeyPress : function(){
8261             var k = this.keyCode;
8262             k = Roo.isSafari ? (safariKeys[k] || k) : k;
8263             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
8264         },
8265
8266         isSpecialKey : function(){
8267             var k = this.keyCode;
8268             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
8269             (k == 16) || (k == 17) ||
8270             (k >= 18 && k <= 20) ||
8271             (k >= 33 && k <= 35) ||
8272             (k >= 36 && k <= 39) ||
8273             (k >= 44 && k <= 45);
8274         },
8275         /**
8276          * Cancels bubbling of the event.
8277          */
8278         stopPropagation : function(){
8279             if(this.browserEvent){
8280                 if(this.type == 'mousedown'){
8281                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
8282                 }
8283                 E.stopPropagation(this.browserEvent);
8284             }
8285         },
8286
8287         /**
8288          * Gets the key code for the event.
8289          * @return {Number}
8290          */
8291         getCharCode : function(){
8292             return this.charCode || this.keyCode;
8293         },
8294
8295         /**
8296          * Returns a normalized keyCode for the event.
8297          * @return {Number} The key code
8298          */
8299         getKey : function(){
8300             var k = this.keyCode || this.charCode;
8301             return Roo.isSafari ? (safariKeys[k] || k) : k;
8302         },
8303
8304         /**
8305          * Gets the x coordinate of the event.
8306          * @return {Number}
8307          */
8308         getPageX : function(){
8309             return this.xy[0];
8310         },
8311
8312         /**
8313          * Gets the y coordinate of the event.
8314          * @return {Number}
8315          */
8316         getPageY : function(){
8317             return this.xy[1];
8318         },
8319
8320         /**
8321          * Gets the time of the event.
8322          * @return {Number}
8323          */
8324         getTime : function(){
8325             if(this.browserEvent){
8326                 return E.getTime(this.browserEvent);
8327             }
8328             return null;
8329         },
8330
8331         /**
8332          * Gets the page coordinates of the event.
8333          * @return {Array} The xy values like [x, y]
8334          */
8335         getXY : function(){
8336             return this.xy;
8337         },
8338
8339         /**
8340          * Gets the target for the event.
8341          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
8342          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8343                 search as a number or element (defaults to 10 || document.body)
8344          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8345          * @return {HTMLelement}
8346          */
8347         getTarget : function(selector, maxDepth, returnEl){
8348             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
8349         },
8350         /**
8351          * Gets the related target.
8352          * @return {HTMLElement}
8353          */
8354         getRelatedTarget : function(){
8355             if(this.browserEvent){
8356                 return E.getRelatedTarget(this.browserEvent);
8357             }
8358             return null;
8359         },
8360
8361         /**
8362          * Normalizes mouse wheel delta across browsers
8363          * @return {Number} The delta
8364          */
8365         getWheelDelta : function(){
8366             var e = this.browserEvent;
8367             var delta = 0;
8368             if(e.wheelDelta){ /* IE/Opera. */
8369                 delta = e.wheelDelta/120;
8370             }else if(e.detail){ /* Mozilla case. */
8371                 delta = -e.detail/3;
8372             }
8373             return delta;
8374         },
8375
8376         /**
8377          * Returns true if the control, meta, shift or alt key was pressed during this event.
8378          * @return {Boolean}
8379          */
8380         hasModifier : function(){
8381             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
8382         },
8383
8384         /**
8385          * Returns true if the target of this event equals el or is a child of el
8386          * @param {String/HTMLElement/Element} el
8387          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
8388          * @return {Boolean}
8389          */
8390         within : function(el, related){
8391             var t = this[related ? "getRelatedTarget" : "getTarget"]();
8392             return t && Roo.fly(el).contains(t);
8393         },
8394
8395         getPoint : function(){
8396             return new Roo.lib.Point(this.xy[0], this.xy[1]);
8397         }
8398     };
8399
8400     return new Roo.EventObjectImpl();
8401 }();
8402             
8403     /*
8404  * Based on:
8405  * Ext JS Library 1.1.1
8406  * Copyright(c) 2006-2007, Ext JS, LLC.
8407  *
8408  * Originally Released Under LGPL - original licence link has changed is not relivant.
8409  *
8410  * Fork - LGPL
8411  * <script type="text/javascript">
8412  */
8413
8414  
8415 // was in Composite Element!??!?!
8416  
8417 (function(){
8418     var D = Roo.lib.Dom;
8419     var E = Roo.lib.Event;
8420     var A = Roo.lib.Anim;
8421
8422     // local style camelizing for speed
8423     var propCache = {};
8424     var camelRe = /(-[a-z])/gi;
8425     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
8426     var view = document.defaultView;
8427
8428 /**
8429  * @class Roo.Element
8430  * Represents an Element in the DOM.<br><br>
8431  * Usage:<br>
8432 <pre><code>
8433 var el = Roo.get("my-div");
8434
8435 // or with getEl
8436 var el = getEl("my-div");
8437
8438 // or with a DOM element
8439 var el = Roo.get(myDivElement);
8440 </code></pre>
8441  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
8442  * each call instead of constructing a new one.<br><br>
8443  * <b>Animations</b><br />
8444  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
8445  * should either be a boolean (true) or an object literal with animation options. The animation options are:
8446 <pre>
8447 Option    Default   Description
8448 --------- --------  ---------------------------------------------
8449 duration  .35       The duration of the animation in seconds
8450 easing    easeOut   The YUI easing method
8451 callback  none      A function to execute when the anim completes
8452 scope     this      The scope (this) of the callback function
8453 </pre>
8454 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
8455 * manipulate the animation. Here's an example:
8456 <pre><code>
8457 var el = Roo.get("my-div");
8458
8459 // no animation
8460 el.setWidth(100);
8461
8462 // default animation
8463 el.setWidth(100, true);
8464
8465 // animation with some options set
8466 el.setWidth(100, {
8467     duration: 1,
8468     callback: this.foo,
8469     scope: this
8470 });
8471
8472 // using the "anim" property to get the Anim object
8473 var opt = {
8474     duration: 1,
8475     callback: this.foo,
8476     scope: this
8477 };
8478 el.setWidth(100, opt);
8479 ...
8480 if(opt.anim.isAnimated()){
8481     opt.anim.stop();
8482 }
8483 </code></pre>
8484 * <b> Composite (Collections of) Elements</b><br />
8485  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
8486  * @constructor Create a new Element directly.
8487  * @param {String/HTMLElement} element
8488  * @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).
8489  */
8490     Roo.Element = function(element, forceNew)
8491     {
8492         var dom = typeof element == "string" ?
8493                 document.getElementById(element) : element;
8494         
8495         this.listeners = {};
8496         
8497         if(!dom){ // invalid id/element
8498             return null;
8499         }
8500         var id = dom.id;
8501         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
8502             return Roo.Element.cache[id];
8503         }
8504
8505         /**
8506          * The DOM element
8507          * @type HTMLElement
8508          */
8509         this.dom = dom;
8510
8511         /**
8512          * The DOM element ID
8513          * @type String
8514          */
8515         this.id = id || Roo.id(dom);
8516         
8517         return this; // assumed for cctor?
8518     };
8519
8520     var El = Roo.Element;
8521
8522     El.prototype = {
8523         /**
8524          * The element's default display mode  (defaults to "") 
8525          * @type String
8526          */
8527         originalDisplay : "",
8528
8529         
8530         // note this is overridden in BS version..
8531         visibilityMode : 1, 
8532         /**
8533          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8534          * @type String
8535          */
8536         defaultUnit : "px",
8537         
8538         /**
8539          * Sets the element's visibility mode. When setVisible() is called it
8540          * will use this to determine whether to set the visibility or the display property.
8541          * @param visMode Element.VISIBILITY or Element.DISPLAY
8542          * @return {Roo.Element} this
8543          */
8544         setVisibilityMode : function(visMode){
8545             this.visibilityMode = visMode;
8546             return this;
8547         },
8548         /**
8549          * Convenience method for setVisibilityMode(Element.DISPLAY)
8550          * @param {String} display (optional) What to set display to when visible
8551          * @return {Roo.Element} this
8552          */
8553         enableDisplayMode : function(display){
8554             this.setVisibilityMode(El.DISPLAY);
8555             if(typeof display != "undefined") { this.originalDisplay = display; }
8556             return this;
8557         },
8558
8559         /**
8560          * 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)
8561          * @param {String} selector The simple selector to test
8562          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8563                 search as a number or element (defaults to 10 || document.body)
8564          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8565          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8566          */
8567         findParent : function(simpleSelector, maxDepth, returnEl){
8568             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8569             maxDepth = maxDepth || 50;
8570             if(typeof maxDepth != "number"){
8571                 stopEl = Roo.getDom(maxDepth);
8572                 maxDepth = 10;
8573             }
8574             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8575                 if(dq.is(p, simpleSelector)){
8576                     return returnEl ? Roo.get(p) : p;
8577                 }
8578                 depth++;
8579                 p = p.parentNode;
8580             }
8581             return null;
8582         },
8583
8584
8585         /**
8586          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8587          * @param {String} selector The simple selector to test
8588          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8589                 search as a number or element (defaults to 10 || document.body)
8590          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8591          * @return {HTMLElement} The matching DOM node (or null if no match was found)
8592          */
8593         findParentNode : function(simpleSelector, maxDepth, returnEl){
8594             var p = Roo.fly(this.dom.parentNode, '_internal');
8595             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8596         },
8597         
8598         /**
8599          * Looks at  the scrollable parent element
8600          */
8601         findScrollableParent : function()
8602         {
8603             var overflowRegex = /(auto|scroll)/;
8604             
8605             if(this.getStyle('position') === 'fixed'){
8606                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8607             }
8608             
8609             var excludeStaticParent = this.getStyle('position') === "absolute";
8610             
8611             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8612                 
8613                 if (excludeStaticParent && parent.getStyle('position') === "static") {
8614                     continue;
8615                 }
8616                 
8617                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8618                     return parent;
8619                 }
8620                 
8621                 if(parent.dom.nodeName.toLowerCase() == 'body'){
8622                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8623                 }
8624             }
8625             
8626             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8627         },
8628
8629         /**
8630          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8631          * This is a shortcut for findParentNode() that always returns an Roo.Element.
8632          * @param {String} selector The simple selector to test
8633          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8634                 search as a number or element (defaults to 10 || document.body)
8635          * @return {Roo.Element} The matching DOM node (or null if no match was found)
8636          */
8637         up : function(simpleSelector, maxDepth){
8638             return this.findParentNode(simpleSelector, maxDepth, true);
8639         },
8640
8641
8642
8643         /**
8644          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8645          * @param {String} selector The simple selector to test
8646          * @return {Boolean} True if this element matches the selector, else false
8647          */
8648         is : function(simpleSelector){
8649             return Roo.DomQuery.is(this.dom, simpleSelector);
8650         },
8651
8652         /**
8653          * Perform animation on this element.
8654          * @param {Object} args The YUI animation control args
8655          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8656          * @param {Function} onComplete (optional) Function to call when animation completes
8657          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8658          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8659          * @return {Roo.Element} this
8660          */
8661         animate : function(args, duration, onComplete, easing, animType){
8662             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8663             return this;
8664         },
8665
8666         /*
8667          * @private Internal animation call
8668          */
8669         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8670             animType = animType || 'run';
8671             opt = opt || {};
8672             var anim = Roo.lib.Anim[animType](
8673                 this.dom, args,
8674                 (opt.duration || defaultDur) || .35,
8675                 (opt.easing || defaultEase) || 'easeOut',
8676                 function(){
8677                     Roo.callback(cb, this);
8678                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8679                 },
8680                 this
8681             );
8682             opt.anim = anim;
8683             return anim;
8684         },
8685
8686         // private legacy anim prep
8687         preanim : function(a, i){
8688             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8689         },
8690
8691         /**
8692          * Removes worthless text nodes
8693          * @param {Boolean} forceReclean (optional) By default the element
8694          * keeps track if it has been cleaned already so
8695          * you can call this over and over. However, if you update the element and
8696          * need to force a reclean, you can pass true.
8697          */
8698         clean : function(forceReclean){
8699             if(this.isCleaned && forceReclean !== true){
8700                 return this;
8701             }
8702             var ns = /\S/;
8703             var d = this.dom, n = d.firstChild, ni = -1;
8704             while(n){
8705                 var nx = n.nextSibling;
8706                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8707                     d.removeChild(n);
8708                 }else{
8709                     n.nodeIndex = ++ni;
8710                 }
8711                 n = nx;
8712             }
8713             this.isCleaned = true;
8714             return this;
8715         },
8716
8717         // private
8718         calcOffsetsTo : function(el){
8719             el = Roo.get(el);
8720             var d = el.dom;
8721             var restorePos = false;
8722             if(el.getStyle('position') == 'static'){
8723                 el.position('relative');
8724                 restorePos = true;
8725             }
8726             var x = 0, y =0;
8727             var op = this.dom;
8728             while(op && op != d && op.tagName != 'HTML'){
8729                 x+= op.offsetLeft;
8730                 y+= op.offsetTop;
8731                 op = op.offsetParent;
8732             }
8733             if(restorePos){
8734                 el.position('static');
8735             }
8736             return [x, y];
8737         },
8738
8739         /**
8740          * Scrolls this element into view within the passed container.
8741          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8742          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8743          * @return {Roo.Element} this
8744          */
8745         scrollIntoView : function(container, hscroll){
8746             var c = Roo.getDom(container) || document.body;
8747             var el = this.dom;
8748
8749             var o = this.calcOffsetsTo(c),
8750                 l = o[0],
8751                 t = o[1],
8752                 b = t+el.offsetHeight,
8753                 r = l+el.offsetWidth;
8754
8755             var ch = c.clientHeight;
8756             var ct = parseInt(c.scrollTop, 10);
8757             var cl = parseInt(c.scrollLeft, 10);
8758             var cb = ct + ch;
8759             var cr = cl + c.clientWidth;
8760
8761             if(t < ct){
8762                 c.scrollTop = t;
8763             }else if(b > cb){
8764                 c.scrollTop = b-ch;
8765             }
8766
8767             if(hscroll !== false){
8768                 if(l < cl){
8769                     c.scrollLeft = l;
8770                 }else if(r > cr){
8771                     c.scrollLeft = r-c.clientWidth;
8772                 }
8773             }
8774             return this;
8775         },
8776
8777         // private
8778         scrollChildIntoView : function(child, hscroll){
8779             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8780         },
8781
8782         /**
8783          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8784          * the new height may not be available immediately.
8785          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8786          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8787          * @param {Function} onComplete (optional) Function to call when animation completes
8788          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8789          * @return {Roo.Element} this
8790          */
8791         autoHeight : function(animate, duration, onComplete, easing){
8792             var oldHeight = this.getHeight();
8793             this.clip();
8794             this.setHeight(1); // force clipping
8795             setTimeout(function(){
8796                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8797                 if(!animate){
8798                     this.setHeight(height);
8799                     this.unclip();
8800                     if(typeof onComplete == "function"){
8801                         onComplete();
8802                     }
8803                 }else{
8804                     this.setHeight(oldHeight); // restore original height
8805                     this.setHeight(height, animate, duration, function(){
8806                         this.unclip();
8807                         if(typeof onComplete == "function") { onComplete(); }
8808                     }.createDelegate(this), easing);
8809                 }
8810             }.createDelegate(this), 0);
8811             return this;
8812         },
8813
8814         /**
8815          * Returns true if this element is an ancestor of the passed element
8816          * @param {HTMLElement/String} el The element to check
8817          * @return {Boolean} True if this element is an ancestor of el, else false
8818          */
8819         contains : function(el){
8820             if(!el){return false;}
8821             return D.isAncestor(this.dom, el.dom ? el.dom : el);
8822         },
8823
8824         /**
8825          * Checks whether the element is currently visible using both visibility and display properties.
8826          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8827          * @return {Boolean} True if the element is currently visible, else false
8828          */
8829         isVisible : function(deep) {
8830             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8831             if(deep !== true || !vis){
8832                 return vis;
8833             }
8834             var p = this.dom.parentNode;
8835             while(p && p.tagName.toLowerCase() != "body"){
8836                 if(!Roo.fly(p, '_isVisible').isVisible()){
8837                     return false;
8838                 }
8839                 p = p.parentNode;
8840             }
8841             return true;
8842         },
8843
8844         /**
8845          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8846          * @param {String} selector The CSS selector
8847          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8848          * @return {CompositeElement/CompositeElementLite} The composite element
8849          */
8850         select : function(selector, unique){
8851             return El.select(selector, unique, this.dom);
8852         },
8853
8854         /**
8855          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8856          * @param {String} selector The CSS selector
8857          * @return {Array} An array of the matched nodes
8858          */
8859         query : function(selector, unique){
8860             return Roo.DomQuery.select(selector, this.dom);
8861         },
8862
8863         /**
8864          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8865          * @param {String} selector The CSS selector
8866          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8867          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8868          */
8869         child : function(selector, returnDom){
8870             var n = Roo.DomQuery.selectNode(selector, this.dom);
8871             return returnDom ? n : Roo.get(n);
8872         },
8873
8874         /**
8875          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8876          * @param {String} selector The CSS selector
8877          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8878          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8879          */
8880         down : function(selector, returnDom){
8881             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8882             return returnDom ? n : Roo.get(n);
8883         },
8884
8885         /**
8886          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8887          * @param {String} group The group the DD object is member of
8888          * @param {Object} config The DD config object
8889          * @param {Object} overrides An object containing methods to override/implement on the DD object
8890          * @return {Roo.dd.DD} The DD object
8891          */
8892         initDD : function(group, config, overrides){
8893             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8894             return Roo.apply(dd, overrides);
8895         },
8896
8897         /**
8898          * Initializes a {@link Roo.dd.DDProxy} object for this element.
8899          * @param {String} group The group the DDProxy object is member of
8900          * @param {Object} config The DDProxy config object
8901          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8902          * @return {Roo.dd.DDProxy} The DDProxy object
8903          */
8904         initDDProxy : function(group, config, overrides){
8905             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8906             return Roo.apply(dd, overrides);
8907         },
8908
8909         /**
8910          * Initializes a {@link Roo.dd.DDTarget} object for this element.
8911          * @param {String} group The group the DDTarget object is member of
8912          * @param {Object} config The DDTarget config object
8913          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8914          * @return {Roo.dd.DDTarget} The DDTarget object
8915          */
8916         initDDTarget : function(group, config, overrides){
8917             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8918             return Roo.apply(dd, overrides);
8919         },
8920
8921         /**
8922          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8923          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8924          * @param {Boolean} visible Whether the element is visible
8925          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8926          * @return {Roo.Element} this
8927          */
8928          setVisible : function(visible, animate){
8929             if(!animate || !A){
8930                 if(this.visibilityMode == El.DISPLAY){
8931                     this.setDisplayed(visible);
8932                 }else{
8933                     this.fixDisplay();
8934                     this.dom.style.visibility = visible ? "visible" : "hidden";
8935                 }
8936             }else{
8937                 // closure for composites
8938                 var dom = this.dom;
8939                 var visMode = this.visibilityMode;
8940                 if(visible){
8941                     this.setOpacity(.01);
8942                     this.setVisible(true);
8943                 }
8944                 this.anim({opacity: { to: (visible?1:0) }},
8945                       this.preanim(arguments, 1),
8946                       null, .35, 'easeIn', function(){
8947                          if(!visible){
8948                              if(visMode == El.DISPLAY){
8949                                  dom.style.display = "none";
8950                              }else{
8951                                  dom.style.visibility = "hidden";
8952                              }
8953                              Roo.get(dom).setOpacity(1);
8954                          }
8955                      });
8956             }
8957             return this;
8958         },
8959
8960         /**
8961          * Returns true if display is not "none"
8962          * @return {Boolean}
8963          */
8964         isDisplayed : function() {
8965             return this.getStyle("display") != "none";
8966         },
8967
8968         /**
8969          * Toggles the element's visibility or display, depending on visibility mode.
8970          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8971          * @return {Roo.Element} this
8972          */
8973         toggle : function(animate){
8974             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8975             return this;
8976         },
8977
8978         /**
8979          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8980          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8981          * @return {Roo.Element} this
8982          */
8983         setDisplayed : function(value) {
8984             if(typeof value == "boolean"){
8985                value = value ? this.originalDisplay : "none";
8986             }
8987             this.setStyle("display", value);
8988             return this;
8989         },
8990
8991         /**
8992          * Tries to focus the element. Any exceptions are caught and ignored.
8993          * @return {Roo.Element} this
8994          */
8995         focus : function() {
8996             try{
8997                 this.dom.focus();
8998             }catch(e){}
8999             return this;
9000         },
9001
9002         /**
9003          * Tries to blur the element. Any exceptions are caught and ignored.
9004          * @return {Roo.Element} this
9005          */
9006         blur : function() {
9007             try{
9008                 this.dom.blur();
9009             }catch(e){}
9010             return this;
9011         },
9012
9013         /**
9014          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
9015          * @param {String/Array} className The CSS class to add, or an array of classes
9016          * @return {Roo.Element} this
9017          */
9018         addClass : function(className){
9019             if(className instanceof Array){
9020                 for(var i = 0, len = className.length; i < len; i++) {
9021                     this.addClass(className[i]);
9022                 }
9023             }else{
9024                 if(className && !this.hasClass(className)){
9025                     if (this.dom instanceof SVGElement) {
9026                         this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
9027                     } else {
9028                         this.dom.className = this.dom.className + " " + className;
9029                     }
9030                 }
9031             }
9032             return this;
9033         },
9034
9035         /**
9036          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
9037          * @param {String/Array} className The CSS class to add, or an array of classes
9038          * @return {Roo.Element} this
9039          */
9040         radioClass : function(className){
9041             var siblings = this.dom.parentNode.childNodes;
9042             for(var i = 0; i < siblings.length; i++) {
9043                 var s = siblings[i];
9044                 if(s.nodeType == 1){
9045                     Roo.get(s).removeClass(className);
9046                 }
9047             }
9048             this.addClass(className);
9049             return this;
9050         },
9051
9052         /**
9053          * Removes one or more CSS classes from the element.
9054          * @param {String/Array} className The CSS class to remove, or an array of classes
9055          * @return {Roo.Element} this
9056          */
9057         removeClass : function(className){
9058             
9059             var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
9060             if(!className || !cn){
9061                 return this;
9062             }
9063             if(className instanceof Array){
9064                 for(var i = 0, len = className.length; i < len; i++) {
9065                     this.removeClass(className[i]);
9066                 }
9067             }else{
9068                 if(this.hasClass(className)){
9069                     var re = this.classReCache[className];
9070                     if (!re) {
9071                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
9072                        this.classReCache[className] = re;
9073                     }
9074                     if (this.dom instanceof SVGElement) {
9075                         this.dom.className.baseVal = cn.replace(re, " ");
9076                     } else {
9077                         this.dom.className = cn.replace(re, " ");
9078                     }
9079                 }
9080             }
9081             return this;
9082         },
9083
9084         // private
9085         classReCache: {},
9086
9087         /**
9088          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
9089          * @param {String} className The CSS class to toggle
9090          * @return {Roo.Element} this
9091          */
9092         toggleClass : function(className){
9093             if(this.hasClass(className)){
9094                 this.removeClass(className);
9095             }else{
9096                 this.addClass(className);
9097             }
9098             return this;
9099         },
9100
9101         /**
9102          * Checks if the specified CSS class exists on this element's DOM node.
9103          * @param {String} className The CSS class to check for
9104          * @return {Boolean} True if the class exists, else false
9105          */
9106         hasClass : function(className){
9107             if (this.dom instanceof SVGElement) {
9108                 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
9109             } 
9110             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
9111         },
9112
9113         /**
9114          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
9115          * @param {String} oldClassName The CSS class to replace
9116          * @param {String} newClassName The replacement CSS class
9117          * @return {Roo.Element} this
9118          */
9119         replaceClass : function(oldClassName, newClassName){
9120             this.removeClass(oldClassName);
9121             this.addClass(newClassName);
9122             return this;
9123         },
9124
9125         /**
9126          * Returns an object with properties matching the styles requested.
9127          * For example, el.getStyles('color', 'font-size', 'width') might return
9128          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
9129          * @param {String} style1 A style name
9130          * @param {String} style2 A style name
9131          * @param {String} etc.
9132          * @return {Object} The style object
9133          */
9134         getStyles : function(){
9135             var a = arguments, len = a.length, r = {};
9136             for(var i = 0; i < len; i++){
9137                 r[a[i]] = this.getStyle(a[i]);
9138             }
9139             return r;
9140         },
9141
9142         /**
9143          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
9144          * @param {String} property The style property whose value is returned.
9145          * @return {String} The current value of the style property for this element.
9146          */
9147         getStyle : function(){
9148             return view && view.getComputedStyle ?
9149                 function(prop){
9150                     var el = this.dom, v, cs, camel;
9151                     if(prop == 'float'){
9152                         prop = "cssFloat";
9153                     }
9154                     if(el.style && (v = el.style[prop])){
9155                         return v;
9156                     }
9157                     if(cs = view.getComputedStyle(el, "")){
9158                         if(!(camel = propCache[prop])){
9159                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
9160                         }
9161                         return cs[camel];
9162                     }
9163                     return null;
9164                 } :
9165                 function(prop){
9166                     var el = this.dom, v, cs, camel;
9167                     if(prop == 'opacity'){
9168                         if(typeof el.style.filter == 'string'){
9169                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
9170                             if(m){
9171                                 var fv = parseFloat(m[1]);
9172                                 if(!isNaN(fv)){
9173                                     return fv ? fv / 100 : 0;
9174                                 }
9175                             }
9176                         }
9177                         return 1;
9178                     }else if(prop == 'float'){
9179                         prop = "styleFloat";
9180                     }
9181                     if(!(camel = propCache[prop])){
9182                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
9183                     }
9184                     if(v = el.style[camel]){
9185                         return v;
9186                     }
9187                     if(cs = el.currentStyle){
9188                         return cs[camel];
9189                     }
9190                     return null;
9191                 };
9192         }(),
9193
9194         /**
9195          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
9196          * @param {String/Object} property The style property to be set, or an object of multiple styles.
9197          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
9198          * @return {Roo.Element} this
9199          */
9200         setStyle : function(prop, value){
9201             if(typeof prop == "string"){
9202                 
9203                 if (prop == 'float') {
9204                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
9205                     return this;
9206                 }
9207                 
9208                 var camel;
9209                 if(!(camel = propCache[prop])){
9210                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
9211                 }
9212                 
9213                 if(camel == 'opacity') {
9214                     this.setOpacity(value);
9215                 }else{
9216                     this.dom.style[camel] = value;
9217                 }
9218             }else{
9219                 for(var style in prop){
9220                     if(typeof prop[style] != "function"){
9221                        this.setStyle(style, prop[style]);
9222                     }
9223                 }
9224             }
9225             return this;
9226         },
9227
9228         /**
9229          * More flexible version of {@link #setStyle} for setting style properties.
9230          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
9231          * a function which returns such a specification.
9232          * @return {Roo.Element} this
9233          */
9234         applyStyles : function(style){
9235             Roo.DomHelper.applyStyles(this.dom, style);
9236             return this;
9237         },
9238
9239         /**
9240           * 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).
9241           * @return {Number} The X position of the element
9242           */
9243         getX : function(){
9244             return D.getX(this.dom);
9245         },
9246
9247         /**
9248           * 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).
9249           * @return {Number} The Y position of the element
9250           */
9251         getY : function(){
9252             return D.getY(this.dom);
9253         },
9254
9255         /**
9256           * 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).
9257           * @return {Array} The XY position of the element
9258           */
9259         getXY : function(){
9260             return D.getXY(this.dom);
9261         },
9262
9263         /**
9264          * 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).
9265          * @param {Number} The X position of the element
9266          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9267          * @return {Roo.Element} this
9268          */
9269         setX : function(x, animate){
9270             if(!animate || !A){
9271                 D.setX(this.dom, x);
9272             }else{
9273                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
9274             }
9275             return this;
9276         },
9277
9278         /**
9279          * 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).
9280          * @param {Number} The Y position of the element
9281          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9282          * @return {Roo.Element} this
9283          */
9284         setY : function(y, animate){
9285             if(!animate || !A){
9286                 D.setY(this.dom, y);
9287             }else{
9288                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
9289             }
9290             return this;
9291         },
9292
9293         /**
9294          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
9295          * @param {String} left The left CSS property value
9296          * @return {Roo.Element} this
9297          */
9298         setLeft : function(left){
9299             this.setStyle("left", this.addUnits(left));
9300             return this;
9301         },
9302
9303         /**
9304          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
9305          * @param {String} top The top CSS property value
9306          * @return {Roo.Element} this
9307          */
9308         setTop : function(top){
9309             this.setStyle("top", this.addUnits(top));
9310             return this;
9311         },
9312
9313         /**
9314          * Sets the element's CSS right style.
9315          * @param {String} right The right CSS property value
9316          * @return {Roo.Element} this
9317          */
9318         setRight : function(right){
9319             this.setStyle("right", this.addUnits(right));
9320             return this;
9321         },
9322
9323         /**
9324          * Sets the element's CSS bottom style.
9325          * @param {String} bottom The bottom CSS property value
9326          * @return {Roo.Element} this
9327          */
9328         setBottom : function(bottom){
9329             this.setStyle("bottom", this.addUnits(bottom));
9330             return this;
9331         },
9332
9333         /**
9334          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9335          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9336          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9337          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9338          * @return {Roo.Element} this
9339          */
9340         setXY : function(pos, animate){
9341             if(!animate || !A){
9342                 D.setXY(this.dom, pos);
9343             }else{
9344                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
9345             }
9346             return this;
9347         },
9348
9349         /**
9350          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9351          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9352          * @param {Number} x X value for new position (coordinates are page-based)
9353          * @param {Number} y Y value for new position (coordinates are page-based)
9354          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9355          * @return {Roo.Element} this
9356          */
9357         setLocation : function(x, y, animate){
9358             this.setXY([x, y], this.preanim(arguments, 2));
9359             return this;
9360         },
9361
9362         /**
9363          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9364          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9365          * @param {Number} x X value for new position (coordinates are page-based)
9366          * @param {Number} y Y value for new position (coordinates are page-based)
9367          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9368          * @return {Roo.Element} this
9369          */
9370         moveTo : function(x, y, animate){
9371             this.setXY([x, y], this.preanim(arguments, 2));
9372             return this;
9373         },
9374
9375         /**
9376          * Returns the region of the given element.
9377          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9378          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
9379          */
9380         getRegion : function(){
9381             return D.getRegion(this.dom);
9382         },
9383
9384         /**
9385          * Returns the offset height of the element
9386          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
9387          * @return {Number} The element's height
9388          */
9389         getHeight : function(contentHeight){
9390             var h = this.dom.offsetHeight || 0;
9391             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
9392         },
9393
9394         /**
9395          * Returns the offset width of the element
9396          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
9397          * @return {Number} The element's width
9398          */
9399         getWidth : function(contentWidth){
9400             var w = this.dom.offsetWidth || 0;
9401             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
9402         },
9403
9404         /**
9405          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
9406          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
9407          * if a height has not been set using CSS.
9408          * @return {Number}
9409          */
9410         getComputedHeight : function(){
9411             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
9412             if(!h){
9413                 h = parseInt(this.getStyle('height'), 10) || 0;
9414                 if(!this.isBorderBox()){
9415                     h += this.getFrameWidth('tb');
9416                 }
9417             }
9418             return h;
9419         },
9420
9421         /**
9422          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
9423          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
9424          * if a width has not been set using CSS.
9425          * @return {Number}
9426          */
9427         getComputedWidth : function(){
9428             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
9429             if(!w){
9430                 w = parseInt(this.getStyle('width'), 10) || 0;
9431                 if(!this.isBorderBox()){
9432                     w += this.getFrameWidth('lr');
9433                 }
9434             }
9435             return w;
9436         },
9437
9438         /**
9439          * Returns the size of the element.
9440          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
9441          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
9442          */
9443         getSize : function(contentSize){
9444             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
9445         },
9446
9447         /**
9448          * Returns the width and height of the viewport.
9449          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
9450          */
9451         getViewSize : function(){
9452             var d = this.dom, doc = document, aw = 0, ah = 0;
9453             if(d == doc || d == doc.body){
9454                 return {width : D.getViewWidth(), height: D.getViewHeight()};
9455             }else{
9456                 return {
9457                     width : d.clientWidth,
9458                     height: d.clientHeight
9459                 };
9460             }
9461         },
9462
9463         /**
9464          * Returns the value of the "value" attribute
9465          * @param {Boolean} asNumber true to parse the value as a number
9466          * @return {String/Number}
9467          */
9468         getValue : function(asNumber){
9469             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
9470         },
9471
9472         // private
9473         adjustWidth : function(width){
9474             if(typeof width == "number"){
9475                 if(this.autoBoxAdjust && !this.isBorderBox()){
9476                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9477                 }
9478                 if(width < 0){
9479                     width = 0;
9480                 }
9481             }
9482             return width;
9483         },
9484
9485         // private
9486         adjustHeight : function(height){
9487             if(typeof height == "number"){
9488                if(this.autoBoxAdjust && !this.isBorderBox()){
9489                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9490                }
9491                if(height < 0){
9492                    height = 0;
9493                }
9494             }
9495             return height;
9496         },
9497
9498         /**
9499          * Set the width of the element
9500          * @param {Number} width The new width
9501          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9502          * @return {Roo.Element} this
9503          */
9504         setWidth : function(width, animate){
9505             width = this.adjustWidth(width);
9506             if(!animate || !A){
9507                 this.dom.style.width = this.addUnits(width);
9508             }else{
9509                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
9510             }
9511             return this;
9512         },
9513
9514         /**
9515          * Set the height of the element
9516          * @param {Number} height The new height
9517          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9518          * @return {Roo.Element} this
9519          */
9520          setHeight : function(height, animate){
9521             height = this.adjustHeight(height);
9522             if(!animate || !A){
9523                 this.dom.style.height = this.addUnits(height);
9524             }else{
9525                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9526             }
9527             return this;
9528         },
9529
9530         /**
9531          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9532          * @param {Number} width The new width
9533          * @param {Number} height The new height
9534          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9535          * @return {Roo.Element} this
9536          */
9537          setSize : function(width, height, animate){
9538             if(typeof width == "object"){ // in case of object from getSize()
9539                 height = width.height; width = width.width;
9540             }
9541             width = this.adjustWidth(width); height = this.adjustHeight(height);
9542             if(!animate || !A){
9543                 this.dom.style.width = this.addUnits(width);
9544                 this.dom.style.height = this.addUnits(height);
9545             }else{
9546                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9547             }
9548             return this;
9549         },
9550
9551         /**
9552          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9553          * @param {Number} x X value for new position (coordinates are page-based)
9554          * @param {Number} y Y value for new position (coordinates are page-based)
9555          * @param {Number} width The new width
9556          * @param {Number} height The new height
9557          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9558          * @return {Roo.Element} this
9559          */
9560         setBounds : function(x, y, width, height, animate){
9561             if(!animate || !A){
9562                 this.setSize(width, height);
9563                 this.setLocation(x, y);
9564             }else{
9565                 width = this.adjustWidth(width); height = this.adjustHeight(height);
9566                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9567                               this.preanim(arguments, 4), 'motion');
9568             }
9569             return this;
9570         },
9571
9572         /**
9573          * 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.
9574          * @param {Roo.lib.Region} region The region to fill
9575          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9576          * @return {Roo.Element} this
9577          */
9578         setRegion : function(region, animate){
9579             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9580             return this;
9581         },
9582
9583         /**
9584          * Appends an event handler
9585          *
9586          * @param {String}   eventName     The type of event to append
9587          * @param {Function} fn        The method the event invokes
9588          * @param {Object} scope       (optional) The scope (this object) of the fn
9589          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9590          */
9591         addListener : function(eventName, fn, scope, options)
9592         {
9593             if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9594                 this.addListener('touchstart', this.onTapHandler, this);
9595             }
9596             
9597             // we need to handle a special case where dom element is a svg element.
9598             // in this case we do not actua
9599             if (!this.dom) {
9600                 return;
9601             }
9602             
9603             if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9604                 if (typeof(this.listeners[eventName]) == 'undefined') {
9605                     this.listeners[eventName] =  new Roo.util.Event(this, eventName);
9606                 }
9607                 this.listeners[eventName].addListener(fn, scope, options);
9608                 return;
9609             }
9610             
9611                 
9612             Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
9613             
9614             
9615         },
9616         tapedTwice : false,
9617         onTapHandler : function(event)
9618         {
9619             if(!this.tapedTwice) {
9620                 this.tapedTwice = true;
9621                 var s = this;
9622                 setTimeout( function() {
9623                     s.tapedTwice = false;
9624                 }, 300 );
9625                 return;
9626             }
9627             event.preventDefault();
9628             var revent = new MouseEvent('dblclick',  {
9629                 view: window,
9630                 bubbles: true,
9631                 cancelable: true
9632             });
9633              
9634             this.dom.dispatchEvent(revent);
9635             //action on double tap goes below
9636              
9637         }, 
9638  
9639         /**
9640          * Removes an event handler from this element
9641          * @param {String} eventName the type of event to remove
9642          * @param {Function} fn the method the event invokes
9643          * @param {Function} scope (needed for svg fake listeners)
9644          * @return {Roo.Element} this
9645          */
9646         removeListener : function(eventName, fn, scope){
9647             Roo.EventManager.removeListener(this.dom,  eventName, fn);
9648             if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
9649                 return this;
9650             }
9651             this.listeners[eventName].removeListener(fn, scope);
9652             return this;
9653         },
9654
9655         /**
9656          * Removes all previous added listeners from this element
9657          * @return {Roo.Element} this
9658          */
9659         removeAllListeners : function(){
9660             E.purgeElement(this.dom);
9661             this.listeners = {};
9662             return this;
9663         },
9664
9665         relayEvent : function(eventName, observable){
9666             this.on(eventName, function(e){
9667                 observable.fireEvent(eventName, e);
9668             });
9669         },
9670
9671         
9672         /**
9673          * Set the opacity of the element
9674          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9675          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9676          * @return {Roo.Element} this
9677          */
9678          setOpacity : function(opacity, animate){
9679             if(!animate || !A){
9680                 var s = this.dom.style;
9681                 if(Roo.isIE){
9682                     s.zoom = 1;
9683                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9684                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9685                 }else{
9686                     s.opacity = opacity;
9687                 }
9688             }else{
9689                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9690             }
9691             return this;
9692         },
9693
9694         /**
9695          * Gets the left X coordinate
9696          * @param {Boolean} local True to get the local css position instead of page coordinate
9697          * @return {Number}
9698          */
9699         getLeft : function(local){
9700             if(!local){
9701                 return this.getX();
9702             }else{
9703                 return parseInt(this.getStyle("left"), 10) || 0;
9704             }
9705         },
9706
9707         /**
9708          * Gets the right X coordinate of the element (element X position + element width)
9709          * @param {Boolean} local True to get the local css position instead of page coordinate
9710          * @return {Number}
9711          */
9712         getRight : function(local){
9713             if(!local){
9714                 return this.getX() + this.getWidth();
9715             }else{
9716                 return (this.getLeft(true) + this.getWidth()) || 0;
9717             }
9718         },
9719
9720         /**
9721          * Gets the top Y coordinate
9722          * @param {Boolean} local True to get the local css position instead of page coordinate
9723          * @return {Number}
9724          */
9725         getTop : function(local) {
9726             if(!local){
9727                 return this.getY();
9728             }else{
9729                 return parseInt(this.getStyle("top"), 10) || 0;
9730             }
9731         },
9732
9733         /**
9734          * Gets the bottom Y coordinate of the element (element Y position + element height)
9735          * @param {Boolean} local True to get the local css position instead of page coordinate
9736          * @return {Number}
9737          */
9738         getBottom : function(local){
9739             if(!local){
9740                 return this.getY() + this.getHeight();
9741             }else{
9742                 return (this.getTop(true) + this.getHeight()) || 0;
9743             }
9744         },
9745
9746         /**
9747         * Initializes positioning on this element. If a desired position is not passed, it will make the
9748         * the element positioned relative IF it is not already positioned.
9749         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9750         * @param {Number} zIndex (optional) The zIndex to apply
9751         * @param {Number} x (optional) Set the page X position
9752         * @param {Number} y (optional) Set the page Y position
9753         */
9754         position : function(pos, zIndex, x, y){
9755             if(!pos){
9756                if(this.getStyle('position') == 'static'){
9757                    this.setStyle('position', 'relative');
9758                }
9759             }else{
9760                 this.setStyle("position", pos);
9761             }
9762             if(zIndex){
9763                 this.setStyle("z-index", zIndex);
9764             }
9765             if(x !== undefined && y !== undefined){
9766                 this.setXY([x, y]);
9767             }else if(x !== undefined){
9768                 this.setX(x);
9769             }else if(y !== undefined){
9770                 this.setY(y);
9771             }
9772         },
9773
9774         /**
9775         * Clear positioning back to the default when the document was loaded
9776         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9777         * @return {Roo.Element} this
9778          */
9779         clearPositioning : function(value){
9780             value = value ||'';
9781             this.setStyle({
9782                 "left": value,
9783                 "right": value,
9784                 "top": value,
9785                 "bottom": value,
9786                 "z-index": "",
9787                 "position" : "static"
9788             });
9789             return this;
9790         },
9791
9792         /**
9793         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9794         * snapshot before performing an update and then restoring the element.
9795         * @return {Object}
9796         */
9797         getPositioning : function(){
9798             var l = this.getStyle("left");
9799             var t = this.getStyle("top");
9800             return {
9801                 "position" : this.getStyle("position"),
9802                 "left" : l,
9803                 "right" : l ? "" : this.getStyle("right"),
9804                 "top" : t,
9805                 "bottom" : t ? "" : this.getStyle("bottom"),
9806                 "z-index" : this.getStyle("z-index")
9807             };
9808         },
9809
9810         /**
9811          * Gets the width of the border(s) for the specified side(s)
9812          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9813          * passing lr would get the border (l)eft width + the border (r)ight width.
9814          * @return {Number} The width of the sides passed added together
9815          */
9816         getBorderWidth : function(side){
9817             return this.addStyles(side, El.borders);
9818         },
9819
9820         /**
9821          * Gets the width of the padding(s) for the specified side(s)
9822          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9823          * passing lr would get the padding (l)eft + the padding (r)ight.
9824          * @return {Number} The padding of the sides passed added together
9825          */
9826         getPadding : function(side){
9827             return this.addStyles(side, El.paddings);
9828         },
9829
9830         /**
9831         * Set positioning with an object returned by getPositioning().
9832         * @param {Object} posCfg
9833         * @return {Roo.Element} this
9834          */
9835         setPositioning : function(pc){
9836             this.applyStyles(pc);
9837             if(pc.right == "auto"){
9838                 this.dom.style.right = "";
9839             }
9840             if(pc.bottom == "auto"){
9841                 this.dom.style.bottom = "";
9842             }
9843             return this;
9844         },
9845
9846         // private
9847         fixDisplay : function(){
9848             if(this.getStyle("display") == "none"){
9849                 this.setStyle("visibility", "hidden");
9850                 this.setStyle("display", this.originalDisplay); // first try reverting to default
9851                 if(this.getStyle("display") == "none"){ // if that fails, default to block
9852                     this.setStyle("display", "block");
9853                 }
9854             }
9855         },
9856
9857         /**
9858          * Quick set left and top adding default units
9859          * @param {String} left The left CSS property value
9860          * @param {String} top The top CSS property value
9861          * @return {Roo.Element} this
9862          */
9863          setLeftTop : function(left, top){
9864             this.dom.style.left = this.addUnits(left);
9865             this.dom.style.top = this.addUnits(top);
9866             return this;
9867         },
9868
9869         /**
9870          * Move this element relative to its current position.
9871          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9872          * @param {Number} distance How far to move the element in pixels
9873          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9874          * @return {Roo.Element} this
9875          */
9876          move : function(direction, distance, animate){
9877             var xy = this.getXY();
9878             direction = direction.toLowerCase();
9879             switch(direction){
9880                 case "l":
9881                 case "left":
9882                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9883                     break;
9884                case "r":
9885                case "right":
9886                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9887                     break;
9888                case "t":
9889                case "top":
9890                case "up":
9891                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9892                     break;
9893                case "b":
9894                case "bottom":
9895                case "down":
9896                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9897                     break;
9898             }
9899             return this;
9900         },
9901
9902         /**
9903          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9904          * @return {Roo.Element} this
9905          */
9906         clip : function(){
9907             if(!this.isClipped){
9908                this.isClipped = true;
9909                this.originalClip = {
9910                    "o": this.getStyle("overflow"),
9911                    "x": this.getStyle("overflow-x"),
9912                    "y": this.getStyle("overflow-y")
9913                };
9914                this.setStyle("overflow", "hidden");
9915                this.setStyle("overflow-x", "hidden");
9916                this.setStyle("overflow-y", "hidden");
9917             }
9918             return this;
9919         },
9920
9921         /**
9922          *  Return clipping (overflow) to original clipping before clip() was called
9923          * @return {Roo.Element} this
9924          */
9925         unclip : function(){
9926             if(this.isClipped){
9927                 this.isClipped = false;
9928                 var o = this.originalClip;
9929                 if(o.o){this.setStyle("overflow", o.o);}
9930                 if(o.x){this.setStyle("overflow-x", o.x);}
9931                 if(o.y){this.setStyle("overflow-y", o.y);}
9932             }
9933             return this;
9934         },
9935
9936
9937         /**
9938          * Gets the x,y coordinates specified by the anchor position on the element.
9939          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
9940          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9941          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
9942          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9943          * @return {Array} [x, y] An array containing the element's x and y coordinates
9944          */
9945         getAnchorXY : function(anchor, local, s){
9946             //Passing a different size is useful for pre-calculating anchors,
9947             //especially for anchored animations that change the el size.
9948
9949             var w, h, vp = false;
9950             if(!s){
9951                 var d = this.dom;
9952                 if(d == document.body || d == document){
9953                     vp = true;
9954                     w = D.getViewWidth(); h = D.getViewHeight();
9955                 }else{
9956                     w = this.getWidth(); h = this.getHeight();
9957                 }
9958             }else{
9959                 w = s.width;  h = s.height;
9960             }
9961             var x = 0, y = 0, r = Math.round;
9962             switch((anchor || "tl").toLowerCase()){
9963                 case "c":
9964                     x = r(w*.5);
9965                     y = r(h*.5);
9966                 break;
9967                 case "t":
9968                     x = r(w*.5);
9969                     y = 0;
9970                 break;
9971                 case "l":
9972                     x = 0;
9973                     y = r(h*.5);
9974                 break;
9975                 case "r":
9976                     x = w;
9977                     y = r(h*.5);
9978                 break;
9979                 case "b":
9980                     x = r(w*.5);
9981                     y = h;
9982                 break;
9983                 case "tl":
9984                     x = 0;
9985                     y = 0;
9986                 break;
9987                 case "bl":
9988                     x = 0;
9989                     y = h;
9990                 break;
9991                 case "br":
9992                     x = w;
9993                     y = h;
9994                 break;
9995                 case "tr":
9996                     x = w;
9997                     y = 0;
9998                 break;
9999             }
10000             if(local === true){
10001                 return [x, y];
10002             }
10003             if(vp){
10004                 var sc = this.getScroll();
10005                 return [x + sc.left, y + sc.top];
10006             }
10007             //Add the element's offset xy
10008             var o = this.getXY();
10009             return [x+o[0], y+o[1]];
10010         },
10011
10012         /**
10013          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
10014          * supported position values.
10015          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10016          * @param {String} position The position to align to.
10017          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10018          * @return {Array} [x, y]
10019          */
10020         getAlignToXY : function(el, p, o)
10021         {
10022             el = Roo.get(el);
10023             var d = this.dom;
10024             if(!el.dom){
10025                 throw "Element.alignTo with an element that doesn't exist";
10026             }
10027             var c = false; //constrain to viewport
10028             var p1 = "", p2 = "";
10029             o = o || [0,0];
10030
10031             if(!p){
10032                 p = "tl-bl";
10033             }else if(p == "?"){
10034                 p = "tl-bl?";
10035             }else if(p.indexOf("-") == -1){
10036                 p = "tl-" + p;
10037             }
10038             p = p.toLowerCase();
10039             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
10040             if(!m){
10041                throw "Element.alignTo with an invalid alignment " + p;
10042             }
10043             p1 = m[1]; p2 = m[2]; c = !!m[3];
10044
10045             //Subtract the aligned el's internal xy from the target's offset xy
10046             //plus custom offset to get the aligned el's new offset xy
10047             var a1 = this.getAnchorXY(p1, true);
10048             var a2 = el.getAnchorXY(p2, false);
10049             var x = a2[0] - a1[0] + o[0];
10050             var y = a2[1] - a1[1] + o[1];
10051             if(c){
10052                 //constrain the aligned el to viewport if necessary
10053                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
10054                 // 5px of margin for ie
10055                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
10056
10057                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
10058                 //perpendicular to the vp border, allow the aligned el to slide on that border,
10059                 //otherwise swap the aligned el to the opposite border of the target.
10060                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
10061                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
10062                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
10063                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
10064
10065                var doc = document;
10066                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
10067                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
10068
10069                if((x+w) > dw + scrollX){
10070                     x = swapX ? r.left-w : dw+scrollX-w;
10071                 }
10072                if(x < scrollX){
10073                    x = swapX ? r.right : scrollX;
10074                }
10075                if((y+h) > dh + scrollY){
10076                     y = swapY ? r.top-h : dh+scrollY-h;
10077                 }
10078                if (y < scrollY){
10079                    y = swapY ? r.bottom : scrollY;
10080                }
10081             }
10082             return [x,y];
10083         },
10084
10085         // private
10086         getConstrainToXY : function(){
10087             var os = {top:0, left:0, bottom:0, right: 0};
10088
10089             return function(el, local, offsets, proposedXY){
10090                 el = Roo.get(el);
10091                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
10092
10093                 var vw, vh, vx = 0, vy = 0;
10094                 if(el.dom == document.body || el.dom == document){
10095                     vw = Roo.lib.Dom.getViewWidth();
10096                     vh = Roo.lib.Dom.getViewHeight();
10097                 }else{
10098                     vw = el.dom.clientWidth;
10099                     vh = el.dom.clientHeight;
10100                     if(!local){
10101                         var vxy = el.getXY();
10102                         vx = vxy[0];
10103                         vy = vxy[1];
10104                     }
10105                 }
10106
10107                 var s = el.getScroll();
10108
10109                 vx += offsets.left + s.left;
10110                 vy += offsets.top + s.top;
10111
10112                 vw -= offsets.right;
10113                 vh -= offsets.bottom;
10114
10115                 var vr = vx+vw;
10116                 var vb = vy+vh;
10117
10118                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
10119                 var x = xy[0], y = xy[1];
10120                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
10121
10122                 // only move it if it needs it
10123                 var moved = false;
10124
10125                 // first validate right/bottom
10126                 if((x + w) > vr){
10127                     x = vr - w;
10128                     moved = true;
10129                 }
10130                 if((y + h) > vb){
10131                     y = vb - h;
10132                     moved = true;
10133                 }
10134                 // then make sure top/left isn't negative
10135                 if(x < vx){
10136                     x = vx;
10137                     moved = true;
10138                 }
10139                 if(y < vy){
10140                     y = vy;
10141                     moved = true;
10142                 }
10143                 return moved ? [x, y] : false;
10144             };
10145         }(),
10146
10147         // private
10148         adjustForConstraints : function(xy, parent, offsets){
10149             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
10150         },
10151
10152         /**
10153          * Aligns this element with another element relative to the specified anchor points. If the other element is the
10154          * document it aligns it to the viewport.
10155          * The position parameter is optional, and can be specified in any one of the following formats:
10156          * <ul>
10157          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
10158          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
10159          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
10160          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
10161          *   <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
10162          *       element's anchor point, and the second value is used as the target's anchor point.</li>
10163          * </ul>
10164          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
10165          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
10166          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
10167          * that specified in order to enforce the viewport constraints.
10168          * Following are all of the supported anchor positions:
10169     <pre>
10170     Value  Description
10171     -----  -----------------------------
10172     tl     The top left corner (default)
10173     t      The center of the top edge
10174     tr     The top right corner
10175     l      The center of the left edge
10176     c      In the center of the element
10177     r      The center of the right edge
10178     bl     The bottom left corner
10179     b      The center of the bottom edge
10180     br     The bottom right corner
10181     </pre>
10182     Example Usage:
10183     <pre><code>
10184     // align el to other-el using the default positioning ("tl-bl", non-constrained)
10185     el.alignTo("other-el");
10186
10187     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
10188     el.alignTo("other-el", "tr?");
10189
10190     // align the bottom right corner of el with the center left edge of other-el
10191     el.alignTo("other-el", "br-l?");
10192
10193     // align the center of el with the bottom left corner of other-el and
10194     // adjust the x position by -6 pixels (and the y position by 0)
10195     el.alignTo("other-el", "c-bl", [-6, 0]);
10196     </code></pre>
10197          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10198          * @param {String} position The position to align to.
10199          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10200          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10201          * @return {Roo.Element} this
10202          */
10203         alignTo : function(element, position, offsets, animate){
10204             var xy = this.getAlignToXY(element, position, offsets);
10205             this.setXY(xy, this.preanim(arguments, 3));
10206             return this;
10207         },
10208
10209         /**
10210          * Anchors an element to another element and realigns it when the window is resized.
10211          * @param {String/HTMLElement/Roo.Element} element The element to align to.
10212          * @param {String} position The position to align to.
10213          * @param {Array} offsets (optional) Offset the positioning by [x, y]
10214          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
10215          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
10216          * is a number, it is used as the buffer delay (defaults to 50ms).
10217          * @param {Function} callback The function to call after the animation finishes
10218          * @return {Roo.Element} this
10219          */
10220         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
10221             var action = function(){
10222                 this.alignTo(el, alignment, offsets, animate);
10223                 Roo.callback(callback, this);
10224             };
10225             Roo.EventManager.onWindowResize(action, this);
10226             var tm = typeof monitorScroll;
10227             if(tm != 'undefined'){
10228                 Roo.EventManager.on(window, 'scroll', action, this,
10229                     {buffer: tm == 'number' ? monitorScroll : 50});
10230             }
10231             action.call(this); // align immediately
10232             return this;
10233         },
10234         /**
10235          * Clears any opacity settings from this element. Required in some cases for IE.
10236          * @return {Roo.Element} this
10237          */
10238         clearOpacity : function(){
10239             if (window.ActiveXObject) {
10240                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
10241                     this.dom.style.filter = "";
10242                 }
10243             } else {
10244                 this.dom.style.opacity = "";
10245                 this.dom.style["-moz-opacity"] = "";
10246                 this.dom.style["-khtml-opacity"] = "";
10247             }
10248             return this;
10249         },
10250
10251         /**
10252          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10253          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10254          * @return {Roo.Element} this
10255          */
10256         hide : function(animate){
10257             this.setVisible(false, this.preanim(arguments, 0));
10258             return this;
10259         },
10260
10261         /**
10262         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
10263         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10264          * @return {Roo.Element} this
10265          */
10266         show : function(animate){
10267             this.setVisible(true, this.preanim(arguments, 0));
10268             return this;
10269         },
10270
10271         /**
10272          * @private Test if size has a unit, otherwise appends the default
10273          */
10274         addUnits : function(size){
10275             return Roo.Element.addUnits(size, this.defaultUnit);
10276         },
10277
10278         /**
10279          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
10280          * @return {Roo.Element} this
10281          */
10282         beginMeasure : function(){
10283             var el = this.dom;
10284             if(el.offsetWidth || el.offsetHeight){
10285                 return this; // offsets work already
10286             }
10287             var changed = [];
10288             var p = this.dom, b = document.body; // start with this element
10289             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
10290                 var pe = Roo.get(p);
10291                 if(pe.getStyle('display') == 'none'){
10292                     changed.push({el: p, visibility: pe.getStyle("visibility")});
10293                     p.style.visibility = "hidden";
10294                     p.style.display = "block";
10295                 }
10296                 p = p.parentNode;
10297             }
10298             this._measureChanged = changed;
10299             return this;
10300
10301         },
10302
10303         /**
10304          * Restores displays to before beginMeasure was called
10305          * @return {Roo.Element} this
10306          */
10307         endMeasure : function(){
10308             var changed = this._measureChanged;
10309             if(changed){
10310                 for(var i = 0, len = changed.length; i < len; i++) {
10311                     var r = changed[i];
10312                     r.el.style.visibility = r.visibility;
10313                     r.el.style.display = "none";
10314                 }
10315                 this._measureChanged = null;
10316             }
10317             return this;
10318         },
10319
10320         /**
10321         * Update the innerHTML of this element, optionally searching for and processing scripts
10322         * @param {String} html The new HTML
10323         * @param {Boolean} loadScripts (optional) true to look for and process scripts
10324         * @param {Function} callback For async script loading you can be noticed when the update completes
10325         * @return {Roo.Element} this
10326          */
10327         update : function(html, loadScripts, callback){
10328             if(typeof html == "undefined"){
10329                 html = "";
10330             }
10331             if(loadScripts !== true){
10332                 this.dom.innerHTML = html;
10333                 if(typeof callback == "function"){
10334                     callback();
10335                 }
10336                 return this;
10337             }
10338             var id = Roo.id();
10339             var dom = this.dom;
10340
10341             html += '<span id="' + id + '"></span>';
10342
10343             E.onAvailable(id, function(){
10344                 var hd = document.getElementsByTagName("head")[0];
10345                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
10346                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
10347                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
10348
10349                 var match;
10350                 while(match = re.exec(html)){
10351                     var attrs = match[1];
10352                     var srcMatch = attrs ? attrs.match(srcRe) : false;
10353                     if(srcMatch && srcMatch[2]){
10354                        var s = document.createElement("script");
10355                        s.src = srcMatch[2];
10356                        var typeMatch = attrs.match(typeRe);
10357                        if(typeMatch && typeMatch[2]){
10358                            s.type = typeMatch[2];
10359                        }
10360                        hd.appendChild(s);
10361                     }else if(match[2] && match[2].length > 0){
10362                         if(window.execScript) {
10363                            window.execScript(match[2]);
10364                         } else {
10365                             /**
10366                              * eval:var:id
10367                              * eval:var:dom
10368                              * eval:var:html
10369                              * 
10370                              */
10371                            window.eval(match[2]);
10372                         }
10373                     }
10374                 }
10375                 var el = document.getElementById(id);
10376                 if(el){el.parentNode.removeChild(el);}
10377                 if(typeof callback == "function"){
10378                     callback();
10379                 }
10380             });
10381             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
10382             return this;
10383         },
10384
10385         /**
10386          * Direct access to the UpdateManager update() method (takes the same parameters).
10387          * @param {String/Function} url The url for this request or a function to call to get the url
10388          * @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}
10389          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10390          * @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.
10391          * @return {Roo.Element} this
10392          */
10393         load : function(){
10394             var um = this.getUpdateManager();
10395             um.update.apply(um, arguments);
10396             return this;
10397         },
10398
10399         /**
10400         * Gets this element's UpdateManager
10401         * @return {Roo.UpdateManager} The UpdateManager
10402         */
10403         getUpdateManager : function(){
10404             if(!this.updateManager){
10405                 this.updateManager = new Roo.UpdateManager(this);
10406             }
10407             return this.updateManager;
10408         },
10409
10410         /**
10411          * Disables text selection for this element (normalized across browsers)
10412          * @return {Roo.Element} this
10413          */
10414         unselectable : function(){
10415             this.dom.unselectable = "on";
10416             this.swallowEvent("selectstart", true);
10417             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
10418             this.addClass("x-unselectable");
10419             return this;
10420         },
10421
10422         /**
10423         * Calculates the x, y to center this element on the screen
10424         * @return {Array} The x, y values [x, y]
10425         */
10426         getCenterXY : function(){
10427             return this.getAlignToXY(document, 'c-c');
10428         },
10429
10430         /**
10431         * Centers the Element in either the viewport, or another Element.
10432         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
10433         */
10434         center : function(centerIn){
10435             this.alignTo(centerIn || document, 'c-c');
10436             return this;
10437         },
10438
10439         /**
10440          * Tests various css rules/browsers to determine if this element uses a border box
10441          * @return {Boolean}
10442          */
10443         isBorderBox : function(){
10444             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
10445         },
10446
10447         /**
10448          * Return a box {x, y, width, height} that can be used to set another elements
10449          * size/location to match this element.
10450          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
10451          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
10452          * @return {Object} box An object in the format {x, y, width, height}
10453          */
10454         getBox : function(contentBox, local){
10455             var xy;
10456             if(!local){
10457                 xy = this.getXY();
10458             }else{
10459                 var left = parseInt(this.getStyle("left"), 10) || 0;
10460                 var top = parseInt(this.getStyle("top"), 10) || 0;
10461                 xy = [left, top];
10462             }
10463             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
10464             if(!contentBox){
10465                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
10466             }else{
10467                 var l = this.getBorderWidth("l")+this.getPadding("l");
10468                 var r = this.getBorderWidth("r")+this.getPadding("r");
10469                 var t = this.getBorderWidth("t")+this.getPadding("t");
10470                 var b = this.getBorderWidth("b")+this.getPadding("b");
10471                 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)};
10472             }
10473             bx.right = bx.x + bx.width;
10474             bx.bottom = bx.y + bx.height;
10475             return bx;
10476         },
10477
10478         /**
10479          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
10480          for more information about the sides.
10481          * @param {String} sides
10482          * @return {Number}
10483          */
10484         getFrameWidth : function(sides, onlyContentBox){
10485             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
10486         },
10487
10488         /**
10489          * 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.
10490          * @param {Object} box The box to fill {x, y, width, height}
10491          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
10492          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10493          * @return {Roo.Element} this
10494          */
10495         setBox : function(box, adjust, animate){
10496             var w = box.width, h = box.height;
10497             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
10498                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
10499                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
10500             }
10501             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
10502             return this;
10503         },
10504
10505         /**
10506          * Forces the browser to repaint this element
10507          * @return {Roo.Element} this
10508          */
10509          repaint : function(){
10510             var dom = this.dom;
10511             this.addClass("x-repaint");
10512             setTimeout(function(){
10513                 Roo.get(dom).removeClass("x-repaint");
10514             }, 1);
10515             return this;
10516         },
10517
10518         /**
10519          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
10520          * then it returns the calculated width of the sides (see getPadding)
10521          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
10522          * @return {Object/Number}
10523          */
10524         getMargins : function(side){
10525             if(!side){
10526                 return {
10527                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
10528                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
10529                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10530                     right: parseInt(this.getStyle("margin-right"), 10) || 0
10531                 };
10532             }else{
10533                 return this.addStyles(side, El.margins);
10534              }
10535         },
10536
10537         // private
10538         addStyles : function(sides, styles){
10539             var val = 0, v, w;
10540             for(var i = 0, len = sides.length; i < len; i++){
10541                 v = this.getStyle(styles[sides.charAt(i)]);
10542                 if(v){
10543                      w = parseInt(v, 10);
10544                      if(w){ val += w; }
10545                 }
10546             }
10547             return val;
10548         },
10549
10550         /**
10551          * Creates a proxy element of this element
10552          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10553          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10554          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10555          * @return {Roo.Element} The new proxy element
10556          */
10557         createProxy : function(config, renderTo, matchBox){
10558             if(renderTo){
10559                 renderTo = Roo.getDom(renderTo);
10560             }else{
10561                 renderTo = document.body;
10562             }
10563             config = typeof config == "object" ?
10564                 config : {tag : "div", cls: config};
10565             var proxy = Roo.DomHelper.append(renderTo, config, true);
10566             if(matchBox){
10567                proxy.setBox(this.getBox());
10568             }
10569             return proxy;
10570         },
10571
10572         /**
10573          * Puts a mask over this element to disable user interaction. Requires core.css.
10574          * This method can only be applied to elements which accept child nodes.
10575          * @param {String} msg (optional) A message to display in the mask
10576          * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10577          * @return {Element} The mask  element
10578          */
10579         mask : function(msg, msgCls)
10580         {
10581             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10582                 this.setStyle("position", "relative");
10583             }
10584             if(!this._mask){
10585                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10586             }
10587             
10588             this.addClass("x-masked");
10589             this._mask.setDisplayed(true);
10590             
10591             // we wander
10592             var z = 0;
10593             var dom = this.dom;
10594             while (dom && dom.style) {
10595                 if (!isNaN(parseInt(dom.style.zIndex))) {
10596                     z = Math.max(z, parseInt(dom.style.zIndex));
10597                 }
10598                 dom = dom.parentNode;
10599             }
10600             // if we are masking the body - then it hides everything..
10601             if (this.dom == document.body) {
10602                 z = 1000000;
10603                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10604                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10605             }
10606            
10607             if(typeof msg == 'string'){
10608                 if(!this._maskMsg){
10609                     this._maskMsg = Roo.DomHelper.append(this.dom, {
10610                         cls: "roo-el-mask-msg", 
10611                         cn: [
10612                             {
10613                                 tag: 'i',
10614                                 cls: 'fa fa-spinner fa-spin'
10615                             },
10616                             {
10617                                 tag: 'div'
10618                             }   
10619                         ]
10620                     }, true);
10621                 }
10622                 var mm = this._maskMsg;
10623                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10624                 if (mm.dom.lastChild) { // weird IE issue?
10625                     mm.dom.lastChild.innerHTML = msg;
10626                 }
10627                 mm.setDisplayed(true);
10628                 mm.center(this);
10629                 mm.setStyle('z-index', z + 102);
10630             }
10631             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10632                 this._mask.setHeight(this.getHeight());
10633             }
10634             this._mask.setStyle('z-index', z + 100);
10635             
10636             return this._mask;
10637         },
10638
10639         /**
10640          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10641          * it is cached for reuse.
10642          */
10643         unmask : function(removeEl){
10644             if(this._mask){
10645                 if(removeEl === true){
10646                     this._mask.remove();
10647                     delete this._mask;
10648                     if(this._maskMsg){
10649                         this._maskMsg.remove();
10650                         delete this._maskMsg;
10651                     }
10652                 }else{
10653                     this._mask.setDisplayed(false);
10654                     if(this._maskMsg){
10655                         this._maskMsg.setDisplayed(false);
10656                     }
10657                 }
10658             }
10659             this.removeClass("x-masked");
10660         },
10661
10662         /**
10663          * Returns true if this element is masked
10664          * @return {Boolean}
10665          */
10666         isMasked : function(){
10667             return this._mask && this._mask.isVisible();
10668         },
10669
10670         /**
10671          * Creates an iframe shim for this element to keep selects and other windowed objects from
10672          * showing through.
10673          * @return {Roo.Element} The new shim element
10674          */
10675         createShim : function(){
10676             var el = document.createElement('iframe');
10677             el.frameBorder = 'no';
10678             el.className = 'roo-shim';
10679             if(Roo.isIE && Roo.isSecure){
10680                 el.src = Roo.SSL_SECURE_URL;
10681             }
10682             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10683             shim.autoBoxAdjust = false;
10684             return shim;
10685         },
10686
10687         /**
10688          * Removes this element from the DOM and deletes it from the cache
10689          */
10690         remove : function(){
10691             if(this.dom.parentNode){
10692                 this.dom.parentNode.removeChild(this.dom);
10693             }
10694             delete El.cache[this.dom.id];
10695         },
10696
10697         /**
10698          * Sets up event handlers to add and remove a css class when the mouse is over this element
10699          * @param {String} className
10700          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10701          * mouseout events for children elements
10702          * @return {Roo.Element} this
10703          */
10704         addClassOnOver : function(className, preventFlicker){
10705             this.on("mouseover", function(){
10706                 Roo.fly(this, '_internal').addClass(className);
10707             }, this.dom);
10708             var removeFn = function(e){
10709                 if(preventFlicker !== true || !e.within(this, true)){
10710                     Roo.fly(this, '_internal').removeClass(className);
10711                 }
10712             };
10713             this.on("mouseout", removeFn, this.dom);
10714             return this;
10715         },
10716
10717         /**
10718          * Sets up event handlers to add and remove a css class when this element has the focus
10719          * @param {String} className
10720          * @return {Roo.Element} this
10721          */
10722         addClassOnFocus : function(className){
10723             this.on("focus", function(){
10724                 Roo.fly(this, '_internal').addClass(className);
10725             }, this.dom);
10726             this.on("blur", function(){
10727                 Roo.fly(this, '_internal').removeClass(className);
10728             }, this.dom);
10729             return this;
10730         },
10731         /**
10732          * 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)
10733          * @param {String} className
10734          * @return {Roo.Element} this
10735          */
10736         addClassOnClick : function(className){
10737             var dom = this.dom;
10738             this.on("mousedown", function(){
10739                 Roo.fly(dom, '_internal').addClass(className);
10740                 var d = Roo.get(document);
10741                 var fn = function(){
10742                     Roo.fly(dom, '_internal').removeClass(className);
10743                     d.removeListener("mouseup", fn);
10744                 };
10745                 d.on("mouseup", fn);
10746             });
10747             return this;
10748         },
10749
10750         /**
10751          * Stops the specified event from bubbling and optionally prevents the default action
10752          * @param {String} eventName
10753          * @param {Boolean} preventDefault (optional) true to prevent the default action too
10754          * @return {Roo.Element} this
10755          */
10756         swallowEvent : function(eventName, preventDefault){
10757             var fn = function(e){
10758                 e.stopPropagation();
10759                 if(preventDefault){
10760                     e.preventDefault();
10761                 }
10762             };
10763             if(eventName instanceof Array){
10764                 for(var i = 0, len = eventName.length; i < len; i++){
10765                      this.on(eventName[i], fn);
10766                 }
10767                 return this;
10768             }
10769             this.on(eventName, fn);
10770             return this;
10771         },
10772
10773         /**
10774          * @private
10775          */
10776         fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10777
10778         /**
10779          * Sizes this element to its parent element's dimensions performing
10780          * neccessary box adjustments.
10781          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10782          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10783          * @return {Roo.Element} this
10784          */
10785         fitToParent : function(monitorResize, targetParent) {
10786           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10787           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10788           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10789             return this;
10790           }
10791           var p = Roo.get(targetParent || this.dom.parentNode);
10792           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10793           if (monitorResize === true) {
10794             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10795             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10796           }
10797           return this;
10798         },
10799
10800         /**
10801          * Gets the next sibling, skipping text nodes
10802          * @return {HTMLElement} The next sibling or null
10803          */
10804         getNextSibling : function(){
10805             var n = this.dom.nextSibling;
10806             while(n && n.nodeType != 1){
10807                 n = n.nextSibling;
10808             }
10809             return n;
10810         },
10811
10812         /**
10813          * Gets the previous sibling, skipping text nodes
10814          * @return {HTMLElement} The previous sibling or null
10815          */
10816         getPrevSibling : function(){
10817             var n = this.dom.previousSibling;
10818             while(n && n.nodeType != 1){
10819                 n = n.previousSibling;
10820             }
10821             return n;
10822         },
10823
10824
10825         /**
10826          * Appends the passed element(s) to this element
10827          * @param {String/HTMLElement/Array/Element/CompositeElement} el
10828          * @return {Roo.Element} this
10829          */
10830         appendChild: function(el){
10831             el = Roo.get(el);
10832             el.appendTo(this);
10833             return this;
10834         },
10835
10836         /**
10837          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10838          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
10839          * automatically generated with the specified attributes.
10840          * @param {HTMLElement} insertBefore (optional) a child element of this element
10841          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10842          * @return {Roo.Element} The new child element
10843          */
10844         createChild: function(config, insertBefore, returnDom){
10845             config = config || {tag:'div'};
10846             if(insertBefore){
10847                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10848             }
10849             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
10850         },
10851
10852         /**
10853          * Appends this element to the passed element
10854          * @param {String/HTMLElement/Element} el The new parent element
10855          * @return {Roo.Element} this
10856          */
10857         appendTo: function(el){
10858             el = Roo.getDom(el);
10859             el.appendChild(this.dom);
10860             return this;
10861         },
10862
10863         /**
10864          * Inserts this element before the passed element in the DOM
10865          * @param {String/HTMLElement/Element} el The element to insert before
10866          * @return {Roo.Element} this
10867          */
10868         insertBefore: function(el){
10869             el = Roo.getDom(el);
10870             el.parentNode.insertBefore(this.dom, el);
10871             return this;
10872         },
10873
10874         /**
10875          * Inserts this element after the passed element in the DOM
10876          * @param {String/HTMLElement/Element} el The element to insert after
10877          * @return {Roo.Element} this
10878          */
10879         insertAfter: function(el){
10880             el = Roo.getDom(el);
10881             el.parentNode.insertBefore(this.dom, el.nextSibling);
10882             return this;
10883         },
10884
10885         /**
10886          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10887          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10888          * @return {Roo.Element} The new child
10889          */
10890         insertFirst: function(el, returnDom){
10891             el = el || {};
10892             if(typeof el == 'object' && !el.nodeType){ // dh config
10893                 return this.createChild(el, this.dom.firstChild, returnDom);
10894             }else{
10895                 el = Roo.getDom(el);
10896                 this.dom.insertBefore(el, this.dom.firstChild);
10897                 return !returnDom ? Roo.get(el) : el;
10898             }
10899         },
10900
10901         /**
10902          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10903          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10904          * @param {String} where (optional) 'before' or 'after' defaults to before
10905          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10906          * @return {Roo.Element} the inserted Element
10907          */
10908         insertSibling: function(el, where, returnDom){
10909             where = where ? where.toLowerCase() : 'before';
10910             el = el || {};
10911             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10912
10913             if(typeof el == 'object' && !el.nodeType){ // dh config
10914                 if(where == 'after' && !this.dom.nextSibling){
10915                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10916                 }else{
10917                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10918                 }
10919
10920             }else{
10921                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10922                             where == 'before' ? this.dom : this.dom.nextSibling);
10923                 if(!returnDom){
10924                     rt = Roo.get(rt);
10925                 }
10926             }
10927             return rt;
10928         },
10929
10930         /**
10931          * Creates and wraps this element with another element
10932          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10933          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10934          * @return {HTMLElement/Element} The newly created wrapper element
10935          */
10936         wrap: function(config, returnDom){
10937             if(!config){
10938                 config = {tag: "div"};
10939             }
10940             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10941             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10942             return newEl;
10943         },
10944
10945         /**
10946          * Replaces the passed element with this element
10947          * @param {String/HTMLElement/Element} el The element to replace
10948          * @return {Roo.Element} this
10949          */
10950         replace: function(el){
10951             el = Roo.get(el);
10952             this.insertBefore(el);
10953             el.remove();
10954             return this;
10955         },
10956
10957         /**
10958          * Inserts an html fragment into this element
10959          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10960          * @param {String} html The HTML fragment
10961          * @param {Boolean} returnEl True to return an Roo.Element
10962          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10963          */
10964         insertHtml : function(where, html, returnEl){
10965             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10966             return returnEl ? Roo.get(el) : el;
10967         },
10968
10969         /**
10970          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10971          * @param {Object} o The object with the attributes
10972          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10973          * @return {Roo.Element} this
10974          */
10975         set : function(o, useSet){
10976             var el = this.dom;
10977             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10978             for(var attr in o){
10979                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
10980                 if(attr=="cls"){
10981                     el.className = o["cls"];
10982                 }else{
10983                     if(useSet) {
10984                         el.setAttribute(attr, o[attr]);
10985                     } else {
10986                         el[attr] = o[attr];
10987                     }
10988                 }
10989             }
10990             if(o.style){
10991                 Roo.DomHelper.applyStyles(el, o.style);
10992             }
10993             return this;
10994         },
10995
10996         /**
10997          * Convenience method for constructing a KeyMap
10998          * @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:
10999          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
11000          * @param {Function} fn The function to call
11001          * @param {Object} scope (optional) The scope of the function
11002          * @return {Roo.KeyMap} The KeyMap created
11003          */
11004         addKeyListener : function(key, fn, scope){
11005             var config;
11006             if(typeof key != "object" || key instanceof Array){
11007                 config = {
11008                     key: key,
11009                     fn: fn,
11010                     scope: scope
11011                 };
11012             }else{
11013                 config = {
11014                     key : key.key,
11015                     shift : key.shift,
11016                     ctrl : key.ctrl,
11017                     alt : key.alt,
11018                     fn: fn,
11019                     scope: scope
11020                 };
11021             }
11022             return new Roo.KeyMap(this, config);
11023         },
11024
11025         /**
11026          * Creates a KeyMap for this element
11027          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
11028          * @return {Roo.KeyMap} The KeyMap created
11029          */
11030         addKeyMap : function(config){
11031             return new Roo.KeyMap(this, config);
11032         },
11033
11034         /**
11035          * Returns true if this element is scrollable.
11036          * @return {Boolean}
11037          */
11038          isScrollable : function(){
11039             var dom = this.dom;
11040             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
11041         },
11042
11043         /**
11044          * 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().
11045          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
11046          * @param {Number} value The new scroll value
11047          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11048          * @return {Element} this
11049          */
11050
11051         scrollTo : function(side, value, animate){
11052             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
11053             if(!animate || !A){
11054                 this.dom[prop] = value;
11055             }else{
11056                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
11057                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
11058             }
11059             return this;
11060         },
11061
11062         /**
11063          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
11064          * within this element's scrollable range.
11065          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
11066          * @param {Number} distance How far to scroll the element in pixels
11067          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
11068          * @return {Boolean} Returns true if a scroll was triggered or false if the element
11069          * was scrolled as far as it could go.
11070          */
11071          scroll : function(direction, distance, animate){
11072              if(!this.isScrollable()){
11073                  return;
11074              }
11075              var el = this.dom;
11076              var l = el.scrollLeft, t = el.scrollTop;
11077              var w = el.scrollWidth, h = el.scrollHeight;
11078              var cw = el.clientWidth, ch = el.clientHeight;
11079              direction = direction.toLowerCase();
11080              var scrolled = false;
11081              var a = this.preanim(arguments, 2);
11082              switch(direction){
11083                  case "l":
11084                  case "left":
11085                      if(w - l > cw){
11086                          var v = Math.min(l + distance, w-cw);
11087                          this.scrollTo("left", v, a);
11088                          scrolled = true;
11089                      }
11090                      break;
11091                 case "r":
11092                 case "right":
11093                      if(l > 0){
11094                          var v = Math.max(l - distance, 0);
11095                          this.scrollTo("left", v, a);
11096                          scrolled = true;
11097                      }
11098                      break;
11099                 case "t":
11100                 case "top":
11101                 case "up":
11102                      if(t > 0){
11103                          var v = Math.max(t - distance, 0);
11104                          this.scrollTo("top", v, a);
11105                          scrolled = true;
11106                      }
11107                      break;
11108                 case "b":
11109                 case "bottom":
11110                 case "down":
11111                      if(h - t > ch){
11112                          var v = Math.min(t + distance, h-ch);
11113                          this.scrollTo("top", v, a);
11114                          scrolled = true;
11115                      }
11116                      break;
11117              }
11118              return scrolled;
11119         },
11120
11121         /**
11122          * Translates the passed page coordinates into left/top css values for this element
11123          * @param {Number/Array} x The page x or an array containing [x, y]
11124          * @param {Number} y The page y
11125          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
11126          */
11127         translatePoints : function(x, y){
11128             if(typeof x == 'object' || x instanceof Array){
11129                 y = x[1]; x = x[0];
11130             }
11131             var p = this.getStyle('position');
11132             var o = this.getXY();
11133
11134             var l = parseInt(this.getStyle('left'), 10);
11135             var t = parseInt(this.getStyle('top'), 10);
11136
11137             if(isNaN(l)){
11138                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
11139             }
11140             if(isNaN(t)){
11141                 t = (p == "relative") ? 0 : this.dom.offsetTop;
11142             }
11143
11144             return {left: (x - o[0] + l), top: (y - o[1] + t)};
11145         },
11146
11147         /**
11148          * Returns the current scroll position of the element.
11149          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
11150          */
11151         getScroll : function(){
11152             var d = this.dom, doc = document;
11153             if(d == doc || d == doc.body){
11154                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
11155                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
11156                 return {left: l, top: t};
11157             }else{
11158                 return {left: d.scrollLeft, top: d.scrollTop};
11159             }
11160         },
11161
11162         /**
11163          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
11164          * are convert to standard 6 digit hex color.
11165          * @param {String} attr The css attribute
11166          * @param {String} defaultValue The default value to use when a valid color isn't found
11167          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
11168          * YUI color anims.
11169          */
11170         getColor : function(attr, defaultValue, prefix){
11171             var v = this.getStyle(attr);
11172             if(!v || v == "transparent" || v == "inherit") {
11173                 return defaultValue;
11174             }
11175             var color = typeof prefix == "undefined" ? "#" : prefix;
11176             if(v.substr(0, 4) == "rgb("){
11177                 var rvs = v.slice(4, v.length -1).split(",");
11178                 for(var i = 0; i < 3; i++){
11179                     var h = parseInt(rvs[i]).toString(16);
11180                     if(h < 16){
11181                         h = "0" + h;
11182                     }
11183                     color += h;
11184                 }
11185             } else {
11186                 if(v.substr(0, 1) == "#"){
11187                     if(v.length == 4) {
11188                         for(var i = 1; i < 4; i++){
11189                             var c = v.charAt(i);
11190                             color +=  c + c;
11191                         }
11192                     }else if(v.length == 7){
11193                         color += v.substr(1);
11194                     }
11195                 }
11196             }
11197             return(color.length > 5 ? color.toLowerCase() : defaultValue);
11198         },
11199
11200         /**
11201          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
11202          * gradient background, rounded corners and a 4-way shadow.
11203          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
11204          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
11205          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
11206          * @return {Roo.Element} this
11207          */
11208         boxWrap : function(cls){
11209             cls = cls || 'x-box';
11210             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
11211             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
11212             return el;
11213         },
11214
11215         /**
11216          * Returns the value of a namespaced attribute from the element's underlying DOM node.
11217          * @param {String} namespace The namespace in which to look for the attribute
11218          * @param {String} name The attribute name
11219          * @return {String} The attribute value
11220          */
11221         getAttributeNS : Roo.isIE ? function(ns, name){
11222             var d = this.dom;
11223             var type = typeof d[ns+":"+name];
11224             if(type != 'undefined' && type != 'unknown'){
11225                 return d[ns+":"+name];
11226             }
11227             return d[name];
11228         } : function(ns, name){
11229             var d = this.dom;
11230             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
11231         },
11232         
11233         
11234         /**
11235          * Sets or Returns the value the dom attribute value
11236          * @param {String|Object} name The attribute name (or object to set multiple attributes)
11237          * @param {String} value (optional) The value to set the attribute to
11238          * @return {String} The attribute value
11239          */
11240         attr : function(name){
11241             if (arguments.length > 1) {
11242                 this.dom.setAttribute(name, arguments[1]);
11243                 return arguments[1];
11244             }
11245             if (typeof(name) == 'object') {
11246                 for(var i in name) {
11247                     this.attr(i, name[i]);
11248                 }
11249                 return name;
11250             }
11251             
11252             
11253             if (!this.dom.hasAttribute(name)) {
11254                 return undefined;
11255             }
11256             return this.dom.getAttribute(name);
11257         }
11258         
11259         
11260         
11261     };
11262
11263     var ep = El.prototype;
11264
11265     /**
11266      * Appends an event handler (Shorthand for addListener)
11267      * @param {String}   eventName     The type of event to append
11268      * @param {Function} fn        The method the event invokes
11269      * @param {Object} scope       (optional) The scope (this object) of the fn
11270      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
11271      * @method
11272      */
11273     ep.on = ep.addListener;
11274         // backwards compat
11275     ep.mon = ep.addListener;
11276
11277     /**
11278      * Removes an event handler from this element (shorthand for removeListener)
11279      * @param {String} eventName the type of event to remove
11280      * @param {Function} fn the method the event invokes
11281      * @return {Roo.Element} this
11282      * @method
11283      */
11284     ep.un = ep.removeListener;
11285
11286     /**
11287      * true to automatically adjust width and height settings for box-model issues (default to true)
11288      */
11289     ep.autoBoxAdjust = true;
11290
11291     // private
11292     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
11293
11294     // private
11295     El.addUnits = function(v, defaultUnit){
11296         if(v === "" || v == "auto"){
11297             return v;
11298         }
11299         if(v === undefined){
11300             return '';
11301         }
11302         if(typeof v == "number" || !El.unitPattern.test(v)){
11303             return v + (defaultUnit || 'px');
11304         }
11305         return v;
11306     };
11307
11308     // special markup used throughout Roo when box wrapping elements
11309     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>';
11310     /**
11311      * Visibility mode constant - Use visibility to hide element
11312      * @static
11313      * @type Number
11314      */
11315     El.VISIBILITY = 1;
11316     /**
11317      * Visibility mode constant - Use display to hide element
11318      * @static
11319      * @type Number
11320      */
11321     El.DISPLAY = 2;
11322
11323     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
11324     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
11325     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
11326
11327
11328
11329     /**
11330      * @private
11331      */
11332     El.cache = {};
11333
11334     var docEl;
11335
11336     /**
11337      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11338      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11339      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11340      * @return {Element} The Element object
11341      * @static
11342      */
11343     El.get = function(el){
11344         var ex, elm, id;
11345         if(!el){ return null; }
11346         if(typeof el == "string"){ // element id
11347             if(!(elm = document.getElementById(el))){
11348                 return null;
11349             }
11350             if(ex = El.cache[el]){
11351                 ex.dom = elm;
11352             }else{
11353                 ex = El.cache[el] = new El(elm);
11354             }
11355             return ex;
11356         }else if(el.tagName){ // dom element
11357             if(!(id = el.id)){
11358                 id = Roo.id(el);
11359             }
11360             if(ex = El.cache[id]){
11361                 ex.dom = el;
11362             }else{
11363                 ex = El.cache[id] = new El(el);
11364             }
11365             return ex;
11366         }else if(el instanceof El){
11367             if(el != docEl){
11368                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
11369                                                               // catch case where it hasn't been appended
11370                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
11371             }
11372             return el;
11373         }else if(el.isComposite){
11374             return el;
11375         }else if(el instanceof Array){
11376             return El.select(el);
11377         }else if(el == document){
11378             // create a bogus element object representing the document object
11379             if(!docEl){
11380                 var f = function(){};
11381                 f.prototype = El.prototype;
11382                 docEl = new f();
11383                 docEl.dom = document;
11384             }
11385             return docEl;
11386         }
11387         return null;
11388     };
11389
11390     // private
11391     El.uncache = function(el){
11392         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
11393             if(a[i]){
11394                 delete El.cache[a[i].id || a[i]];
11395             }
11396         }
11397     };
11398
11399     // private
11400     // Garbage collection - uncache elements/purge listeners on orphaned elements
11401     // so we don't hold a reference and cause the browser to retain them
11402     El.garbageCollect = function(){
11403         if(!Roo.enableGarbageCollector){
11404             clearInterval(El.collectorThread);
11405             return;
11406         }
11407         for(var eid in El.cache){
11408             var el = El.cache[eid], d = el.dom;
11409             // -------------------------------------------------------
11410             // Determining what is garbage:
11411             // -------------------------------------------------------
11412             // !d
11413             // dom node is null, definitely garbage
11414             // -------------------------------------------------------
11415             // !d.parentNode
11416             // no parentNode == direct orphan, definitely garbage
11417             // -------------------------------------------------------
11418             // !d.offsetParent && !document.getElementById(eid)
11419             // display none elements have no offsetParent so we will
11420             // also try to look it up by it's id. However, check
11421             // offsetParent first so we don't do unneeded lookups.
11422             // This enables collection of elements that are not orphans
11423             // directly, but somewhere up the line they have an orphan
11424             // parent.
11425             // -------------------------------------------------------
11426             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
11427                 delete El.cache[eid];
11428                 if(d && Roo.enableListenerCollection){
11429                     E.purgeElement(d);
11430                 }
11431             }
11432         }
11433     }
11434     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
11435
11436
11437     // dom is optional
11438     El.Flyweight = function(dom){
11439         this.dom = dom;
11440     };
11441     El.Flyweight.prototype = El.prototype;
11442
11443     El._flyweights = {};
11444     /**
11445      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11446      * the dom node can be overwritten by other code.
11447      * @param {String/HTMLElement} el The dom node or id
11448      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11449      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11450      * @static
11451      * @return {Element} The shared Element object
11452      */
11453     El.fly = function(el, named){
11454         named = named || '_global';
11455         el = Roo.getDom(el);
11456         if(!el){
11457             return null;
11458         }
11459         if(!El._flyweights[named]){
11460             El._flyweights[named] = new El.Flyweight();
11461         }
11462         El._flyweights[named].dom = el;
11463         return El._flyweights[named];
11464     };
11465
11466     /**
11467      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
11468      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
11469      * Shorthand of {@link Roo.Element#get}
11470      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
11471      * @return {Element} The Element object
11472      * @member Roo
11473      * @method get
11474      */
11475     Roo.get = El.get;
11476     /**
11477      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
11478      * the dom node can be overwritten by other code.
11479      * Shorthand of {@link Roo.Element#fly}
11480      * @param {String/HTMLElement} el The dom node or id
11481      * @param {String} named (optional) Allows for creation of named reusable flyweights to
11482      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
11483      * @static
11484      * @return {Element} The shared Element object
11485      * @member Roo
11486      * @method fly
11487      */
11488     Roo.fly = El.fly;
11489
11490     // speedy lookup for elements never to box adjust
11491     var noBoxAdjust = Roo.isStrict ? {
11492         select:1
11493     } : {
11494         input:1, select:1, textarea:1
11495     };
11496     if(Roo.isIE || Roo.isGecko){
11497         noBoxAdjust['button'] = 1;
11498     }
11499
11500
11501     Roo.EventManager.on(window, 'unload', function(){
11502         delete El.cache;
11503         delete El._flyweights;
11504     });
11505 })();
11506
11507
11508
11509
11510 if(Roo.DomQuery){
11511     Roo.Element.selectorFunction = Roo.DomQuery.select;
11512 }
11513
11514 Roo.Element.select = function(selector, unique, root){
11515     var els;
11516     if(typeof selector == "string"){
11517         els = Roo.Element.selectorFunction(selector, root);
11518     }else if(selector.length !== undefined){
11519         els = selector;
11520     }else{
11521         throw "Invalid selector";
11522     }
11523     if(unique === true){
11524         return new Roo.CompositeElement(els);
11525     }else{
11526         return new Roo.CompositeElementLite(els);
11527     }
11528 };
11529 /**
11530  * Selects elements based on the passed CSS selector to enable working on them as 1.
11531  * @param {String/Array} selector The CSS selector or an array of elements
11532  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11533  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11534  * @return {CompositeElementLite/CompositeElement}
11535  * @member Roo
11536  * @method select
11537  */
11538 Roo.select = Roo.Element.select;
11539
11540
11541
11542
11543
11544
11545
11546
11547
11548
11549
11550
11551
11552
11553 /*
11554  * Based on:
11555  * Ext JS Library 1.1.1
11556  * Copyright(c) 2006-2007, Ext JS, LLC.
11557  *
11558  * Originally Released Under LGPL - original licence link has changed is not relivant.
11559  *
11560  * Fork - LGPL
11561  * <script type="text/javascript">
11562  */
11563
11564
11565
11566 //Notifies Element that fx methods are available
11567 Roo.enableFx = true;
11568
11569 /**
11570  * @class Roo.Fx
11571  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
11572  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11573  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
11574  * Element effects to work.</p><br/>
11575  *
11576  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11577  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11578  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11579  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
11580  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11581  * expected results and should be done with care.</p><br/>
11582  *
11583  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11584  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
11585 <pre>
11586 Value  Description
11587 -----  -----------------------------
11588 tl     The top left corner
11589 t      The center of the top edge
11590 tr     The top right corner
11591 l      The center of the left edge
11592 r      The center of the right edge
11593 bl     The bottom left corner
11594 b      The center of the bottom edge
11595 br     The bottom right corner
11596 </pre>
11597  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11598  * below are common options that can be passed to any Fx method.</b>
11599  * @cfg {Function} callback A function called when the effect is finished
11600  * @cfg {Object} scope The scope of the effect function
11601  * @cfg {String} easing A valid Easing value for the effect
11602  * @cfg {String} afterCls A css class to apply after the effect
11603  * @cfg {Number} duration The length of time (in seconds) that the effect should last
11604  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11605  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
11606  * effects that end with the element being visually hidden, ignored otherwise)
11607  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11608  * a function which returns such a specification that will be applied to the Element after the effect finishes
11609  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11610  * @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
11611  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11612  */
11613 Roo.Fx = {
11614         /**
11615          * Slides the element into view.  An anchor point can be optionally passed to set the point of
11616          * origin for the slide effect.  This function automatically handles wrapping the element with
11617          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11618          * Usage:
11619          *<pre><code>
11620 // default: slide the element in from the top
11621 el.slideIn();
11622
11623 // custom: slide the element in from the right with a 2-second duration
11624 el.slideIn('r', { duration: 2 });
11625
11626 // common config options shown with default values
11627 el.slideIn('t', {
11628     easing: 'easeOut',
11629     duration: .5
11630 });
11631 </code></pre>
11632          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11633          * @param {Object} options (optional) Object literal with any of the Fx config options
11634          * @return {Roo.Element} The Element
11635          */
11636     slideIn : function(anchor, o){
11637         var el = this.getFxEl();
11638         o = o || {};
11639
11640         el.queueFx(o, function(){
11641
11642             anchor = anchor || "t";
11643
11644             // fix display to visibility
11645             this.fixDisplay();
11646
11647             // restore values after effect
11648             var r = this.getFxRestore();
11649             var b = this.getBox();
11650             // fixed size for slide
11651             this.setSize(b);
11652
11653             // wrap if needed
11654             var wrap = this.fxWrap(r.pos, o, "hidden");
11655
11656             var st = this.dom.style;
11657             st.visibility = "visible";
11658             st.position = "absolute";
11659
11660             // clear out temp styles after slide and unwrap
11661             var after = function(){
11662                 el.fxUnwrap(wrap, r.pos, o);
11663                 st.width = r.width;
11664                 st.height = r.height;
11665                 el.afterFx(o);
11666             };
11667             // time to calc the positions
11668             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11669
11670             switch(anchor.toLowerCase()){
11671                 case "t":
11672                     wrap.setSize(b.width, 0);
11673                     st.left = st.bottom = "0";
11674                     a = {height: bh};
11675                 break;
11676                 case "l":
11677                     wrap.setSize(0, b.height);
11678                     st.right = st.top = "0";
11679                     a = {width: bw};
11680                 break;
11681                 case "r":
11682                     wrap.setSize(0, b.height);
11683                     wrap.setX(b.right);
11684                     st.left = st.top = "0";
11685                     a = {width: bw, points: pt};
11686                 break;
11687                 case "b":
11688                     wrap.setSize(b.width, 0);
11689                     wrap.setY(b.bottom);
11690                     st.left = st.top = "0";
11691                     a = {height: bh, points: pt};
11692                 break;
11693                 case "tl":
11694                     wrap.setSize(0, 0);
11695                     st.right = st.bottom = "0";
11696                     a = {width: bw, height: bh};
11697                 break;
11698                 case "bl":
11699                     wrap.setSize(0, 0);
11700                     wrap.setY(b.y+b.height);
11701                     st.right = st.top = "0";
11702                     a = {width: bw, height: bh, points: pt};
11703                 break;
11704                 case "br":
11705                     wrap.setSize(0, 0);
11706                     wrap.setXY([b.right, b.bottom]);
11707                     st.left = st.top = "0";
11708                     a = {width: bw, height: bh, points: pt};
11709                 break;
11710                 case "tr":
11711                     wrap.setSize(0, 0);
11712                     wrap.setX(b.x+b.width);
11713                     st.left = st.bottom = "0";
11714                     a = {width: bw, height: bh, points: pt};
11715                 break;
11716             }
11717             this.dom.style.visibility = "visible";
11718             wrap.show();
11719
11720             arguments.callee.anim = wrap.fxanim(a,
11721                 o,
11722                 'motion',
11723                 .5,
11724                 'easeOut', after);
11725         });
11726         return this;
11727     },
11728     
11729         /**
11730          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
11731          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
11732          * 'hidden') but block elements will still take up space in the document.  The element must be removed
11733          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
11734          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
11735          * Usage:
11736          *<pre><code>
11737 // default: slide the element out to the top
11738 el.slideOut();
11739
11740 // custom: slide the element out to the right with a 2-second duration
11741 el.slideOut('r', { duration: 2 });
11742
11743 // common config options shown with default values
11744 el.slideOut('t', {
11745     easing: 'easeOut',
11746     duration: .5,
11747     remove: false,
11748     useDisplay: false
11749 });
11750 </code></pre>
11751          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11752          * @param {Object} options (optional) Object literal with any of the Fx config options
11753          * @return {Roo.Element} The Element
11754          */
11755     slideOut : function(anchor, o){
11756         var el = this.getFxEl();
11757         o = o || {};
11758
11759         el.queueFx(o, function(){
11760
11761             anchor = anchor || "t";
11762
11763             // restore values after effect
11764             var r = this.getFxRestore();
11765             
11766             var b = this.getBox();
11767             // fixed size for slide
11768             this.setSize(b);
11769
11770             // wrap if needed
11771             var wrap = this.fxWrap(r.pos, o, "visible");
11772
11773             var st = this.dom.style;
11774             st.visibility = "visible";
11775             st.position = "absolute";
11776
11777             wrap.setSize(b);
11778
11779             var after = function(){
11780                 if(o.useDisplay){
11781                     el.setDisplayed(false);
11782                 }else{
11783                     el.hide();
11784                 }
11785
11786                 el.fxUnwrap(wrap, r.pos, o);
11787
11788                 st.width = r.width;
11789                 st.height = r.height;
11790
11791                 el.afterFx(o);
11792             };
11793
11794             var a, zero = {to: 0};
11795             switch(anchor.toLowerCase()){
11796                 case "t":
11797                     st.left = st.bottom = "0";
11798                     a = {height: zero};
11799                 break;
11800                 case "l":
11801                     st.right = st.top = "0";
11802                     a = {width: zero};
11803                 break;
11804                 case "r":
11805                     st.left = st.top = "0";
11806                     a = {width: zero, points: {to:[b.right, b.y]}};
11807                 break;
11808                 case "b":
11809                     st.left = st.top = "0";
11810                     a = {height: zero, points: {to:[b.x, b.bottom]}};
11811                 break;
11812                 case "tl":
11813                     st.right = st.bottom = "0";
11814                     a = {width: zero, height: zero};
11815                 break;
11816                 case "bl":
11817                     st.right = st.top = "0";
11818                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11819                 break;
11820                 case "br":
11821                     st.left = st.top = "0";
11822                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11823                 break;
11824                 case "tr":
11825                     st.left = st.bottom = "0";
11826                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11827                 break;
11828             }
11829
11830             arguments.callee.anim = wrap.fxanim(a,
11831                 o,
11832                 'motion',
11833                 .5,
11834                 "easeOut", after);
11835         });
11836         return this;
11837     },
11838
11839         /**
11840          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
11841          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
11842          * The element must be removed from the DOM using the 'remove' config option if desired.
11843          * Usage:
11844          *<pre><code>
11845 // default
11846 el.puff();
11847
11848 // common config options shown with default values
11849 el.puff({
11850     easing: 'easeOut',
11851     duration: .5,
11852     remove: false,
11853     useDisplay: false
11854 });
11855 </code></pre>
11856          * @param {Object} options (optional) Object literal with any of the Fx config options
11857          * @return {Roo.Element} The Element
11858          */
11859     puff : function(o){
11860         var el = this.getFxEl();
11861         o = o || {};
11862
11863         el.queueFx(o, function(){
11864             this.clearOpacity();
11865             this.show();
11866
11867             // restore values after effect
11868             var r = this.getFxRestore();
11869             var st = this.dom.style;
11870
11871             var after = function(){
11872                 if(o.useDisplay){
11873                     el.setDisplayed(false);
11874                 }else{
11875                     el.hide();
11876                 }
11877
11878                 el.clearOpacity();
11879
11880                 el.setPositioning(r.pos);
11881                 st.width = r.width;
11882                 st.height = r.height;
11883                 st.fontSize = '';
11884                 el.afterFx(o);
11885             };
11886
11887             var width = this.getWidth();
11888             var height = this.getHeight();
11889
11890             arguments.callee.anim = this.fxanim({
11891                     width : {to: this.adjustWidth(width * 2)},
11892                     height : {to: this.adjustHeight(height * 2)},
11893                     points : {by: [-(width * .5), -(height * .5)]},
11894                     opacity : {to: 0},
11895                     fontSize: {to:200, unit: "%"}
11896                 },
11897                 o,
11898                 'motion',
11899                 .5,
11900                 "easeOut", after);
11901         });
11902         return this;
11903     },
11904
11905         /**
11906          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11907          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
11908          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11909          * Usage:
11910          *<pre><code>
11911 // default
11912 el.switchOff();
11913
11914 // all config options shown with default values
11915 el.switchOff({
11916     easing: 'easeIn',
11917     duration: .3,
11918     remove: false,
11919     useDisplay: false
11920 });
11921 </code></pre>
11922          * @param {Object} options (optional) Object literal with any of the Fx config options
11923          * @return {Roo.Element} The Element
11924          */
11925     switchOff : function(o){
11926         var el = this.getFxEl();
11927         o = o || {};
11928
11929         el.queueFx(o, function(){
11930             this.clearOpacity();
11931             this.clip();
11932
11933             // restore values after effect
11934             var r = this.getFxRestore();
11935             var st = this.dom.style;
11936
11937             var after = function(){
11938                 if(o.useDisplay){
11939                     el.setDisplayed(false);
11940                 }else{
11941                     el.hide();
11942                 }
11943
11944                 el.clearOpacity();
11945                 el.setPositioning(r.pos);
11946                 st.width = r.width;
11947                 st.height = r.height;
11948
11949                 el.afterFx(o);
11950             };
11951
11952             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11953                 this.clearOpacity();
11954                 (function(){
11955                     this.fxanim({
11956                         height:{to:1},
11957                         points:{by:[0, this.getHeight() * .5]}
11958                     }, o, 'motion', 0.3, 'easeIn', after);
11959                 }).defer(100, this);
11960             });
11961         });
11962         return this;
11963     },
11964
11965     /**
11966      * Highlights the Element by setting a color (applies to the background-color by default, but can be
11967      * changed using the "attr" config option) and then fading back to the original color. If no original
11968      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11969      * Usage:
11970 <pre><code>
11971 // default: highlight background to yellow
11972 el.highlight();
11973
11974 // custom: highlight foreground text to blue for 2 seconds
11975 el.highlight("0000ff", { attr: 'color', duration: 2 });
11976
11977 // common config options shown with default values
11978 el.highlight("ffff9c", {
11979     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11980     endColor: (current color) or "ffffff",
11981     easing: 'easeIn',
11982     duration: 1
11983 });
11984 </code></pre>
11985      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11986      * @param {Object} options (optional) Object literal with any of the Fx config options
11987      * @return {Roo.Element} The Element
11988      */ 
11989     highlight : function(color, o){
11990         var el = this.getFxEl();
11991         o = o || {};
11992
11993         el.queueFx(o, function(){
11994             color = color || "ffff9c";
11995             attr = o.attr || "backgroundColor";
11996
11997             this.clearOpacity();
11998             this.show();
11999
12000             var origColor = this.getColor(attr);
12001             var restoreColor = this.dom.style[attr];
12002             endColor = (o.endColor || origColor) || "ffffff";
12003
12004             var after = function(){
12005                 el.dom.style[attr] = restoreColor;
12006                 el.afterFx(o);
12007             };
12008
12009             var a = {};
12010             a[attr] = {from: color, to: endColor};
12011             arguments.callee.anim = this.fxanim(a,
12012                 o,
12013                 'color',
12014                 1,
12015                 'easeIn', after);
12016         });
12017         return this;
12018     },
12019
12020    /**
12021     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
12022     * Usage:
12023 <pre><code>
12024 // default: a single light blue ripple
12025 el.frame();
12026
12027 // custom: 3 red ripples lasting 3 seconds total
12028 el.frame("ff0000", 3, { duration: 3 });
12029
12030 // common config options shown with default values
12031 el.frame("C3DAF9", 1, {
12032     duration: 1 //duration of entire animation (not each individual ripple)
12033     // Note: Easing is not configurable and will be ignored if included
12034 });
12035 </code></pre>
12036     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
12037     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
12038     * @param {Object} options (optional) Object literal with any of the Fx config options
12039     * @return {Roo.Element} The Element
12040     */
12041     frame : function(color, count, o){
12042         var el = this.getFxEl();
12043         o = o || {};
12044
12045         el.queueFx(o, function(){
12046             color = color || "#C3DAF9";
12047             if(color.length == 6){
12048                 color = "#" + color;
12049             }
12050             count = count || 1;
12051             duration = o.duration || 1;
12052             this.show();
12053
12054             var b = this.getBox();
12055             var animFn = function(){
12056                 var proxy = this.createProxy({
12057
12058                      style:{
12059                         visbility:"hidden",
12060                         position:"absolute",
12061                         "z-index":"35000", // yee haw
12062                         border:"0px solid " + color
12063                      }
12064                   });
12065                 var scale = Roo.isBorderBox ? 2 : 1;
12066                 proxy.animate({
12067                     top:{from:b.y, to:b.y - 20},
12068                     left:{from:b.x, to:b.x - 20},
12069                     borderWidth:{from:0, to:10},
12070                     opacity:{from:1, to:0},
12071                     height:{from:b.height, to:(b.height + (20*scale))},
12072                     width:{from:b.width, to:(b.width + (20*scale))}
12073                 }, duration, function(){
12074                     proxy.remove();
12075                 });
12076                 if(--count > 0){
12077                      animFn.defer((duration/2)*1000, this);
12078                 }else{
12079                     el.afterFx(o);
12080                 }
12081             };
12082             animFn.call(this);
12083         });
12084         return this;
12085     },
12086
12087    /**
12088     * Creates a pause before any subsequent queued effects begin.  If there are
12089     * no effects queued after the pause it will have no effect.
12090     * Usage:
12091 <pre><code>
12092 el.pause(1);
12093 </code></pre>
12094     * @param {Number} seconds The length of time to pause (in seconds)
12095     * @return {Roo.Element} The Element
12096     */
12097     pause : function(seconds){
12098         var el = this.getFxEl();
12099         var o = {};
12100
12101         el.queueFx(o, function(){
12102             setTimeout(function(){
12103                 el.afterFx(o);
12104             }, seconds * 1000);
12105         });
12106         return this;
12107     },
12108
12109    /**
12110     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
12111     * using the "endOpacity" config option.
12112     * Usage:
12113 <pre><code>
12114 // default: fade in from opacity 0 to 100%
12115 el.fadeIn();
12116
12117 // custom: fade in from opacity 0 to 75% over 2 seconds
12118 el.fadeIn({ endOpacity: .75, duration: 2});
12119
12120 // common config options shown with default values
12121 el.fadeIn({
12122     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
12123     easing: 'easeOut',
12124     duration: .5
12125 });
12126 </code></pre>
12127     * @param {Object} options (optional) Object literal with any of the Fx config options
12128     * @return {Roo.Element} The Element
12129     */
12130     fadeIn : function(o){
12131         var el = this.getFxEl();
12132         o = o || {};
12133         el.queueFx(o, function(){
12134             this.setOpacity(0);
12135             this.fixDisplay();
12136             this.dom.style.visibility = 'visible';
12137             var to = o.endOpacity || 1;
12138             arguments.callee.anim = this.fxanim({opacity:{to:to}},
12139                 o, null, .5, "easeOut", function(){
12140                 if(to == 1){
12141                     this.clearOpacity();
12142                 }
12143                 el.afterFx(o);
12144             });
12145         });
12146         return this;
12147     },
12148
12149    /**
12150     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
12151     * using the "endOpacity" config option.
12152     * Usage:
12153 <pre><code>
12154 // default: fade out from the element's current opacity to 0
12155 el.fadeOut();
12156
12157 // custom: fade out from the element's current opacity to 25% over 2 seconds
12158 el.fadeOut({ endOpacity: .25, duration: 2});
12159
12160 // common config options shown with default values
12161 el.fadeOut({
12162     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
12163     easing: 'easeOut',
12164     duration: .5
12165     remove: false,
12166     useDisplay: false
12167 });
12168 </code></pre>
12169     * @param {Object} options (optional) Object literal with any of the Fx config options
12170     * @return {Roo.Element} The Element
12171     */
12172     fadeOut : function(o){
12173         var el = this.getFxEl();
12174         o = o || {};
12175         el.queueFx(o, function(){
12176             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
12177                 o, null, .5, "easeOut", function(){
12178                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
12179                      this.dom.style.display = "none";
12180                 }else{
12181                      this.dom.style.visibility = "hidden";
12182                 }
12183                 this.clearOpacity();
12184                 el.afterFx(o);
12185             });
12186         });
12187         return this;
12188     },
12189
12190    /**
12191     * Animates the transition of an element's dimensions from a starting height/width
12192     * to an ending height/width.
12193     * Usage:
12194 <pre><code>
12195 // change height and width to 100x100 pixels
12196 el.scale(100, 100);
12197
12198 // common config options shown with default values.  The height and width will default to
12199 // the element's existing values if passed as null.
12200 el.scale(
12201     [element's width],
12202     [element's height], {
12203     easing: 'easeOut',
12204     duration: .35
12205 });
12206 </code></pre>
12207     * @param {Number} width  The new width (pass undefined to keep the original width)
12208     * @param {Number} height  The new height (pass undefined to keep the original height)
12209     * @param {Object} options (optional) Object literal with any of the Fx config options
12210     * @return {Roo.Element} The Element
12211     */
12212     scale : function(w, h, o){
12213         this.shift(Roo.apply({}, o, {
12214             width: w,
12215             height: h
12216         }));
12217         return this;
12218     },
12219
12220    /**
12221     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
12222     * Any of these properties not specified in the config object will not be changed.  This effect 
12223     * requires that at least one new dimension, position or opacity setting must be passed in on
12224     * the config object in order for the function to have any effect.
12225     * Usage:
12226 <pre><code>
12227 // slide the element horizontally to x position 200 while changing the height and opacity
12228 el.shift({ x: 200, height: 50, opacity: .8 });
12229
12230 // common config options shown with default values.
12231 el.shift({
12232     width: [element's width],
12233     height: [element's height],
12234     x: [element's x position],
12235     y: [element's y position],
12236     opacity: [element's opacity],
12237     easing: 'easeOut',
12238     duration: .35
12239 });
12240 </code></pre>
12241     * @param {Object} options  Object literal with any of the Fx config options
12242     * @return {Roo.Element} The Element
12243     */
12244     shift : function(o){
12245         var el = this.getFxEl();
12246         o = o || {};
12247         el.queueFx(o, function(){
12248             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
12249             if(w !== undefined){
12250                 a.width = {to: this.adjustWidth(w)};
12251             }
12252             if(h !== undefined){
12253                 a.height = {to: this.adjustHeight(h)};
12254             }
12255             if(x !== undefined || y !== undefined){
12256                 a.points = {to: [
12257                     x !== undefined ? x : this.getX(),
12258                     y !== undefined ? y : this.getY()
12259                 ]};
12260             }
12261             if(op !== undefined){
12262                 a.opacity = {to: op};
12263             }
12264             if(o.xy !== undefined){
12265                 a.points = {to: o.xy};
12266             }
12267             arguments.callee.anim = this.fxanim(a,
12268                 o, 'motion', .35, "easeOut", function(){
12269                 el.afterFx(o);
12270             });
12271         });
12272         return this;
12273     },
12274
12275         /**
12276          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
12277          * ending point of the effect.
12278          * Usage:
12279          *<pre><code>
12280 // default: slide the element downward while fading out
12281 el.ghost();
12282
12283 // custom: slide the element out to the right with a 2-second duration
12284 el.ghost('r', { duration: 2 });
12285
12286 // common config options shown with default values
12287 el.ghost('b', {
12288     easing: 'easeOut',
12289     duration: .5
12290     remove: false,
12291     useDisplay: false
12292 });
12293 </code></pre>
12294          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
12295          * @param {Object} options (optional) Object literal with any of the Fx config options
12296          * @return {Roo.Element} The Element
12297          */
12298     ghost : function(anchor, o){
12299         var el = this.getFxEl();
12300         o = o || {};
12301
12302         el.queueFx(o, function(){
12303             anchor = anchor || "b";
12304
12305             // restore values after effect
12306             var r = this.getFxRestore();
12307             var w = this.getWidth(),
12308                 h = this.getHeight();
12309
12310             var st = this.dom.style;
12311
12312             var after = function(){
12313                 if(o.useDisplay){
12314                     el.setDisplayed(false);
12315                 }else{
12316                     el.hide();
12317                 }
12318
12319                 el.clearOpacity();
12320                 el.setPositioning(r.pos);
12321                 st.width = r.width;
12322                 st.height = r.height;
12323
12324                 el.afterFx(o);
12325             };
12326
12327             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
12328             switch(anchor.toLowerCase()){
12329                 case "t":
12330                     pt.by = [0, -h];
12331                 break;
12332                 case "l":
12333                     pt.by = [-w, 0];
12334                 break;
12335                 case "r":
12336                     pt.by = [w, 0];
12337                 break;
12338                 case "b":
12339                     pt.by = [0, h];
12340                 break;
12341                 case "tl":
12342                     pt.by = [-w, -h];
12343                 break;
12344                 case "bl":
12345                     pt.by = [-w, h];
12346                 break;
12347                 case "br":
12348                     pt.by = [w, h];
12349                 break;
12350                 case "tr":
12351                     pt.by = [w, -h];
12352                 break;
12353             }
12354
12355             arguments.callee.anim = this.fxanim(a,
12356                 o,
12357                 'motion',
12358                 .5,
12359                 "easeOut", after);
12360         });
12361         return this;
12362     },
12363
12364         /**
12365          * Ensures that all effects queued after syncFx is called on the element are
12366          * run concurrently.  This is the opposite of {@link #sequenceFx}.
12367          * @return {Roo.Element} The Element
12368          */
12369     syncFx : function(){
12370         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12371             block : false,
12372             concurrent : true,
12373             stopFx : false
12374         });
12375         return this;
12376     },
12377
12378         /**
12379          * Ensures that all effects queued after sequenceFx is called on the element are
12380          * run in sequence.  This is the opposite of {@link #syncFx}.
12381          * @return {Roo.Element} The Element
12382          */
12383     sequenceFx : function(){
12384         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
12385             block : false,
12386             concurrent : false,
12387             stopFx : false
12388         });
12389         return this;
12390     },
12391
12392         /* @private */
12393     nextFx : function(){
12394         var ef = this.fxQueue[0];
12395         if(ef){
12396             ef.call(this);
12397         }
12398     },
12399
12400         /**
12401          * Returns true if the element has any effects actively running or queued, else returns false.
12402          * @return {Boolean} True if element has active effects, else false
12403          */
12404     hasActiveFx : function(){
12405         return this.fxQueue && this.fxQueue[0];
12406     },
12407
12408         /**
12409          * Stops any running effects and clears the element's internal effects queue if it contains
12410          * any additional effects that haven't started yet.
12411          * @return {Roo.Element} The Element
12412          */
12413     stopFx : function(){
12414         if(this.hasActiveFx()){
12415             var cur = this.fxQueue[0];
12416             if(cur && cur.anim && cur.anim.isAnimated()){
12417                 this.fxQueue = [cur]; // clear out others
12418                 cur.anim.stop(true);
12419             }
12420         }
12421         return this;
12422     },
12423
12424         /* @private */
12425     beforeFx : function(o){
12426         if(this.hasActiveFx() && !o.concurrent){
12427            if(o.stopFx){
12428                this.stopFx();
12429                return true;
12430            }
12431            return false;
12432         }
12433         return true;
12434     },
12435
12436         /**
12437          * Returns true if the element is currently blocking so that no other effect can be queued
12438          * until this effect is finished, else returns false if blocking is not set.  This is commonly
12439          * used to ensure that an effect initiated by a user action runs to completion prior to the
12440          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
12441          * @return {Boolean} True if blocking, else false
12442          */
12443     hasFxBlock : function(){
12444         var q = this.fxQueue;
12445         return q && q[0] && q[0].block;
12446     },
12447
12448         /* @private */
12449     queueFx : function(o, fn){
12450         if(!this.fxQueue){
12451             this.fxQueue = [];
12452         }
12453         if(!this.hasFxBlock()){
12454             Roo.applyIf(o, this.fxDefaults);
12455             if(!o.concurrent){
12456                 var run = this.beforeFx(o);
12457                 fn.block = o.block;
12458                 this.fxQueue.push(fn);
12459                 if(run){
12460                     this.nextFx();
12461                 }
12462             }else{
12463                 fn.call(this);
12464             }
12465         }
12466         return this;
12467     },
12468
12469         /* @private */
12470     fxWrap : function(pos, o, vis){
12471         var wrap;
12472         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
12473             var wrapXY;
12474             if(o.fixPosition){
12475                 wrapXY = this.getXY();
12476             }
12477             var div = document.createElement("div");
12478             div.style.visibility = vis;
12479             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
12480             wrap.setPositioning(pos);
12481             if(wrap.getStyle("position") == "static"){
12482                 wrap.position("relative");
12483             }
12484             this.clearPositioning('auto');
12485             wrap.clip();
12486             wrap.dom.appendChild(this.dom);
12487             if(wrapXY){
12488                 wrap.setXY(wrapXY);
12489             }
12490         }
12491         return wrap;
12492     },
12493
12494         /* @private */
12495     fxUnwrap : function(wrap, pos, o){
12496         this.clearPositioning();
12497         this.setPositioning(pos);
12498         if(!o.wrap){
12499             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
12500             wrap.remove();
12501         }
12502     },
12503
12504         /* @private */
12505     getFxRestore : function(){
12506         var st = this.dom.style;
12507         return {pos: this.getPositioning(), width: st.width, height : st.height};
12508     },
12509
12510         /* @private */
12511     afterFx : function(o){
12512         if(o.afterStyle){
12513             this.applyStyles(o.afterStyle);
12514         }
12515         if(o.afterCls){
12516             this.addClass(o.afterCls);
12517         }
12518         if(o.remove === true){
12519             this.remove();
12520         }
12521         Roo.callback(o.callback, o.scope, [this]);
12522         if(!o.concurrent){
12523             this.fxQueue.shift();
12524             this.nextFx();
12525         }
12526     },
12527
12528         /* @private */
12529     getFxEl : function(){ // support for composite element fx
12530         return Roo.get(this.dom);
12531     },
12532
12533         /* @private */
12534     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12535         animType = animType || 'run';
12536         opt = opt || {};
12537         var anim = Roo.lib.Anim[animType](
12538             this.dom, args,
12539             (opt.duration || defaultDur) || .35,
12540             (opt.easing || defaultEase) || 'easeOut',
12541             function(){
12542                 Roo.callback(cb, this);
12543             },
12544             this
12545         );
12546         opt.anim = anim;
12547         return anim;
12548     }
12549 };
12550
12551 // backwords compat
12552 Roo.Fx.resize = Roo.Fx.scale;
12553
12554 //When included, Roo.Fx is automatically applied to Element so that all basic
12555 //effects are available directly via the Element API
12556 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12557  * Based on:
12558  * Ext JS Library 1.1.1
12559  * Copyright(c) 2006-2007, Ext JS, LLC.
12560  *
12561  * Originally Released Under LGPL - original licence link has changed is not relivant.
12562  *
12563  * Fork - LGPL
12564  * <script type="text/javascript">
12565  */
12566
12567
12568 /**
12569  * @class Roo.CompositeElement
12570  * Standard composite class. Creates a Roo.Element for every element in the collection.
12571  * <br><br>
12572  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12573  * actions will be performed on all the elements in this collection.</b>
12574  * <br><br>
12575  * All methods return <i>this</i> and can be chained.
12576  <pre><code>
12577  var els = Roo.select("#some-el div.some-class", true);
12578  // or select directly from an existing element
12579  var el = Roo.get('some-el');
12580  el.select('div.some-class', true);
12581
12582  els.setWidth(100); // all elements become 100 width
12583  els.hide(true); // all elements fade out and hide
12584  // or
12585  els.setWidth(100).hide(true);
12586  </code></pre>
12587  */
12588 Roo.CompositeElement = function(els){
12589     this.elements = [];
12590     this.addElements(els);
12591 };
12592 Roo.CompositeElement.prototype = {
12593     isComposite: true,
12594     addElements : function(els){
12595         if(!els) {
12596             return this;
12597         }
12598         if(typeof els == "string"){
12599             els = Roo.Element.selectorFunction(els);
12600         }
12601         var yels = this.elements;
12602         var index = yels.length-1;
12603         for(var i = 0, len = els.length; i < len; i++) {
12604                 yels[++index] = Roo.get(els[i]);
12605         }
12606         return this;
12607     },
12608
12609     /**
12610     * Clears this composite and adds the elements returned by the passed selector.
12611     * @param {String/Array} els A string CSS selector, an array of elements or an element
12612     * @return {CompositeElement} this
12613     */
12614     fill : function(els){
12615         this.elements = [];
12616         this.add(els);
12617         return this;
12618     },
12619
12620     /**
12621     * Filters this composite to only elements that match the passed selector.
12622     * @param {String} selector A string CSS selector
12623     * @param {Boolean} inverse return inverse filter (not matches)
12624     * @return {CompositeElement} this
12625     */
12626     filter : function(selector, inverse){
12627         var els = [];
12628         inverse = inverse || false;
12629         this.each(function(el){
12630             var match = inverse ? !el.is(selector) : el.is(selector);
12631             if(match){
12632                 els[els.length] = el.dom;
12633             }
12634         });
12635         this.fill(els);
12636         return this;
12637     },
12638
12639     invoke : function(fn, args){
12640         var els = this.elements;
12641         for(var i = 0, len = els.length; i < len; i++) {
12642                 Roo.Element.prototype[fn].apply(els[i], args);
12643         }
12644         return this;
12645     },
12646     /**
12647     * Adds elements to this composite.
12648     * @param {String/Array} els A string CSS selector, an array of elements or an element
12649     * @return {CompositeElement} this
12650     */
12651     add : function(els){
12652         if(typeof els == "string"){
12653             this.addElements(Roo.Element.selectorFunction(els));
12654         }else if(els.length !== undefined){
12655             this.addElements(els);
12656         }else{
12657             this.addElements([els]);
12658         }
12659         return this;
12660     },
12661     /**
12662     * Calls the passed function passing (el, this, index) for each element in this composite.
12663     * @param {Function} fn The function to call
12664     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12665     * @return {CompositeElement} this
12666     */
12667     each : function(fn, scope){
12668         var els = this.elements;
12669         for(var i = 0, len = els.length; i < len; i++){
12670             if(fn.call(scope || els[i], els[i], this, i) === false) {
12671                 break;
12672             }
12673         }
12674         return this;
12675     },
12676
12677     /**
12678      * Returns the Element object at the specified index
12679      * @param {Number} index
12680      * @return {Roo.Element}
12681      */
12682     item : function(index){
12683         return this.elements[index] || null;
12684     },
12685
12686     /**
12687      * Returns the first Element
12688      * @return {Roo.Element}
12689      */
12690     first : function(){
12691         return this.item(0);
12692     },
12693
12694     /**
12695      * Returns the last Element
12696      * @return {Roo.Element}
12697      */
12698     last : function(){
12699         return this.item(this.elements.length-1);
12700     },
12701
12702     /**
12703      * Returns the number of elements in this composite
12704      * @return Number
12705      */
12706     getCount : function(){
12707         return this.elements.length;
12708     },
12709
12710     /**
12711      * Returns true if this composite contains the passed element
12712      * @return Boolean
12713      */
12714     contains : function(el){
12715         return this.indexOf(el) !== -1;
12716     },
12717
12718     /**
12719      * Returns true if this composite contains the passed element
12720      * @return Boolean
12721      */
12722     indexOf : function(el){
12723         return this.elements.indexOf(Roo.get(el));
12724     },
12725
12726
12727     /**
12728     * Removes the specified element(s).
12729     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12730     * or an array of any of those.
12731     * @param {Boolean} removeDom (optional) True to also remove the element from the document
12732     * @return {CompositeElement} this
12733     */
12734     removeElement : function(el, removeDom){
12735         if(el instanceof Array){
12736             for(var i = 0, len = el.length; i < len; i++){
12737                 this.removeElement(el[i]);
12738             }
12739             return this;
12740         }
12741         var index = typeof el == 'number' ? el : this.indexOf(el);
12742         if(index !== -1){
12743             if(removeDom){
12744                 var d = this.elements[index];
12745                 if(d.dom){
12746                     d.remove();
12747                 }else{
12748                     d.parentNode.removeChild(d);
12749                 }
12750             }
12751             this.elements.splice(index, 1);
12752         }
12753         return this;
12754     },
12755
12756     /**
12757     * Replaces the specified element with the passed element.
12758     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12759     * to replace.
12760     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12761     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12762     * @return {CompositeElement} this
12763     */
12764     replaceElement : function(el, replacement, domReplace){
12765         var index = typeof el == 'number' ? el : this.indexOf(el);
12766         if(index !== -1){
12767             if(domReplace){
12768                 this.elements[index].replaceWith(replacement);
12769             }else{
12770                 this.elements.splice(index, 1, Roo.get(replacement))
12771             }
12772         }
12773         return this;
12774     },
12775
12776     /**
12777      * Removes all elements.
12778      */
12779     clear : function(){
12780         this.elements = [];
12781     }
12782 };
12783 (function(){
12784     Roo.CompositeElement.createCall = function(proto, fnName){
12785         if(!proto[fnName]){
12786             proto[fnName] = function(){
12787                 return this.invoke(fnName, arguments);
12788             };
12789         }
12790     };
12791     for(var fnName in Roo.Element.prototype){
12792         if(typeof Roo.Element.prototype[fnName] == "function"){
12793             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12794         }
12795     };
12796 })();
12797 /*
12798  * Based on:
12799  * Ext JS Library 1.1.1
12800  * Copyright(c) 2006-2007, Ext JS, LLC.
12801  *
12802  * Originally Released Under LGPL - original licence link has changed is not relivant.
12803  *
12804  * Fork - LGPL
12805  * <script type="text/javascript">
12806  */
12807
12808 /**
12809  * @class Roo.CompositeElementLite
12810  * @extends Roo.CompositeElement
12811  * Flyweight composite class. Reuses the same Roo.Element for element operations.
12812  <pre><code>
12813  var els = Roo.select("#some-el div.some-class");
12814  // or select directly from an existing element
12815  var el = Roo.get('some-el');
12816  el.select('div.some-class');
12817
12818  els.setWidth(100); // all elements become 100 width
12819  els.hide(true); // all elements fade out and hide
12820  // or
12821  els.setWidth(100).hide(true);
12822  </code></pre><br><br>
12823  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12824  * actions will be performed on all the elements in this collection.</b>
12825  */
12826 Roo.CompositeElementLite = function(els){
12827     Roo.CompositeElementLite.superclass.constructor.call(this, els);
12828     this.el = new Roo.Element.Flyweight();
12829 };
12830 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12831     addElements : function(els){
12832         if(els){
12833             if(els instanceof Array){
12834                 this.elements = this.elements.concat(els);
12835             }else{
12836                 var yels = this.elements;
12837                 var index = yels.length-1;
12838                 for(var i = 0, len = els.length; i < len; i++) {
12839                     yels[++index] = els[i];
12840                 }
12841             }
12842         }
12843         return this;
12844     },
12845     invoke : function(fn, args){
12846         var els = this.elements;
12847         var el = this.el;
12848         for(var i = 0, len = els.length; i < len; i++) {
12849             el.dom = els[i];
12850                 Roo.Element.prototype[fn].apply(el, args);
12851         }
12852         return this;
12853     },
12854     /**
12855      * Returns a flyweight Element of the dom element object at the specified index
12856      * @param {Number} index
12857      * @return {Roo.Element}
12858      */
12859     item : function(index){
12860         if(!this.elements[index]){
12861             return null;
12862         }
12863         this.el.dom = this.elements[index];
12864         return this.el;
12865     },
12866
12867     // fixes scope with flyweight
12868     addListener : function(eventName, handler, scope, opt){
12869         var els = this.elements;
12870         for(var i = 0, len = els.length; i < len; i++) {
12871             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12872         }
12873         return this;
12874     },
12875
12876     /**
12877     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12878     * passed is the flyweight (shared) Roo.Element instance, so if you require a
12879     * a reference to the dom node, use el.dom.</b>
12880     * @param {Function} fn The function to call
12881     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12882     * @return {CompositeElement} this
12883     */
12884     each : function(fn, scope){
12885         var els = this.elements;
12886         var el = this.el;
12887         for(var i = 0, len = els.length; i < len; i++){
12888             el.dom = els[i];
12889                 if(fn.call(scope || el, el, this, i) === false){
12890                 break;
12891             }
12892         }
12893         return this;
12894     },
12895
12896     indexOf : function(el){
12897         return this.elements.indexOf(Roo.getDom(el));
12898     },
12899
12900     replaceElement : function(el, replacement, domReplace){
12901         var index = typeof el == 'number' ? el : this.indexOf(el);
12902         if(index !== -1){
12903             replacement = Roo.getDom(replacement);
12904             if(domReplace){
12905                 var d = this.elements[index];
12906                 d.parentNode.insertBefore(replacement, d);
12907                 d.parentNode.removeChild(d);
12908             }
12909             this.elements.splice(index, 1, replacement);
12910         }
12911         return this;
12912     }
12913 });
12914 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12915
12916 /*
12917  * Based on:
12918  * Ext JS Library 1.1.1
12919  * Copyright(c) 2006-2007, Ext JS, LLC.
12920  *
12921  * Originally Released Under LGPL - original licence link has changed is not relivant.
12922  *
12923  * Fork - LGPL
12924  * <script type="text/javascript">
12925  */
12926
12927  
12928
12929 /**
12930  * @class Roo.data.Connection
12931  * @extends Roo.util.Observable
12932  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12933  * either to a configured URL, or to a URL specified at request time. 
12934  * 
12935  * Requests made by this class are asynchronous, and will return immediately. No data from
12936  * the server will be available to the statement immediately following the {@link #request} call.
12937  * To process returned data, use a callback in the request options object, or an event listener.
12938  * 
12939  * Note: If you are doing a file upload, you will not get a normal response object sent back to
12940  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12941  * The response object is created using the innerHTML of the IFRAME's document as the responseText
12942  * property and, if present, the IFRAME's XML document as the responseXML property.
12943  * 
12944  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12945  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
12946  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12947  * standard DOM methods.
12948  * @constructor
12949  * @param {Object} config a configuration object.
12950  */
12951 Roo.data.Connection = function(config){
12952     Roo.apply(this, config);
12953     this.addEvents({
12954         /**
12955          * @event beforerequest
12956          * Fires before a network request is made to retrieve a data object.
12957          * @param {Connection} conn This Connection object.
12958          * @param {Object} options The options config object passed to the {@link #request} method.
12959          */
12960         "beforerequest" : true,
12961         /**
12962          * @event requestcomplete
12963          * Fires if the request was successfully completed.
12964          * @param {Connection} conn This Connection object.
12965          * @param {Object} response The XHR object containing the response data.
12966          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12967          * @param {Object} options The options config object passed to the {@link #request} method.
12968          */
12969         "requestcomplete" : true,
12970         /**
12971          * @event requestexception
12972          * Fires if an error HTTP status was returned from the server.
12973          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12974          * @param {Connection} conn This Connection object.
12975          * @param {Object} response The XHR object containing the response data.
12976          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12977          * @param {Object} options The options config object passed to the {@link #request} method.
12978          */
12979         "requestexception" : true
12980     });
12981     Roo.data.Connection.superclass.constructor.call(this);
12982 };
12983
12984 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12985     /**
12986      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12987      */
12988     /**
12989      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12990      * extra parameters to each request made by this object. (defaults to undefined)
12991      */
12992     /**
12993      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12994      *  to each request made by this object. (defaults to undefined)
12995      */
12996     /**
12997      * @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)
12998      */
12999     /**
13000      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13001      */
13002     timeout : 30000,
13003     /**
13004      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
13005      * @type Boolean
13006      */
13007     autoAbort:false,
13008
13009     /**
13010      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
13011      * @type Boolean
13012      */
13013     disableCaching: true,
13014
13015     /**
13016      * Sends an HTTP request to a remote server.
13017      * @param {Object} options An object which may contain the following properties:<ul>
13018      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
13019      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
13020      * request, a url encoded string or a function to call to get either.</li>
13021      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
13022      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
13023      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
13024      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
13025      * <li>options {Object} The parameter to the request call.</li>
13026      * <li>success {Boolean} True if the request succeeded.</li>
13027      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13028      * </ul></li>
13029      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
13030      * The callback is passed the following parameters:<ul>
13031      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13032      * <li>options {Object} The parameter to the request call.</li>
13033      * </ul></li>
13034      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
13035      * The callback is passed the following parameters:<ul>
13036      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
13037      * <li>options {Object} The parameter to the request call.</li>
13038      * </ul></li>
13039      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
13040      * for the callback function. Defaults to the browser window.</li>
13041      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
13042      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
13043      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
13044      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
13045      * params for the post data. Any params will be appended to the URL.</li>
13046      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
13047      * </ul>
13048      * @return {Number} transactionId
13049      */
13050     request : function(o){
13051         if(this.fireEvent("beforerequest", this, o) !== false){
13052             var p = o.params;
13053
13054             if(typeof p == "function"){
13055                 p = p.call(o.scope||window, o);
13056             }
13057             if(typeof p == "object"){
13058                 p = Roo.urlEncode(o.params);
13059             }
13060             if(this.extraParams){
13061                 var extras = Roo.urlEncode(this.extraParams);
13062                 p = p ? (p + '&' + extras) : extras;
13063             }
13064
13065             var url = o.url || this.url;
13066             if(typeof url == 'function'){
13067                 url = url.call(o.scope||window, o);
13068             }
13069
13070             if(o.form){
13071                 var form = Roo.getDom(o.form);
13072                 url = url || form.action;
13073
13074                 var enctype = form.getAttribute("enctype");
13075                 
13076                 if (o.formData) {
13077                     return this.doFormDataUpload(o, url);
13078                 }
13079                 
13080                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
13081                     return this.doFormUpload(o, p, url);
13082                 }
13083                 var f = Roo.lib.Ajax.serializeForm(form);
13084                 p = p ? (p + '&' + f) : f;
13085             }
13086             
13087             if (!o.form && o.formData) {
13088                 o.formData = o.formData === true ? new FormData() : o.formData;
13089                 for (var k in o.params) {
13090                     o.formData.append(k,o.params[k]);
13091                 }
13092                     
13093                 return this.doFormDataUpload(o, url);
13094             }
13095             
13096
13097             var hs = o.headers;
13098             if(this.defaultHeaders){
13099                 hs = Roo.apply(hs || {}, this.defaultHeaders);
13100                 if(!o.headers){
13101                     o.headers = hs;
13102                 }
13103             }
13104
13105             var cb = {
13106                 success: this.handleResponse,
13107                 failure: this.handleFailure,
13108                 scope: this,
13109                 argument: {options: o},
13110                 timeout : o.timeout || this.timeout
13111             };
13112
13113             var method = o.method||this.method||(p ? "POST" : "GET");
13114
13115             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
13116                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
13117             }
13118
13119             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13120                 if(o.autoAbort){
13121                     this.abort();
13122                 }
13123             }else if(this.autoAbort !== false){
13124                 this.abort();
13125             }
13126
13127             if((method == 'GET' && p) || o.xmlData){
13128                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
13129                 p = '';
13130             }
13131             Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
13132             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
13133             Roo.lib.Ajax.useDefaultHeader == true;
13134             return this.transId;
13135         }else{
13136             Roo.callback(o.callback, o.scope, [o, null, null]);
13137             return null;
13138         }
13139     },
13140
13141     /**
13142      * Determine whether this object has a request outstanding.
13143      * @param {Number} transactionId (Optional) defaults to the last transaction
13144      * @return {Boolean} True if there is an outstanding request.
13145      */
13146     isLoading : function(transId){
13147         if(transId){
13148             return Roo.lib.Ajax.isCallInProgress(transId);
13149         }else{
13150             return this.transId ? true : false;
13151         }
13152     },
13153
13154     /**
13155      * Aborts any outstanding request.
13156      * @param {Number} transactionId (Optional) defaults to the last transaction
13157      */
13158     abort : function(transId){
13159         if(transId || this.isLoading()){
13160             Roo.lib.Ajax.abort(transId || this.transId);
13161         }
13162     },
13163
13164     // private
13165     handleResponse : function(response){
13166         this.transId = false;
13167         var options = response.argument.options;
13168         response.argument = options ? options.argument : null;
13169         this.fireEvent("requestcomplete", this, response, options);
13170         Roo.callback(options.success, options.scope, [response, options]);
13171         Roo.callback(options.callback, options.scope, [options, true, response]);
13172     },
13173
13174     // private
13175     handleFailure : function(response, e){
13176         this.transId = false;
13177         var options = response.argument.options;
13178         response.argument = options ? options.argument : null;
13179         this.fireEvent("requestexception", this, response, options, e);
13180         Roo.callback(options.failure, options.scope, [response, options]);
13181         Roo.callback(options.callback, options.scope, [options, false, response]);
13182     },
13183
13184     // private
13185     doFormUpload : function(o, ps, url){
13186         var id = Roo.id();
13187         var frame = document.createElement('iframe');
13188         frame.id = id;
13189         frame.name = id;
13190         frame.className = 'x-hidden';
13191         if(Roo.isIE){
13192             frame.src = Roo.SSL_SECURE_URL;
13193         }
13194         document.body.appendChild(frame);
13195
13196         if(Roo.isIE){
13197            document.frames[id].name = id;
13198         }
13199
13200         var form = Roo.getDom(o.form);
13201         form.target = id;
13202         form.method = 'POST';
13203         form.enctype = form.encoding = 'multipart/form-data';
13204         if(url){
13205             form.action = url;
13206         }
13207
13208         var hiddens, hd;
13209         if(ps){ // add dynamic params
13210             hiddens = [];
13211             ps = Roo.urlDecode(ps, false);
13212             for(var k in ps){
13213                 if(ps.hasOwnProperty(k)){
13214                     hd = document.createElement('input');
13215                     hd.type = 'hidden';
13216                     hd.name = k;
13217                     hd.value = ps[k];
13218                     form.appendChild(hd);
13219                     hiddens.push(hd);
13220                 }
13221             }
13222         }
13223
13224         function cb(){
13225             var r = {  // bogus response object
13226                 responseText : '',
13227                 responseXML : null
13228             };
13229
13230             r.argument = o ? o.argument : null;
13231
13232             try { //
13233                 var doc;
13234                 if(Roo.isIE){
13235                     doc = frame.contentWindow.document;
13236                 }else {
13237                     doc = (frame.contentDocument || window.frames[id].document);
13238                 }
13239                 if(doc && doc.body){
13240                     r.responseText = doc.body.innerHTML;
13241                 }
13242                 if(doc && doc.XMLDocument){
13243                     r.responseXML = doc.XMLDocument;
13244                 }else {
13245                     r.responseXML = doc;
13246                 }
13247             }
13248             catch(e) {
13249                 // ignore
13250             }
13251
13252             Roo.EventManager.removeListener(frame, 'load', cb, this);
13253
13254             this.fireEvent("requestcomplete", this, r, o);
13255             Roo.callback(o.success, o.scope, [r, o]);
13256             Roo.callback(o.callback, o.scope, [o, true, r]);
13257
13258             setTimeout(function(){document.body.removeChild(frame);}, 100);
13259         }
13260
13261         Roo.EventManager.on(frame, 'load', cb, this);
13262         form.submit();
13263
13264         if(hiddens){ // remove dynamic params
13265             for(var i = 0, len = hiddens.length; i < len; i++){
13266                 form.removeChild(hiddens[i]);
13267             }
13268         }
13269     },
13270     // this is a 'formdata version???'
13271     
13272     
13273     doFormDataUpload : function(o,  url)
13274     {
13275         var formData;
13276         if (o.form) {
13277             var form =  Roo.getDom(o.form);
13278             form.enctype = form.encoding = 'multipart/form-data';
13279             formData = o.formData === true ? new FormData(form) : o.formData;
13280         } else {
13281             formData = o.formData === true ? new FormData() : o.formData;
13282         }
13283         
13284       
13285         var cb = {
13286             success: this.handleResponse,
13287             failure: this.handleFailure,
13288             scope: this,
13289             argument: {options: o},
13290             timeout : o.timeout || this.timeout
13291         };
13292  
13293         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
13294             if(o.autoAbort){
13295                 this.abort();
13296             }
13297         }else if(this.autoAbort !== false){
13298             this.abort();
13299         }
13300
13301         //Roo.lib.Ajax.defaultPostHeader = null;
13302         Roo.lib.Ajax.useDefaultHeader = false;
13303         this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
13304         Roo.lib.Ajax.useDefaultHeader = true;
13305  
13306          
13307     }
13308     
13309 });
13310 /*
13311  * Based on:
13312  * Ext JS Library 1.1.1
13313  * Copyright(c) 2006-2007, Ext JS, LLC.
13314  *
13315  * Originally Released Under LGPL - original licence link has changed is not relivant.
13316  *
13317  * Fork - LGPL
13318  * <script type="text/javascript">
13319  */
13320  
13321 /**
13322  * Global Ajax request class.
13323  * 
13324  * @class Roo.Ajax
13325  * @extends Roo.data.Connection
13326  * @static
13327  * 
13328  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
13329  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
13330  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
13331  * @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)
13332  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
13333  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
13334  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
13335  */
13336 Roo.Ajax = new Roo.data.Connection({
13337     // fix up the docs
13338     /**
13339      * @scope Roo.Ajax
13340      * @type {Boolear} 
13341      */
13342     autoAbort : false,
13343
13344     /**
13345      * Serialize the passed form into a url encoded string
13346      * @scope Roo.Ajax
13347      * @param {String/HTMLElement} form
13348      * @return {String}
13349      */
13350     serializeForm : function(form){
13351         return Roo.lib.Ajax.serializeForm(form);
13352     }
13353 });/*
13354  * Based on:
13355  * Ext JS Library 1.1.1
13356  * Copyright(c) 2006-2007, Ext JS, LLC.
13357  *
13358  * Originally Released Under LGPL - original licence link has changed is not relivant.
13359  *
13360  * Fork - LGPL
13361  * <script type="text/javascript">
13362  */
13363
13364  
13365 /**
13366  * @class Roo.UpdateManager
13367  * @extends Roo.util.Observable
13368  * Provides AJAX-style update for Element object.<br><br>
13369  * Usage:<br>
13370  * <pre><code>
13371  * // Get it from a Roo.Element object
13372  * var el = Roo.get("foo");
13373  * var mgr = el.getUpdateManager();
13374  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
13375  * ...
13376  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
13377  * <br>
13378  * // or directly (returns the same UpdateManager instance)
13379  * var mgr = new Roo.UpdateManager("myElementId");
13380  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
13381  * mgr.on("update", myFcnNeedsToKnow);
13382  * <br>
13383    // short handed call directly from the element object
13384    Roo.get("foo").load({
13385         url: "bar.php",
13386         scripts:true,
13387         params: "for=bar",
13388         text: "Loading Foo..."
13389    });
13390  * </code></pre>
13391  * @constructor
13392  * Create new UpdateManager directly.
13393  * @param {String/HTMLElement/Roo.Element} el The element to update
13394  * @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).
13395  */
13396 Roo.UpdateManager = function(el, forceNew){
13397     el = Roo.get(el);
13398     if(!forceNew && el.updateManager){
13399         return el.updateManager;
13400     }
13401     /**
13402      * The Element object
13403      * @type Roo.Element
13404      */
13405     this.el = el;
13406     /**
13407      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
13408      * @type String
13409      */
13410     this.defaultUrl = null;
13411
13412     this.addEvents({
13413         /**
13414          * @event beforeupdate
13415          * Fired before an update is made, return false from your handler and the update is cancelled.
13416          * @param {Roo.Element} el
13417          * @param {String/Object/Function} url
13418          * @param {String/Object} params
13419          */
13420         "beforeupdate": true,
13421         /**
13422          * @event update
13423          * Fired after successful update is made.
13424          * @param {Roo.Element} el
13425          * @param {Object} oResponseObject The response Object
13426          */
13427         "update": true,
13428         /**
13429          * @event failure
13430          * Fired on update failure.
13431          * @param {Roo.Element} el
13432          * @param {Object} oResponseObject The response Object
13433          */
13434         "failure": true
13435     });
13436     var d = Roo.UpdateManager.defaults;
13437     /**
13438      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
13439      * @type String
13440      */
13441     this.sslBlankUrl = d.sslBlankUrl;
13442     /**
13443      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
13444      * @type Boolean
13445      */
13446     this.disableCaching = d.disableCaching;
13447     /**
13448      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13449      * @type String
13450      */
13451     this.indicatorText = d.indicatorText;
13452     /**
13453      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
13454      * @type String
13455      */
13456     this.showLoadIndicator = d.showLoadIndicator;
13457     /**
13458      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
13459      * @type Number
13460      */
13461     this.timeout = d.timeout;
13462
13463     /**
13464      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
13465      * @type Boolean
13466      */
13467     this.loadScripts = d.loadScripts;
13468
13469     /**
13470      * Transaction object of current executing transaction
13471      */
13472     this.transaction = null;
13473
13474     /**
13475      * @private
13476      */
13477     this.autoRefreshProcId = null;
13478     /**
13479      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
13480      * @type Function
13481      */
13482     this.refreshDelegate = this.refresh.createDelegate(this);
13483     /**
13484      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
13485      * @type Function
13486      */
13487     this.updateDelegate = this.update.createDelegate(this);
13488     /**
13489      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
13490      * @type Function
13491      */
13492     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
13493     /**
13494      * @private
13495      */
13496     this.successDelegate = this.processSuccess.createDelegate(this);
13497     /**
13498      * @private
13499      */
13500     this.failureDelegate = this.processFailure.createDelegate(this);
13501
13502     if(!this.renderer){
13503      /**
13504       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
13505       */
13506     this.renderer = new Roo.UpdateManager.BasicRenderer();
13507     }
13508     
13509     Roo.UpdateManager.superclass.constructor.call(this);
13510 };
13511
13512 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
13513     /**
13514      * Get the Element this UpdateManager is bound to
13515      * @return {Roo.Element} The element
13516      */
13517     getEl : function(){
13518         return this.el;
13519     },
13520     /**
13521      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
13522      * @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:
13523 <pre><code>
13524 um.update({<br/>
13525     url: "your-url.php",<br/>
13526     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13527     callback: yourFunction,<br/>
13528     scope: yourObject, //(optional scope)  <br/>
13529     discardUrl: false, <br/>
13530     nocache: false,<br/>
13531     text: "Loading...",<br/>
13532     timeout: 30,<br/>
13533     scripts: false<br/>
13534 });
13535 </code></pre>
13536      * The only required property is url. The optional properties nocache, text and scripts
13537      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13538      * @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}
13539      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13540      * @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.
13541      */
13542     update : function(url, params, callback, discardUrl){
13543         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13544             var method = this.method,
13545                 cfg;
13546             if(typeof url == "object"){ // must be config object
13547                 cfg = url;
13548                 url = cfg.url;
13549                 params = params || cfg.params;
13550                 callback = callback || cfg.callback;
13551                 discardUrl = discardUrl || cfg.discardUrl;
13552                 if(callback && cfg.scope){
13553                     callback = callback.createDelegate(cfg.scope);
13554                 }
13555                 if(typeof cfg.method != "undefined"){method = cfg.method;};
13556                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13557                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13558                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13559                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13560             }
13561             this.showLoading();
13562             if(!discardUrl){
13563                 this.defaultUrl = url;
13564             }
13565             if(typeof url == "function"){
13566                 url = url.call(this);
13567             }
13568
13569             method = method || (params ? "POST" : "GET");
13570             if(method == "GET"){
13571                 url = this.prepareUrl(url);
13572             }
13573
13574             var o = Roo.apply(cfg ||{}, {
13575                 url : url,
13576                 params: params,
13577                 success: this.successDelegate,
13578                 failure: this.failureDelegate,
13579                 callback: undefined,
13580                 timeout: (this.timeout*1000),
13581                 argument: {"url": url, "form": null, "callback": callback, "params": params}
13582             });
13583             Roo.log("updated manager called with timeout of " + o.timeout);
13584             this.transaction = Roo.Ajax.request(o);
13585         }
13586     },
13587
13588     /**
13589      * 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.
13590      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13591      * @param {String/HTMLElement} form The form Id or form element
13592      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13593      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13594      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13595      */
13596     formUpdate : function(form, url, reset, callback){
13597         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13598             if(typeof url == "function"){
13599                 url = url.call(this);
13600             }
13601             form = Roo.getDom(form);
13602             this.transaction = Roo.Ajax.request({
13603                 form: form,
13604                 url:url,
13605                 success: this.successDelegate,
13606                 failure: this.failureDelegate,
13607                 timeout: (this.timeout*1000),
13608                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13609             });
13610             this.showLoading.defer(1, this);
13611         }
13612     },
13613
13614     /**
13615      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13616      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13617      */
13618     refresh : function(callback){
13619         if(this.defaultUrl == null){
13620             return;
13621         }
13622         this.update(this.defaultUrl, null, callback, true);
13623     },
13624
13625     /**
13626      * Set this element to auto refresh.
13627      * @param {Number} interval How often to update (in seconds).
13628      * @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)
13629      * @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}
13630      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13631      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13632      */
13633     startAutoRefresh : function(interval, url, params, callback, refreshNow){
13634         if(refreshNow){
13635             this.update(url || this.defaultUrl, params, callback, true);
13636         }
13637         if(this.autoRefreshProcId){
13638             clearInterval(this.autoRefreshProcId);
13639         }
13640         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13641     },
13642
13643     /**
13644      * Stop auto refresh on this element.
13645      */
13646      stopAutoRefresh : function(){
13647         if(this.autoRefreshProcId){
13648             clearInterval(this.autoRefreshProcId);
13649             delete this.autoRefreshProcId;
13650         }
13651     },
13652
13653     isAutoRefreshing : function(){
13654        return this.autoRefreshProcId ? true : false;
13655     },
13656     /**
13657      * Called to update the element to "Loading" state. Override to perform custom action.
13658      */
13659     showLoading : function(){
13660         if(this.showLoadIndicator){
13661             this.el.update(this.indicatorText);
13662         }
13663     },
13664
13665     /**
13666      * Adds unique parameter to query string if disableCaching = true
13667      * @private
13668      */
13669     prepareUrl : function(url){
13670         if(this.disableCaching){
13671             var append = "_dc=" + (new Date().getTime());
13672             if(url.indexOf("?") !== -1){
13673                 url += "&" + append;
13674             }else{
13675                 url += "?" + append;
13676             }
13677         }
13678         return url;
13679     },
13680
13681     /**
13682      * @private
13683      */
13684     processSuccess : function(response){
13685         this.transaction = null;
13686         if(response.argument.form && response.argument.reset){
13687             try{ // put in try/catch since some older FF releases had problems with this
13688                 response.argument.form.reset();
13689             }catch(e){}
13690         }
13691         if(this.loadScripts){
13692             this.renderer.render(this.el, response, this,
13693                 this.updateComplete.createDelegate(this, [response]));
13694         }else{
13695             this.renderer.render(this.el, response, this);
13696             this.updateComplete(response);
13697         }
13698     },
13699
13700     updateComplete : function(response){
13701         this.fireEvent("update", this.el, response);
13702         if(typeof response.argument.callback == "function"){
13703             response.argument.callback(this.el, true, response);
13704         }
13705     },
13706
13707     /**
13708      * @private
13709      */
13710     processFailure : function(response){
13711         this.transaction = null;
13712         this.fireEvent("failure", this.el, response);
13713         if(typeof response.argument.callback == "function"){
13714             response.argument.callback(this.el, false, response);
13715         }
13716     },
13717
13718     /**
13719      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13720      * @param {Object} renderer The object implementing the render() method
13721      */
13722     setRenderer : function(renderer){
13723         this.renderer = renderer;
13724     },
13725
13726     getRenderer : function(){
13727        return this.renderer;
13728     },
13729
13730     /**
13731      * Set the defaultUrl used for updates
13732      * @param {String/Function} defaultUrl The url or a function to call to get the url
13733      */
13734     setDefaultUrl : function(defaultUrl){
13735         this.defaultUrl = defaultUrl;
13736     },
13737
13738     /**
13739      * Aborts the executing transaction
13740      */
13741     abort : function(){
13742         if(this.transaction){
13743             Roo.Ajax.abort(this.transaction);
13744         }
13745     },
13746
13747     /**
13748      * Returns true if an update is in progress
13749      * @return {Boolean}
13750      */
13751     isUpdating : function(){
13752         if(this.transaction){
13753             return Roo.Ajax.isLoading(this.transaction);
13754         }
13755         return false;
13756     }
13757 });
13758
13759 /**
13760  * @class Roo.UpdateManager.defaults
13761  * @static (not really - but it helps the doc tool)
13762  * The defaults collection enables customizing the default properties of UpdateManager
13763  */
13764    Roo.UpdateManager.defaults = {
13765        /**
13766          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13767          * @type Number
13768          */
13769          timeout : 30,
13770
13771          /**
13772          * True to process scripts by default (Defaults to false).
13773          * @type Boolean
13774          */
13775         loadScripts : false,
13776
13777         /**
13778         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13779         * @type String
13780         */
13781         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13782         /**
13783          * Whether to append unique parameter on get request to disable caching (Defaults to false).
13784          * @type Boolean
13785          */
13786         disableCaching : false,
13787         /**
13788          * Whether to show indicatorText when loading (Defaults to true).
13789          * @type Boolean
13790          */
13791         showLoadIndicator : true,
13792         /**
13793          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
13794          * @type String
13795          */
13796         indicatorText : '<div class="loading-indicator">Loading...</div>'
13797    };
13798
13799 /**
13800  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13801  *Usage:
13802  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13803  * @param {String/HTMLElement/Roo.Element} el The element to update
13804  * @param {String} url The url
13805  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13806  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13807  * @static
13808  * @deprecated
13809  * @member Roo.UpdateManager
13810  */
13811 Roo.UpdateManager.updateElement = function(el, url, params, options){
13812     var um = Roo.get(el, true).getUpdateManager();
13813     Roo.apply(um, options);
13814     um.update(url, params, options ? options.callback : null);
13815 };
13816 // alias for backwards compat
13817 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13818 /**
13819  * @class Roo.UpdateManager.BasicRenderer
13820  * Default Content renderer. Updates the elements innerHTML with the responseText.
13821  */
13822 Roo.UpdateManager.BasicRenderer = function(){};
13823
13824 Roo.UpdateManager.BasicRenderer.prototype = {
13825     /**
13826      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13827      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13828      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13829      * @param {Roo.Element} el The element being rendered
13830      * @param {Object} response The YUI Connect response object
13831      * @param {UpdateManager} updateManager The calling update manager
13832      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13833      */
13834      render : function(el, response, updateManager, callback){
13835         el.update(response.responseText, updateManager.loadScripts, callback);
13836     }
13837 };
13838 /*
13839  * Based on:
13840  * Roo JS
13841  * (c)) Alan Knowles
13842  * Licence : LGPL
13843  */
13844
13845
13846 /**
13847  * @class Roo.DomTemplate
13848  * @extends Roo.Template
13849  * An effort at a dom based template engine..
13850  *
13851  * Similar to XTemplate, except it uses dom parsing to create the template..
13852  *
13853  * Supported features:
13854  *
13855  *  Tags:
13856
13857 <pre><code>
13858       {a_variable} - output encoded.
13859       {a_variable.format:("Y-m-d")} - call a method on the variable
13860       {a_variable:raw} - unencoded output
13861       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13862       {a_variable:this.method_on_template(...)} - call a method on the template object.
13863  
13864 </code></pre>
13865  *  The tpl tag:
13866 <pre><code>
13867         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
13868         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
13869         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
13870         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
13871   
13872 </code></pre>
13873  *      
13874  */
13875 Roo.DomTemplate = function()
13876 {
13877      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13878      if (this.html) {
13879         this.compile();
13880      }
13881 };
13882
13883
13884 Roo.extend(Roo.DomTemplate, Roo.Template, {
13885     /**
13886      * id counter for sub templates.
13887      */
13888     id : 0,
13889     /**
13890      * flag to indicate if dom parser is inside a pre,
13891      * it will strip whitespace if not.
13892      */
13893     inPre : false,
13894     
13895     /**
13896      * The various sub templates
13897      */
13898     tpls : false,
13899     
13900     
13901     
13902     /**
13903      *
13904      * basic tag replacing syntax
13905      * WORD:WORD()
13906      *
13907      * // you can fake an object call by doing this
13908      *  x.t:(test,tesT) 
13909      * 
13910      */
13911     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13912     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13913     
13914     iterChild : function (node, method) {
13915         
13916         var oldPre = this.inPre;
13917         if (node.tagName == 'PRE') {
13918             this.inPre = true;
13919         }
13920         for( var i = 0; i < node.childNodes.length; i++) {
13921             method.call(this, node.childNodes[i]);
13922         }
13923         this.inPre = oldPre;
13924     },
13925     
13926     
13927     
13928     /**
13929      * compile the template
13930      *
13931      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13932      *
13933      */
13934     compile: function()
13935     {
13936         var s = this.html;
13937         
13938         // covert the html into DOM...
13939         var doc = false;
13940         var div =false;
13941         try {
13942             doc = document.implementation.createHTMLDocument("");
13943             doc.documentElement.innerHTML =   this.html  ;
13944             div = doc.documentElement;
13945         } catch (e) {
13946             // old IE... - nasty -- it causes all sorts of issues.. with
13947             // images getting pulled from server..
13948             div = document.createElement('div');
13949             div.innerHTML = this.html;
13950         }
13951         //doc.documentElement.innerHTML = htmlBody
13952          
13953         
13954         
13955         this.tpls = [];
13956         var _t = this;
13957         this.iterChild(div, function(n) {_t.compileNode(n, true); });
13958         
13959         var tpls = this.tpls;
13960         
13961         // create a top level template from the snippet..
13962         
13963         //Roo.log(div.innerHTML);
13964         
13965         var tpl = {
13966             uid : 'master',
13967             id : this.id++,
13968             attr : false,
13969             value : false,
13970             body : div.innerHTML,
13971             
13972             forCall : false,
13973             execCall : false,
13974             dom : div,
13975             isTop : true
13976             
13977         };
13978         tpls.unshift(tpl);
13979         
13980         
13981         // compile them...
13982         this.tpls = [];
13983         Roo.each(tpls, function(tp){
13984             this.compileTpl(tp);
13985             this.tpls[tp.id] = tp;
13986         }, this);
13987         
13988         this.master = tpls[0];
13989         return this;
13990         
13991         
13992     },
13993     
13994     compileNode : function(node, istop) {
13995         // test for
13996         //Roo.log(node);
13997         
13998         
13999         // skip anything not a tag..
14000         if (node.nodeType != 1) {
14001             if (node.nodeType == 3 && !this.inPre) {
14002                 // reduce white space..
14003                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
14004                 
14005             }
14006             return;
14007         }
14008         
14009         var tpl = {
14010             uid : false,
14011             id : false,
14012             attr : false,
14013             value : false,
14014             body : '',
14015             
14016             forCall : false,
14017             execCall : false,
14018             dom : false,
14019             isTop : istop
14020             
14021             
14022         };
14023         
14024         
14025         switch(true) {
14026             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
14027             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
14028             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
14029             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
14030             // no default..
14031         }
14032         
14033         
14034         if (!tpl.attr) {
14035             // just itterate children..
14036             this.iterChild(node,this.compileNode);
14037             return;
14038         }
14039         tpl.uid = this.id++;
14040         tpl.value = node.getAttribute('roo-' +  tpl.attr);
14041         node.removeAttribute('roo-'+ tpl.attr);
14042         if (tpl.attr != 'name') {
14043             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
14044             node.parentNode.replaceChild(placeholder,  node);
14045         } else {
14046             
14047             var placeholder =  document.createElement('span');
14048             placeholder.className = 'roo-tpl-' + tpl.value;
14049             node.parentNode.replaceChild(placeholder,  node);
14050         }
14051         
14052         // parent now sees '{domtplXXXX}
14053         this.iterChild(node,this.compileNode);
14054         
14055         // we should now have node body...
14056         var div = document.createElement('div');
14057         div.appendChild(node);
14058         tpl.dom = node;
14059         // this has the unfortunate side effect of converting tagged attributes
14060         // eg. href="{...}" into %7C...%7D
14061         // this has been fixed by searching for those combo's although it's a bit hacky..
14062         
14063         
14064         tpl.body = div.innerHTML;
14065         
14066         
14067          
14068         tpl.id = tpl.uid;
14069         switch(tpl.attr) {
14070             case 'for' :
14071                 switch (tpl.value) {
14072                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
14073                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
14074                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
14075                 }
14076                 break;
14077             
14078             case 'exec':
14079                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14080                 break;
14081             
14082             case 'if':     
14083                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
14084                 break;
14085             
14086             case 'name':
14087                 tpl.id  = tpl.value; // replace non characters???
14088                 break;
14089             
14090         }
14091         
14092         
14093         this.tpls.push(tpl);
14094         
14095         
14096         
14097     },
14098     
14099     
14100     
14101     
14102     /**
14103      * Compile a segment of the template into a 'sub-template'
14104      *
14105      * 
14106      * 
14107      *
14108      */
14109     compileTpl : function(tpl)
14110     {
14111         var fm = Roo.util.Format;
14112         var useF = this.disableFormats !== true;
14113         
14114         var sep = Roo.isGecko ? "+\n" : ",\n";
14115         
14116         var undef = function(str) {
14117             Roo.debug && Roo.log("Property not found :"  + str);
14118             return '';
14119         };
14120           
14121         //Roo.log(tpl.body);
14122         
14123         
14124         
14125         var fn = function(m, lbrace, name, format, args)
14126         {
14127             //Roo.log("ARGS");
14128             //Roo.log(arguments);
14129             args = args ? args.replace(/\\'/g,"'") : args;
14130             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
14131             if (typeof(format) == 'undefined') {
14132                 format =  'htmlEncode'; 
14133             }
14134             if (format == 'raw' ) {
14135                 format = false;
14136             }
14137             
14138             if(name.substr(0, 6) == 'domtpl'){
14139                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
14140             }
14141             
14142             // build an array of options to determine if value is undefined..
14143             
14144             // basically get 'xxxx.yyyy' then do
14145             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
14146             //    (function () { Roo.log("Property not found"); return ''; })() :
14147             //    ......
14148             
14149             var udef_ar = [];
14150             var lookfor = '';
14151             Roo.each(name.split('.'), function(st) {
14152                 lookfor += (lookfor.length ? '.': '') + st;
14153                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
14154             });
14155             
14156             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
14157             
14158             
14159             if(format && useF){
14160                 
14161                 args = args ? ',' + args : "";
14162                  
14163                 if(format.substr(0, 5) != "this."){
14164                     format = "fm." + format + '(';
14165                 }else{
14166                     format = 'this.call("'+ format.substr(5) + '", ';
14167                     args = ", values";
14168                 }
14169                 
14170                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
14171             }
14172              
14173             if (args && args.length) {
14174                 // called with xxyx.yuu:(test,test)
14175                 // change to ()
14176                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
14177             }
14178             // raw.. - :raw modifier..
14179             return "'"+ sep + udef_st  + name + ")"+sep+"'";
14180             
14181         };
14182         var body;
14183         // branched to use + in gecko and [].join() in others
14184         if(Roo.isGecko){
14185             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
14186                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
14187                     "';};};";
14188         }else{
14189             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
14190             body.push(tpl.body.replace(/(\r\n|\n)/g,
14191                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
14192             body.push("'].join('');};};");
14193             body = body.join('');
14194         }
14195         
14196         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
14197        
14198         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
14199         eval(body);
14200         
14201         return this;
14202     },
14203      
14204     /**
14205      * same as applyTemplate, except it's done to one of the subTemplates
14206      * when using named templates, you can do:
14207      *
14208      * var str = pl.applySubTemplate('your-name', values);
14209      *
14210      * 
14211      * @param {Number} id of the template
14212      * @param {Object} values to apply to template
14213      * @param {Object} parent (normaly the instance of this object)
14214      */
14215     applySubTemplate : function(id, values, parent)
14216     {
14217         
14218         
14219         var t = this.tpls[id];
14220         
14221         
14222         try { 
14223             if(t.ifCall && !t.ifCall.call(this, values, parent)){
14224                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
14225                 return '';
14226             }
14227         } catch(e) {
14228             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
14229             Roo.log(values);
14230           
14231             return '';
14232         }
14233         try { 
14234             
14235             if(t.execCall && t.execCall.call(this, values, parent)){
14236                 return '';
14237             }
14238         } catch(e) {
14239             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14240             Roo.log(values);
14241             return '';
14242         }
14243         
14244         try {
14245             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
14246             parent = t.target ? values : parent;
14247             if(t.forCall && vs instanceof Array){
14248                 var buf = [];
14249                 for(var i = 0, len = vs.length; i < len; i++){
14250                     try {
14251                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
14252                     } catch (e) {
14253                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14254                         Roo.log(e.body);
14255                         //Roo.log(t.compiled);
14256                         Roo.log(vs[i]);
14257                     }   
14258                 }
14259                 return buf.join('');
14260             }
14261         } catch (e) {
14262             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
14263             Roo.log(values);
14264             return '';
14265         }
14266         try {
14267             return t.compiled.call(this, vs, parent);
14268         } catch (e) {
14269             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
14270             Roo.log(e.body);
14271             //Roo.log(t.compiled);
14272             Roo.log(values);
14273             return '';
14274         }
14275     },
14276
14277    
14278
14279     applyTemplate : function(values){
14280         return this.master.compiled.call(this, values, {});
14281         //var s = this.subs;
14282     },
14283
14284     apply : function(){
14285         return this.applyTemplate.apply(this, arguments);
14286     }
14287
14288  });
14289
14290 Roo.DomTemplate.from = function(el){
14291     el = Roo.getDom(el);
14292     return new Roo.Domtemplate(el.value || el.innerHTML);
14293 };/*
14294  * Based on:
14295  * Ext JS Library 1.1.1
14296  * Copyright(c) 2006-2007, Ext JS, LLC.
14297  *
14298  * Originally Released Under LGPL - original licence link has changed is not relivant.
14299  *
14300  * Fork - LGPL
14301  * <script type="text/javascript">
14302  */
14303
14304 /**
14305  * @class Roo.util.DelayedTask
14306  * Provides a convenient method of performing setTimeout where a new
14307  * timeout cancels the old timeout. An example would be performing validation on a keypress.
14308  * You can use this class to buffer
14309  * the keypress events for a certain number of milliseconds, and perform only if they stop
14310  * for that amount of time.
14311  * @constructor The parameters to this constructor serve as defaults and are not required.
14312  * @param {Function} fn (optional) The default function to timeout
14313  * @param {Object} scope (optional) The default scope of that timeout
14314  * @param {Array} args (optional) The default Array of arguments
14315  */
14316 Roo.util.DelayedTask = function(fn, scope, args){
14317     var id = null, d, t;
14318
14319     var call = function(){
14320         var now = new Date().getTime();
14321         if(now - t >= d){
14322             clearInterval(id);
14323             id = null;
14324             fn.apply(scope, args || []);
14325         }
14326     };
14327     /**
14328      * Cancels any pending timeout and queues a new one
14329      * @param {Number} delay The milliseconds to delay
14330      * @param {Function} newFn (optional) Overrides function passed to constructor
14331      * @param {Object} newScope (optional) Overrides scope passed to constructor
14332      * @param {Array} newArgs (optional) Overrides args passed to constructor
14333      */
14334     this.delay = function(delay, newFn, newScope, newArgs){
14335         if(id && delay != d){
14336             this.cancel();
14337         }
14338         d = delay;
14339         t = new Date().getTime();
14340         fn = newFn || fn;
14341         scope = newScope || scope;
14342         args = newArgs || args;
14343         if(!id){
14344             id = setInterval(call, d);
14345         }
14346     };
14347
14348     /**
14349      * Cancel the last queued timeout
14350      */
14351     this.cancel = function(){
14352         if(id){
14353             clearInterval(id);
14354             id = null;
14355         }
14356     };
14357 };/*
14358  * Based on:
14359  * Ext JS Library 1.1.1
14360  * Copyright(c) 2006-2007, Ext JS, LLC.
14361  *
14362  * Originally Released Under LGPL - original licence link has changed is not relivant.
14363  *
14364  * Fork - LGPL
14365  * <script type="text/javascript">
14366  */
14367 /**
14368  * @class Roo.util.TaskRunner
14369  * Manage background tasks - not sure why this is better that setInterval?
14370  * @static
14371  *
14372  */
14373  
14374 Roo.util.TaskRunner = function(interval){
14375     interval = interval || 10;
14376     var tasks = [], removeQueue = [];
14377     var id = 0;
14378     var running = false;
14379
14380     var stopThread = function(){
14381         running = false;
14382         clearInterval(id);
14383         id = 0;
14384     };
14385
14386     var startThread = function(){
14387         if(!running){
14388             running = true;
14389             id = setInterval(runTasks, interval);
14390         }
14391     };
14392
14393     var removeTask = function(task){
14394         removeQueue.push(task);
14395         if(task.onStop){
14396             task.onStop();
14397         }
14398     };
14399
14400     var runTasks = function(){
14401         if(removeQueue.length > 0){
14402             for(var i = 0, len = removeQueue.length; i < len; i++){
14403                 tasks.remove(removeQueue[i]);
14404             }
14405             removeQueue = [];
14406             if(tasks.length < 1){
14407                 stopThread();
14408                 return;
14409             }
14410         }
14411         var now = new Date().getTime();
14412         for(var i = 0, len = tasks.length; i < len; ++i){
14413             var t = tasks[i];
14414             var itime = now - t.taskRunTime;
14415             if(t.interval <= itime){
14416                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
14417                 t.taskRunTime = now;
14418                 if(rt === false || t.taskRunCount === t.repeat){
14419                     removeTask(t);
14420                     return;
14421                 }
14422             }
14423             if(t.duration && t.duration <= (now - t.taskStartTime)){
14424                 removeTask(t);
14425             }
14426         }
14427     };
14428
14429     /**
14430      * Queues a new task.
14431      * @param {Object} task
14432      *
14433      * Task property : interval = how frequent to run.
14434      * Task object should implement
14435      * function run()
14436      * Task object may implement
14437      * function onStop()
14438      */
14439     this.start = function(task){
14440         tasks.push(task);
14441         task.taskStartTime = new Date().getTime();
14442         task.taskRunTime = 0;
14443         task.taskRunCount = 0;
14444         startThread();
14445         return task;
14446     };
14447     /**
14448      * Stop  new task.
14449      * @param {Object} task
14450      */
14451     this.stop = function(task){
14452         removeTask(task);
14453         return task;
14454     };
14455     /**
14456      * Stop all Tasks
14457      */
14458     this.stopAll = function(){
14459         stopThread();
14460         for(var i = 0, len = tasks.length; i < len; i++){
14461             if(tasks[i].onStop){
14462                 tasks[i].onStop();
14463             }
14464         }
14465         tasks = [];
14466         removeQueue = [];
14467     };
14468 };
14469
14470 Roo.TaskMgr = new Roo.util.TaskRunner();/*
14471  * Based on:
14472  * Ext JS Library 1.1.1
14473  * Copyright(c) 2006-2007, Ext JS, LLC.
14474  *
14475  * Originally Released Under LGPL - original licence link has changed is not relivant.
14476  *
14477  * Fork - LGPL
14478  * <script type="text/javascript">
14479  */
14480
14481  
14482 /**
14483  * @class Roo.util.MixedCollection
14484  * @extends Roo.util.Observable
14485  * A Collection class that maintains both numeric indexes and keys and exposes events.
14486  * @constructor
14487  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
14488  * collection (defaults to false)
14489  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
14490  * and return the key value for that item.  This is used when available to look up the key on items that
14491  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
14492  * equivalent to providing an implementation for the {@link #getKey} method.
14493  */
14494 Roo.util.MixedCollection = function(allowFunctions, keyFn){
14495     this.items = [];
14496     this.map = {};
14497     this.keys = [];
14498     this.length = 0;
14499     this.addEvents({
14500         /**
14501          * @event clear
14502          * Fires when the collection is cleared.
14503          */
14504         "clear" : true,
14505         /**
14506          * @event add
14507          * Fires when an item is added to the collection.
14508          * @param {Number} index The index at which the item was added.
14509          * @param {Object} o The item added.
14510          * @param {String} key The key associated with the added item.
14511          */
14512         "add" : true,
14513         /**
14514          * @event replace
14515          * Fires when an item is replaced in the collection.
14516          * @param {String} key he key associated with the new added.
14517          * @param {Object} old The item being replaced.
14518          * @param {Object} new The new item.
14519          */
14520         "replace" : true,
14521         /**
14522          * @event remove
14523          * Fires when an item is removed from the collection.
14524          * @param {Object} o The item being removed.
14525          * @param {String} key (optional) The key associated with the removed item.
14526          */
14527         "remove" : true,
14528         "sort" : true
14529     });
14530     this.allowFunctions = allowFunctions === true;
14531     if(keyFn){
14532         this.getKey = keyFn;
14533     }
14534     Roo.util.MixedCollection.superclass.constructor.call(this);
14535 };
14536
14537 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14538     allowFunctions : false,
14539     
14540 /**
14541  * Adds an item to the collection.
14542  * @param {String} key The key to associate with the item
14543  * @param {Object} o The item to add.
14544  * @return {Object} The item added.
14545  */
14546     add : function(key, o){
14547         if(arguments.length == 1){
14548             o = arguments[0];
14549             key = this.getKey(o);
14550         }
14551         if(typeof key == "undefined" || key === null){
14552             this.length++;
14553             this.items.push(o);
14554             this.keys.push(null);
14555         }else{
14556             var old = this.map[key];
14557             if(old){
14558                 return this.replace(key, o);
14559             }
14560             this.length++;
14561             this.items.push(o);
14562             this.map[key] = o;
14563             this.keys.push(key);
14564         }
14565         this.fireEvent("add", this.length-1, o, key);
14566         return o;
14567     },
14568        
14569 /**
14570   * MixedCollection has a generic way to fetch keys if you implement getKey.
14571 <pre><code>
14572 // normal way
14573 var mc = new Roo.util.MixedCollection();
14574 mc.add(someEl.dom.id, someEl);
14575 mc.add(otherEl.dom.id, otherEl);
14576 //and so on
14577
14578 // using getKey
14579 var mc = new Roo.util.MixedCollection();
14580 mc.getKey = function(el){
14581    return el.dom.id;
14582 };
14583 mc.add(someEl);
14584 mc.add(otherEl);
14585
14586 // or via the constructor
14587 var mc = new Roo.util.MixedCollection(false, function(el){
14588    return el.dom.id;
14589 });
14590 mc.add(someEl);
14591 mc.add(otherEl);
14592 </code></pre>
14593  * @param o {Object} The item for which to find the key.
14594  * @return {Object} The key for the passed item.
14595  */
14596     getKey : function(o){
14597          return o.id; 
14598     },
14599    
14600 /**
14601  * Replaces an item in the collection.
14602  * @param {String} key The key associated with the item to replace, or the item to replace.
14603  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14604  * @return {Object}  The new item.
14605  */
14606     replace : function(key, o){
14607         if(arguments.length == 1){
14608             o = arguments[0];
14609             key = this.getKey(o);
14610         }
14611         var old = this.item(key);
14612         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14613              return this.add(key, o);
14614         }
14615         var index = this.indexOfKey(key);
14616         this.items[index] = o;
14617         this.map[key] = o;
14618         this.fireEvent("replace", key, old, o);
14619         return o;
14620     },
14621    
14622 /**
14623  * Adds all elements of an Array or an Object to the collection.
14624  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14625  * an Array of values, each of which are added to the collection.
14626  */
14627     addAll : function(objs){
14628         if(arguments.length > 1 || objs instanceof Array){
14629             var args = arguments.length > 1 ? arguments : objs;
14630             for(var i = 0, len = args.length; i < len; i++){
14631                 this.add(args[i]);
14632             }
14633         }else{
14634             for(var key in objs){
14635                 if(this.allowFunctions || typeof objs[key] != "function"){
14636                     this.add(key, objs[key]);
14637                 }
14638             }
14639         }
14640     },
14641    
14642 /**
14643  * Executes the specified function once for every item in the collection, passing each
14644  * item as the first and only parameter. returning false from the function will stop the iteration.
14645  * @param {Function} fn The function to execute for each item.
14646  * @param {Object} scope (optional) The scope in which to execute the function.
14647  */
14648     each : function(fn, scope){
14649         var items = [].concat(this.items); // each safe for removal
14650         for(var i = 0, len = items.length; i < len; i++){
14651             if(fn.call(scope || items[i], items[i], i, len) === false){
14652                 break;
14653             }
14654         }
14655     },
14656    
14657 /**
14658  * Executes the specified function once for every key in the collection, passing each
14659  * key, and its associated item as the first two parameters.
14660  * @param {Function} fn The function to execute for each item.
14661  * @param {Object} scope (optional) The scope in which to execute the function.
14662  */
14663     eachKey : function(fn, scope){
14664         for(var i = 0, len = this.keys.length; i < len; i++){
14665             fn.call(scope || window, this.keys[i], this.items[i], i, len);
14666         }
14667     },
14668    
14669 /**
14670  * Returns the first item in the collection which elicits a true return value from the
14671  * passed selection function.
14672  * @param {Function} fn The selection function to execute for each item.
14673  * @param {Object} scope (optional) The scope in which to execute the function.
14674  * @return {Object} The first item in the collection which returned true from the selection function.
14675  */
14676     find : function(fn, scope){
14677         for(var i = 0, len = this.items.length; i < len; i++){
14678             if(fn.call(scope || window, this.items[i], this.keys[i])){
14679                 return this.items[i];
14680             }
14681         }
14682         return null;
14683     },
14684    
14685 /**
14686  * Inserts an item at the specified index in the collection.
14687  * @param {Number} index The index to insert the item at.
14688  * @param {String} key The key to associate with the new item, or the item itself.
14689  * @param {Object} o  (optional) If the second parameter was a key, the new item.
14690  * @return {Object} The item inserted.
14691  */
14692     insert : function(index, key, o){
14693         if(arguments.length == 2){
14694             o = arguments[1];
14695             key = this.getKey(o);
14696         }
14697         if(index >= this.length){
14698             return this.add(key, o);
14699         }
14700         this.length++;
14701         this.items.splice(index, 0, o);
14702         if(typeof key != "undefined" && key != null){
14703             this.map[key] = o;
14704         }
14705         this.keys.splice(index, 0, key);
14706         this.fireEvent("add", index, o, key);
14707         return o;
14708     },
14709    
14710 /**
14711  * Removed an item from the collection.
14712  * @param {Object} o The item to remove.
14713  * @return {Object} The item removed.
14714  */
14715     remove : function(o){
14716         return this.removeAt(this.indexOf(o));
14717     },
14718    
14719 /**
14720  * Remove an item from a specified index in the collection.
14721  * @param {Number} index The index within the collection of the item to remove.
14722  */
14723     removeAt : function(index){
14724         if(index < this.length && index >= 0){
14725             this.length--;
14726             var o = this.items[index];
14727             this.items.splice(index, 1);
14728             var key = this.keys[index];
14729             if(typeof key != "undefined"){
14730                 delete this.map[key];
14731             }
14732             this.keys.splice(index, 1);
14733             this.fireEvent("remove", o, key);
14734         }
14735     },
14736    
14737 /**
14738  * Removed an item associated with the passed key fom the collection.
14739  * @param {String} key The key of the item to remove.
14740  */
14741     removeKey : function(key){
14742         return this.removeAt(this.indexOfKey(key));
14743     },
14744    
14745 /**
14746  * Returns the number of items in the collection.
14747  * @return {Number} the number of items in the collection.
14748  */
14749     getCount : function(){
14750         return this.length; 
14751     },
14752    
14753 /**
14754  * Returns index within the collection of the passed Object.
14755  * @param {Object} o The item to find the index of.
14756  * @return {Number} index of the item.
14757  */
14758     indexOf : function(o){
14759         if(!this.items.indexOf){
14760             for(var i = 0, len = this.items.length; i < len; i++){
14761                 if(this.items[i] == o) {
14762                     return i;
14763                 }
14764             }
14765             return -1;
14766         }else{
14767             return this.items.indexOf(o);
14768         }
14769     },
14770    
14771 /**
14772  * Returns index within the collection of the passed key.
14773  * @param {String} key The key to find the index of.
14774  * @return {Number} index of the key.
14775  */
14776     indexOfKey : function(key){
14777         if(!this.keys.indexOf){
14778             for(var i = 0, len = this.keys.length; i < len; i++){
14779                 if(this.keys[i] == key) {
14780                     return i;
14781                 }
14782             }
14783             return -1;
14784         }else{
14785             return this.keys.indexOf(key);
14786         }
14787     },
14788    
14789 /**
14790  * Returns the item associated with the passed key OR index. Key has priority over index.
14791  * @param {String/Number} key The key or index of the item.
14792  * @return {Object} The item associated with the passed key.
14793  */
14794     item : function(key){
14795         if (key === 'length') {
14796             return null;
14797         }
14798         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14799         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14800     },
14801     
14802 /**
14803  * Returns the item at the specified index.
14804  * @param {Number} index The index of the item.
14805  * @return {Object}
14806  */
14807     itemAt : function(index){
14808         return this.items[index];
14809     },
14810     
14811 /**
14812  * Returns the item associated with the passed key.
14813  * @param {String/Number} key The key of the item.
14814  * @return {Object} The item associated with the passed key.
14815  */
14816     key : function(key){
14817         return this.map[key];
14818     },
14819    
14820 /**
14821  * Returns true if the collection contains the passed Object as an item.
14822  * @param {Object} o  The Object to look for in the collection.
14823  * @return {Boolean} True if the collection contains the Object as an item.
14824  */
14825     contains : function(o){
14826         return this.indexOf(o) != -1;
14827     },
14828    
14829 /**
14830  * Returns true if the collection contains the passed Object as a key.
14831  * @param {String} key The key to look for in the collection.
14832  * @return {Boolean} True if the collection contains the Object as a key.
14833  */
14834     containsKey : function(key){
14835         return typeof this.map[key] != "undefined";
14836     },
14837    
14838 /**
14839  * Removes all items from the collection.
14840  */
14841     clear : function(){
14842         this.length = 0;
14843         this.items = [];
14844         this.keys = [];
14845         this.map = {};
14846         this.fireEvent("clear");
14847     },
14848    
14849 /**
14850  * Returns the first item in the collection.
14851  * @return {Object} the first item in the collection..
14852  */
14853     first : function(){
14854         return this.items[0]; 
14855     },
14856    
14857 /**
14858  * Returns the last item in the collection.
14859  * @return {Object} the last item in the collection..
14860  */
14861     last : function(){
14862         return this.items[this.length-1];   
14863     },
14864     
14865     _sort : function(property, dir, fn){
14866         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14867         fn = fn || function(a, b){
14868             return a-b;
14869         };
14870         var c = [], k = this.keys, items = this.items;
14871         for(var i = 0, len = items.length; i < len; i++){
14872             c[c.length] = {key: k[i], value: items[i], index: i};
14873         }
14874         c.sort(function(a, b){
14875             var v = fn(a[property], b[property]) * dsc;
14876             if(v == 0){
14877                 v = (a.index < b.index ? -1 : 1);
14878             }
14879             return v;
14880         });
14881         for(var i = 0, len = c.length; i < len; i++){
14882             items[i] = c[i].value;
14883             k[i] = c[i].key;
14884         }
14885         this.fireEvent("sort", this);
14886     },
14887     
14888     /**
14889      * Sorts this collection with the passed comparison function
14890      * @param {String} direction (optional) "ASC" or "DESC"
14891      * @param {Function} fn (optional) comparison function
14892      */
14893     sort : function(dir, fn){
14894         this._sort("value", dir, fn);
14895     },
14896     
14897     /**
14898      * Sorts this collection by keys
14899      * @param {String} direction (optional) "ASC" or "DESC"
14900      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14901      */
14902     keySort : function(dir, fn){
14903         this._sort("key", dir, fn || function(a, b){
14904             return String(a).toUpperCase()-String(b).toUpperCase();
14905         });
14906     },
14907     
14908     /**
14909      * Returns a range of items in this collection
14910      * @param {Number} startIndex (optional) defaults to 0
14911      * @param {Number} endIndex (optional) default to the last item
14912      * @return {Array} An array of items
14913      */
14914     getRange : function(start, end){
14915         var items = this.items;
14916         if(items.length < 1){
14917             return [];
14918         }
14919         start = start || 0;
14920         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14921         var r = [];
14922         if(start <= end){
14923             for(var i = start; i <= end; i++) {
14924                     r[r.length] = items[i];
14925             }
14926         }else{
14927             for(var i = start; i >= end; i--) {
14928                     r[r.length] = items[i];
14929             }
14930         }
14931         return r;
14932     },
14933         
14934     /**
14935      * Filter the <i>objects</i> in this collection by a specific property. 
14936      * Returns a new collection that has been filtered.
14937      * @param {String} property A property on your objects
14938      * @param {String/RegExp} value Either string that the property values 
14939      * should start with or a RegExp to test against the property
14940      * @return {MixedCollection} The new filtered collection
14941      */
14942     filter : function(property, value){
14943         if(!value.exec){ // not a regex
14944             value = String(value);
14945             if(value.length == 0){
14946                 return this.clone();
14947             }
14948             value = new RegExp("^" + Roo.escapeRe(value), "i");
14949         }
14950         return this.filterBy(function(o){
14951             return o && value.test(o[property]);
14952         });
14953         },
14954     
14955     /**
14956      * Filter by a function. * Returns a new collection that has been filtered.
14957      * The passed function will be called with each 
14958      * object in the collection. If the function returns true, the value is included 
14959      * otherwise it is filtered.
14960      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14961      * @param {Object} scope (optional) The scope of the function (defaults to this) 
14962      * @return {MixedCollection} The new filtered collection
14963      */
14964     filterBy : function(fn, scope){
14965         var r = new Roo.util.MixedCollection();
14966         r.getKey = this.getKey;
14967         var k = this.keys, it = this.items;
14968         for(var i = 0, len = it.length; i < len; i++){
14969             if(fn.call(scope||this, it[i], k[i])){
14970                                 r.add(k[i], it[i]);
14971                         }
14972         }
14973         return r;
14974     },
14975     
14976     /**
14977      * Creates a duplicate of this collection
14978      * @return {MixedCollection}
14979      */
14980     clone : function(){
14981         var r = new Roo.util.MixedCollection();
14982         var k = this.keys, it = this.items;
14983         for(var i = 0, len = it.length; i < len; i++){
14984             r.add(k[i], it[i]);
14985         }
14986         r.getKey = this.getKey;
14987         return r;
14988     }
14989 });
14990 /**
14991  * Returns the item associated with the passed key or index.
14992  * @method
14993  * @param {String/Number} key The key or index of the item.
14994  * @return {Object} The item associated with the passed key.
14995  */
14996 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14997  * Based on:
14998  * Ext JS Library 1.1.1
14999  * Copyright(c) 2006-2007, Ext JS, LLC.
15000  *
15001  * Originally Released Under LGPL - original licence link has changed is not relivant.
15002  *
15003  * Fork - LGPL
15004  * <script type="text/javascript">
15005  */
15006 /**
15007  * @class Roo.util.JSON
15008  * Modified version of Douglas Crockford"s json.js that doesn"t
15009  * mess with the Object prototype 
15010  * http://www.json.org/js.html
15011  * @static
15012  */
15013 Roo.util.JSON = new (function(){
15014     var useHasOwn = {}.hasOwnProperty ? true : false;
15015     
15016     // crashes Safari in some instances
15017     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
15018     
15019     var pad = function(n) {
15020         return n < 10 ? "0" + n : n;
15021     };
15022     
15023     var m = {
15024         "\b": '\\b',
15025         "\t": '\\t',
15026         "\n": '\\n',
15027         "\f": '\\f',
15028         "\r": '\\r',
15029         '"' : '\\"',
15030         "\\": '\\\\'
15031     };
15032
15033     var encodeString = function(s){
15034         if (/["\\\x00-\x1f]/.test(s)) {
15035             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
15036                 var c = m[b];
15037                 if(c){
15038                     return c;
15039                 }
15040                 c = b.charCodeAt();
15041                 return "\\u00" +
15042                     Math.floor(c / 16).toString(16) +
15043                     (c % 16).toString(16);
15044             }) + '"';
15045         }
15046         return '"' + s + '"';
15047     };
15048     
15049     var encodeArray = function(o){
15050         var a = ["["], b, i, l = o.length, v;
15051             for (i = 0; i < l; i += 1) {
15052                 v = o[i];
15053                 switch (typeof v) {
15054                     case "undefined":
15055                     case "function":
15056                     case "unknown":
15057                         break;
15058                     default:
15059                         if (b) {
15060                             a.push(',');
15061                         }
15062                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
15063                         b = true;
15064                 }
15065             }
15066             a.push("]");
15067             return a.join("");
15068     };
15069     
15070     var encodeDate = function(o){
15071         return '"' + o.getFullYear() + "-" +
15072                 pad(o.getMonth() + 1) + "-" +
15073                 pad(o.getDate()) + "T" +
15074                 pad(o.getHours()) + ":" +
15075                 pad(o.getMinutes()) + ":" +
15076                 pad(o.getSeconds()) + '"';
15077     };
15078     
15079     /**
15080      * Encodes an Object, Array or other value
15081      * @param {Mixed} o The variable to encode
15082      * @return {String} The JSON string
15083      */
15084     this.encode = function(o)
15085     {
15086         // should this be extended to fully wrap stringify..
15087         
15088         if(typeof o == "undefined" || o === null){
15089             return "null";
15090         }else if(o instanceof Array){
15091             return encodeArray(o);
15092         }else if(o instanceof Date){
15093             return encodeDate(o);
15094         }else if(typeof o == "string"){
15095             return encodeString(o);
15096         }else if(typeof o == "number"){
15097             return isFinite(o) ? String(o) : "null";
15098         }else if(typeof o == "boolean"){
15099             return String(o);
15100         }else {
15101             var a = ["{"], b, i, v;
15102             for (i in o) {
15103                 if(!useHasOwn || o.hasOwnProperty(i)) {
15104                     v = o[i];
15105                     switch (typeof v) {
15106                     case "undefined":
15107                     case "function":
15108                     case "unknown":
15109                         break;
15110                     default:
15111                         if(b){
15112                             a.push(',');
15113                         }
15114                         a.push(this.encode(i), ":",
15115                                 v === null ? "null" : this.encode(v));
15116                         b = true;
15117                     }
15118                 }
15119             }
15120             a.push("}");
15121             return a.join("");
15122         }
15123     };
15124     
15125     /**
15126      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
15127      * @param {String} json The JSON string
15128      * @return {Object} The resulting object
15129      */
15130     this.decode = function(json){
15131         
15132         return  /** eval:var:json */ eval("(" + json + ')');
15133     };
15134 })();
15135 /** 
15136  * Shorthand for {@link Roo.util.JSON#encode}
15137  * @member Roo encode 
15138  * @method */
15139 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
15140 /** 
15141  * Shorthand for {@link Roo.util.JSON#decode}
15142  * @member Roo decode 
15143  * @method */
15144 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
15145 /*
15146  * Based on:
15147  * Ext JS Library 1.1.1
15148  * Copyright(c) 2006-2007, Ext JS, LLC.
15149  *
15150  * Originally Released Under LGPL - original licence link has changed is not relivant.
15151  *
15152  * Fork - LGPL
15153  * <script type="text/javascript">
15154  */
15155  
15156 /**
15157  * @class Roo.util.Format
15158  * Reusable data formatting functions
15159  * @static
15160  */
15161 Roo.util.Format = function(){
15162     var trimRe = /^\s+|\s+$/g;
15163     return {
15164         /**
15165          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
15166          * @param {String} value The string to truncate
15167          * @param {Number} length The maximum length to allow before truncating
15168          * @return {String} The converted text
15169          */
15170         ellipsis : function(value, len){
15171             if(value && value.length > len){
15172                 return value.substr(0, len-3)+"...";
15173             }
15174             return value;
15175         },
15176
15177         /**
15178          * Checks a reference and converts it to empty string if it is undefined
15179          * @param {Mixed} value Reference to check
15180          * @return {Mixed} Empty string if converted, otherwise the original value
15181          */
15182         undef : function(value){
15183             return typeof value != "undefined" ? value : "";
15184         },
15185
15186         /**
15187          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
15188          * @param {String} value The string to encode
15189          * @return {String} The encoded text
15190          */
15191         htmlEncode : function(value){
15192             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
15193         },
15194
15195         /**
15196          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
15197          * @param {String} value The string to decode
15198          * @return {String} The decoded text
15199          */
15200         htmlDecode : function(value){
15201             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
15202         },
15203
15204         /**
15205          * Trims any whitespace from either side of a string
15206          * @param {String} value The text to trim
15207          * @return {String} The trimmed text
15208          */
15209         trim : function(value){
15210             return String(value).replace(trimRe, "");
15211         },
15212
15213         /**
15214          * Returns a substring from within an original string
15215          * @param {String} value The original text
15216          * @param {Number} start The start index of the substring
15217          * @param {Number} length The length of the substring
15218          * @return {String} The substring
15219          */
15220         substr : function(value, start, length){
15221             return String(value).substr(start, length);
15222         },
15223
15224         /**
15225          * Converts a string to all lower case letters
15226          * @param {String} value The text to convert
15227          * @return {String} The converted text
15228          */
15229         lowercase : function(value){
15230             return String(value).toLowerCase();
15231         },
15232
15233         /**
15234          * Converts a string to all upper case letters
15235          * @param {String} value The text to convert
15236          * @return {String} The converted text
15237          */
15238         uppercase : function(value){
15239             return String(value).toUpperCase();
15240         },
15241
15242         /**
15243          * Converts the first character only of a string to upper case
15244          * @param {String} value The text to convert
15245          * @return {String} The converted text
15246          */
15247         capitalize : function(value){
15248             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
15249         },
15250
15251         // private
15252         call : function(value, fn){
15253             if(arguments.length > 2){
15254                 var args = Array.prototype.slice.call(arguments, 2);
15255                 args.unshift(value);
15256                  
15257                 return /** eval:var:value */  eval(fn).apply(window, args);
15258             }else{
15259                 /** eval:var:value */
15260                 return /** eval:var:value */ eval(fn).call(window, value);
15261             }
15262         },
15263
15264        
15265         /**
15266          * safer version of Math.toFixed..??/
15267          * @param {Number/String} value The numeric value to format
15268          * @param {Number/String} value Decimal places 
15269          * @return {String} The formatted currency string
15270          */
15271         toFixed : function(v, n)
15272         {
15273             // why not use to fixed - precision is buggered???
15274             if (!n) {
15275                 return Math.round(v-0);
15276             }
15277             var fact = Math.pow(10,n+1);
15278             v = (Math.round((v-0)*fact))/fact;
15279             var z = (''+fact).substring(2);
15280             if (v == Math.floor(v)) {
15281                 return Math.floor(v) + '.' + z;
15282             }
15283             
15284             // now just padd decimals..
15285             var ps = String(v).split('.');
15286             var fd = (ps[1] + z);
15287             var r = fd.substring(0,n); 
15288             var rm = fd.substring(n); 
15289             if (rm < 5) {
15290                 return ps[0] + '.' + r;
15291             }
15292             r*=1; // turn it into a number;
15293             r++;
15294             if (String(r).length != n) {
15295                 ps[0]*=1;
15296                 ps[0]++;
15297                 r = String(r).substring(1); // chop the end off.
15298             }
15299             
15300             return ps[0] + '.' + r;
15301              
15302         },
15303         
15304         /**
15305          * Format a number as US currency
15306          * @param {Number/String} value The numeric value to format
15307          * @return {String} The formatted currency string
15308          */
15309         usMoney : function(v){
15310             return '$' + Roo.util.Format.number(v);
15311         },
15312         
15313         /**
15314          * Format a number
15315          * eventually this should probably emulate php's number_format
15316          * @param {Number/String} value The numeric value to format
15317          * @param {Number} decimals number of decimal places
15318          * @param {String} delimiter for thousands (default comma)
15319          * @return {String} The formatted currency string
15320          */
15321         number : function(v, decimals, thousandsDelimiter)
15322         {
15323             // multiply and round.
15324             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
15325             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
15326             
15327             var mul = Math.pow(10, decimals);
15328             var zero = String(mul).substring(1);
15329             v = (Math.round((v-0)*mul))/mul;
15330             
15331             // if it's '0' number.. then
15332             
15333             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
15334             v = String(v);
15335             var ps = v.split('.');
15336             var whole = ps[0];
15337             
15338             var r = /(\d+)(\d{3})/;
15339             // add comma's
15340             
15341             if(thousandsDelimiter.length != 0) {
15342                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
15343             } 
15344             
15345             var sub = ps[1] ?
15346                     // has decimals..
15347                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
15348                     // does not have decimals
15349                     (decimals ? ('.' + zero) : '');
15350             
15351             
15352             return whole + sub ;
15353         },
15354         
15355         /**
15356          * Parse a value into a formatted date using the specified format pattern.
15357          * @param {Mixed} value The value to format
15358          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
15359          * @return {String} The formatted date string
15360          */
15361         date : function(v, format){
15362             if(!v){
15363                 return "";
15364             }
15365             if(!(v instanceof Date)){
15366                 v = new Date(Date.parse(v));
15367             }
15368             return v.dateFormat(format || Roo.util.Format.defaults.date);
15369         },
15370
15371         /**
15372          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
15373          * @param {String} format Any valid date format string
15374          * @return {Function} The date formatting function
15375          */
15376         dateRenderer : function(format){
15377             return function(v){
15378                 return Roo.util.Format.date(v, format);  
15379             };
15380         },
15381
15382         // private
15383         stripTagsRE : /<\/?[^>]+>/gi,
15384         
15385         /**
15386          * Strips all HTML tags
15387          * @param {Mixed} value The text from which to strip tags
15388          * @return {String} The stripped text
15389          */
15390         stripTags : function(v){
15391             return !v ? v : String(v).replace(this.stripTagsRE, "");
15392         },
15393         
15394         /**
15395          * Size in Mb,Gb etc.
15396          * @param {Number} value The number to be formated
15397          * @param {number} decimals how many decimal places
15398          * @return {String} the formated string
15399          */
15400         size : function(value, decimals)
15401         {
15402             var sizes = ['b', 'k', 'M', 'G', 'T'];
15403             if (value == 0) {
15404                 return 0;
15405             }
15406             var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
15407             return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
15408         }
15409         
15410         
15411         
15412     };
15413 }();
15414 Roo.util.Format.defaults = {
15415     date : 'd/M/Y'
15416 };/*
15417  * Based on:
15418  * Ext JS Library 1.1.1
15419  * Copyright(c) 2006-2007, Ext JS, LLC.
15420  *
15421  * Originally Released Under LGPL - original licence link has changed is not relivant.
15422  *
15423  * Fork - LGPL
15424  * <script type="text/javascript">
15425  */
15426
15427
15428  
15429
15430 /**
15431  * @class Roo.MasterTemplate
15432  * @extends Roo.Template
15433  * Provides a template that can have child templates. The syntax is:
15434 <pre><code>
15435 var t = new Roo.MasterTemplate(
15436         '&lt;select name="{name}"&gt;',
15437                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
15438         '&lt;/select&gt;'
15439 );
15440 t.add('options', {value: 'foo', text: 'bar'});
15441 // or you can add multiple child elements in one shot
15442 t.addAll('options', [
15443     {value: 'foo', text: 'bar'},
15444     {value: 'foo2', text: 'bar2'},
15445     {value: 'foo3', text: 'bar3'}
15446 ]);
15447 // then append, applying the master template values
15448 t.append('my-form', {name: 'my-select'});
15449 </code></pre>
15450 * A name attribute for the child template is not required if you have only one child
15451 * template or you want to refer to them by index.
15452  */
15453 Roo.MasterTemplate = function(){
15454     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
15455     this.originalHtml = this.html;
15456     var st = {};
15457     var m, re = this.subTemplateRe;
15458     re.lastIndex = 0;
15459     var subIndex = 0;
15460     while(m = re.exec(this.html)){
15461         var name = m[1], content = m[2];
15462         st[subIndex] = {
15463             name: name,
15464             index: subIndex,
15465             buffer: [],
15466             tpl : new Roo.Template(content)
15467         };
15468         if(name){
15469             st[name] = st[subIndex];
15470         }
15471         st[subIndex].tpl.compile();
15472         st[subIndex].tpl.call = this.call.createDelegate(this);
15473         subIndex++;
15474     }
15475     this.subCount = subIndex;
15476     this.subs = st;
15477 };
15478 Roo.extend(Roo.MasterTemplate, Roo.Template, {
15479     /**
15480     * The regular expression used to match sub templates
15481     * @type RegExp
15482     * @property
15483     */
15484     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
15485
15486     /**
15487      * Applies the passed values to a child template.
15488      * @param {String/Number} name (optional) The name or index of the child template
15489      * @param {Array/Object} values The values to be applied to the template
15490      * @return {MasterTemplate} this
15491      */
15492      add : function(name, values){
15493         if(arguments.length == 1){
15494             values = arguments[0];
15495             name = 0;
15496         }
15497         var s = this.subs[name];
15498         s.buffer[s.buffer.length] = s.tpl.apply(values);
15499         return this;
15500     },
15501
15502     /**
15503      * Applies all the passed values to a child template.
15504      * @param {String/Number} name (optional) The name or index of the child template
15505      * @param {Array} values The values to be applied to the template, this should be an array of objects.
15506      * @param {Boolean} reset (optional) True to reset the template first
15507      * @return {MasterTemplate} this
15508      */
15509     fill : function(name, values, reset){
15510         var a = arguments;
15511         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
15512             values = a[0];
15513             name = 0;
15514             reset = a[1];
15515         }
15516         if(reset){
15517             this.reset();
15518         }
15519         for(var i = 0, len = values.length; i < len; i++){
15520             this.add(name, values[i]);
15521         }
15522         return this;
15523     },
15524
15525     /**
15526      * Resets the template for reuse
15527      * @return {MasterTemplate} this
15528      */
15529      reset : function(){
15530         var s = this.subs;
15531         for(var i = 0; i < this.subCount; i++){
15532             s[i].buffer = [];
15533         }
15534         return this;
15535     },
15536
15537     applyTemplate : function(values){
15538         var s = this.subs;
15539         var replaceIndex = -1;
15540         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15541             return s[++replaceIndex].buffer.join("");
15542         });
15543         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15544     },
15545
15546     apply : function(){
15547         return this.applyTemplate.apply(this, arguments);
15548     },
15549
15550     compile : function(){return this;}
15551 });
15552
15553 /**
15554  * Alias for fill().
15555  * @method
15556  */
15557 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15558  /**
15559  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15560  * var tpl = Roo.MasterTemplate.from('element-id');
15561  * @param {String/HTMLElement} el
15562  * @param {Object} config
15563  * @static
15564  */
15565 Roo.MasterTemplate.from = function(el, config){
15566     el = Roo.getDom(el);
15567     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15568 };/*
15569  * Based on:
15570  * Ext JS Library 1.1.1
15571  * Copyright(c) 2006-2007, Ext JS, LLC.
15572  *
15573  * Originally Released Under LGPL - original licence link has changed is not relivant.
15574  *
15575  * Fork - LGPL
15576  * <script type="text/javascript">
15577  */
15578
15579  
15580 /**
15581  * @class Roo.util.CSS
15582  * Utility class for manipulating CSS rules
15583  * @static
15584
15585  */
15586 Roo.util.CSS = function(){
15587         var rules = null;
15588         var doc = document;
15589
15590     var camelRe = /(-[a-z])/gi;
15591     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15592
15593    return {
15594    /**
15595     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
15596     * tag and appended to the HEAD of the document.
15597     * @param {String|Object} cssText The text containing the css rules
15598     * @param {String} id An id to add to the stylesheet for later removal
15599     * @return {StyleSheet}
15600     */
15601     createStyleSheet : function(cssText, id){
15602         var ss;
15603         var head = doc.getElementsByTagName("head")[0];
15604         var nrules = doc.createElement("style");
15605         nrules.setAttribute("type", "text/css");
15606         if(id){
15607             nrules.setAttribute("id", id);
15608         }
15609         if (typeof(cssText) != 'string') {
15610             // support object maps..
15611             // not sure if this a good idea.. 
15612             // perhaps it should be merged with the general css handling
15613             // and handle js style props.
15614             var cssTextNew = [];
15615             for(var n in cssText) {
15616                 var citems = [];
15617                 for(var k in cssText[n]) {
15618                     citems.push( k + ' : ' +cssText[n][k] + ';' );
15619                 }
15620                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15621                 
15622             }
15623             cssText = cssTextNew.join("\n");
15624             
15625         }
15626        
15627        
15628        if(Roo.isIE){
15629            head.appendChild(nrules);
15630            ss = nrules.styleSheet;
15631            ss.cssText = cssText;
15632        }else{
15633            try{
15634                 nrules.appendChild(doc.createTextNode(cssText));
15635            }catch(e){
15636                nrules.cssText = cssText; 
15637            }
15638            head.appendChild(nrules);
15639            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15640        }
15641        this.cacheStyleSheet(ss);
15642        return ss;
15643    },
15644
15645    /**
15646     * Removes a style or link tag by id
15647     * @param {String} id The id of the tag
15648     */
15649    removeStyleSheet : function(id){
15650        var existing = doc.getElementById(id);
15651        if(existing){
15652            existing.parentNode.removeChild(existing);
15653        }
15654    },
15655
15656    /**
15657     * Dynamically swaps an existing stylesheet reference for a new one
15658     * @param {String} id The id of an existing link tag to remove
15659     * @param {String} url The href of the new stylesheet to include
15660     */
15661    swapStyleSheet : function(id, url){
15662        this.removeStyleSheet(id);
15663        var ss = doc.createElement("link");
15664        ss.setAttribute("rel", "stylesheet");
15665        ss.setAttribute("type", "text/css");
15666        ss.setAttribute("id", id);
15667        ss.setAttribute("href", url);
15668        doc.getElementsByTagName("head")[0].appendChild(ss);
15669    },
15670    
15671    /**
15672     * Refresh the rule cache if you have dynamically added stylesheets
15673     * @return {Object} An object (hash) of rules indexed by selector
15674     */
15675    refreshCache : function(){
15676        return this.getRules(true);
15677    },
15678
15679    // private
15680    cacheStyleSheet : function(stylesheet){
15681        if(!rules){
15682            rules = {};
15683        }
15684        try{// try catch for cross domain access issue
15685            var ssRules = stylesheet.cssRules || stylesheet.rules;
15686            for(var j = ssRules.length-1; j >= 0; --j){
15687                rules[ssRules[j].selectorText] = ssRules[j];
15688            }
15689        }catch(e){}
15690    },
15691    
15692    /**
15693     * Gets all css rules for the document
15694     * @param {Boolean} refreshCache true to refresh the internal cache
15695     * @return {Object} An object (hash) of rules indexed by selector
15696     */
15697    getRules : function(refreshCache){
15698                 if(rules == null || refreshCache){
15699                         rules = {};
15700                         var ds = doc.styleSheets;
15701                         for(var i =0, len = ds.length; i < len; i++){
15702                             try{
15703                         this.cacheStyleSheet(ds[i]);
15704                     }catch(e){} 
15705                 }
15706                 }
15707                 return rules;
15708         },
15709         
15710         /**
15711     * Gets an an individual CSS rule by selector(s)
15712     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15713     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15714     * @return {CSSRule} The CSS rule or null if one is not found
15715     */
15716    getRule : function(selector, refreshCache){
15717                 var rs = this.getRules(refreshCache);
15718                 if(!(selector instanceof Array)){
15719                     return rs[selector];
15720                 }
15721                 for(var i = 0; i < selector.length; i++){
15722                         if(rs[selector[i]]){
15723                                 return rs[selector[i]];
15724                         }
15725                 }
15726                 return null;
15727         },
15728         
15729         
15730         /**
15731     * Updates a rule property
15732     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15733     * @param {String} property The css property
15734     * @param {String} value The new value for the property
15735     * @return {Boolean} true If a rule was found and updated
15736     */
15737    updateRule : function(selector, property, value){
15738                 if(!(selector instanceof Array)){
15739                         var rule = this.getRule(selector);
15740                         if(rule){
15741                                 rule.style[property.replace(camelRe, camelFn)] = value;
15742                                 return true;
15743                         }
15744                 }else{
15745                         for(var i = 0; i < selector.length; i++){
15746                                 if(this.updateRule(selector[i], property, value)){
15747                                         return true;
15748                                 }
15749                         }
15750                 }
15751                 return false;
15752         }
15753    };   
15754 }();/*
15755  * Based on:
15756  * Ext JS Library 1.1.1
15757  * Copyright(c) 2006-2007, Ext JS, LLC.
15758  *
15759  * Originally Released Under LGPL - original licence link has changed is not relivant.
15760  *
15761  * Fork - LGPL
15762  * <script type="text/javascript">
15763  */
15764
15765  
15766
15767 /**
15768  * @class Roo.util.ClickRepeater
15769  * @extends Roo.util.Observable
15770  * 
15771  * A wrapper class which can be applied to any element. Fires a "click" event while the
15772  * mouse is pressed. The interval between firings may be specified in the config but
15773  * defaults to 10 milliseconds.
15774  * 
15775  * Optionally, a CSS class may be applied to the element during the time it is pressed.
15776  * 
15777  * @cfg {String/HTMLElement/Element} el The element to act as a button.
15778  * @cfg {Number} delay The initial delay before the repeating event begins firing.
15779  * Similar to an autorepeat key delay.
15780  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15781  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15782  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15783  *           "interval" and "delay" are ignored. "immediate" is honored.
15784  * @cfg {Boolean} preventDefault True to prevent the default click event
15785  * @cfg {Boolean} stopDefault True to stop the default click event
15786  * 
15787  * @history
15788  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
15789  *     2007-02-02 jvs Renamed to ClickRepeater
15790  *   2007-02-03 jvs Modifications for FF Mac and Safari 
15791  *
15792  *  @constructor
15793  * @param {String/HTMLElement/Element} el The element to listen on
15794  * @param {Object} config
15795  **/
15796 Roo.util.ClickRepeater = function(el, config)
15797 {
15798     this.el = Roo.get(el);
15799     this.el.unselectable();
15800
15801     Roo.apply(this, config);
15802
15803     this.addEvents({
15804     /**
15805      * @event mousedown
15806      * Fires when the mouse button is depressed.
15807      * @param {Roo.util.ClickRepeater} this
15808      */
15809         "mousedown" : true,
15810     /**
15811      * @event click
15812      * Fires on a specified interval during the time the element is pressed.
15813      * @param {Roo.util.ClickRepeater} this
15814      */
15815         "click" : true,
15816     /**
15817      * @event mouseup
15818      * Fires when the mouse key is released.
15819      * @param {Roo.util.ClickRepeater} this
15820      */
15821         "mouseup" : true
15822     });
15823
15824     this.el.on("mousedown", this.handleMouseDown, this);
15825     if(this.preventDefault || this.stopDefault){
15826         this.el.on("click", function(e){
15827             if(this.preventDefault){
15828                 e.preventDefault();
15829             }
15830             if(this.stopDefault){
15831                 e.stopEvent();
15832             }
15833         }, this);
15834     }
15835
15836     // allow inline handler
15837     if(this.handler){
15838         this.on("click", this.handler,  this.scope || this);
15839     }
15840
15841     Roo.util.ClickRepeater.superclass.constructor.call(this);
15842 };
15843
15844 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15845     interval : 20,
15846     delay: 250,
15847     preventDefault : true,
15848     stopDefault : false,
15849     timer : 0,
15850
15851     // private
15852     handleMouseDown : function(){
15853         clearTimeout(this.timer);
15854         this.el.blur();
15855         if(this.pressClass){
15856             this.el.addClass(this.pressClass);
15857         }
15858         this.mousedownTime = new Date();
15859
15860         Roo.get(document).on("mouseup", this.handleMouseUp, this);
15861         this.el.on("mouseout", this.handleMouseOut, this);
15862
15863         this.fireEvent("mousedown", this);
15864         this.fireEvent("click", this);
15865         
15866         this.timer = this.click.defer(this.delay || this.interval, this);
15867     },
15868
15869     // private
15870     click : function(){
15871         this.fireEvent("click", this);
15872         this.timer = this.click.defer(this.getInterval(), this);
15873     },
15874
15875     // private
15876     getInterval: function(){
15877         if(!this.accelerate){
15878             return this.interval;
15879         }
15880         var pressTime = this.mousedownTime.getElapsed();
15881         if(pressTime < 500){
15882             return 400;
15883         }else if(pressTime < 1700){
15884             return 320;
15885         }else if(pressTime < 2600){
15886             return 250;
15887         }else if(pressTime < 3500){
15888             return 180;
15889         }else if(pressTime < 4400){
15890             return 140;
15891         }else if(pressTime < 5300){
15892             return 80;
15893         }else if(pressTime < 6200){
15894             return 50;
15895         }else{
15896             return 10;
15897         }
15898     },
15899
15900     // private
15901     handleMouseOut : function(){
15902         clearTimeout(this.timer);
15903         if(this.pressClass){
15904             this.el.removeClass(this.pressClass);
15905         }
15906         this.el.on("mouseover", this.handleMouseReturn, this);
15907     },
15908
15909     // private
15910     handleMouseReturn : function(){
15911         this.el.un("mouseover", this.handleMouseReturn);
15912         if(this.pressClass){
15913             this.el.addClass(this.pressClass);
15914         }
15915         this.click();
15916     },
15917
15918     // private
15919     handleMouseUp : function(){
15920         clearTimeout(this.timer);
15921         this.el.un("mouseover", this.handleMouseReturn);
15922         this.el.un("mouseout", this.handleMouseOut);
15923         Roo.get(document).un("mouseup", this.handleMouseUp);
15924         this.el.removeClass(this.pressClass);
15925         this.fireEvent("mouseup", this);
15926     }
15927 });/**
15928  * @class Roo.util.Clipboard
15929  * @static
15930  * 
15931  * Clipboard UTILS
15932  * 
15933  **/
15934 Roo.util.Clipboard = {
15935     /**
15936      * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15937      * @param {String} text to copy to clipboard
15938      */
15939     write : function(text) {
15940         // navigator clipboard api needs a secure context (https)
15941         if (navigator.clipboard && window.isSecureContext) {
15942             // navigator clipboard api method'
15943             navigator.clipboard.writeText(text);
15944             return ;
15945         } 
15946         // text area method
15947         var ta = document.createElement("textarea");
15948         ta.value = text;
15949         // make the textarea out of viewport
15950         ta.style.position = "fixed";
15951         ta.style.left = "-999999px";
15952         ta.style.top = "-999999px";
15953         document.body.appendChild(ta);
15954         ta.focus();
15955         ta.select();
15956         document.execCommand('copy');
15957         (function() {
15958             ta.remove();
15959         }).defer(100);
15960         
15961     }
15962         
15963 }
15964     /*
15965  * Based on:
15966  * Ext JS Library 1.1.1
15967  * Copyright(c) 2006-2007, Ext JS, LLC.
15968  *
15969  * Originally Released Under LGPL - original licence link has changed is not relivant.
15970  *
15971  * Fork - LGPL
15972  * <script type="text/javascript">
15973  */
15974
15975  
15976 /**
15977  * @class Roo.KeyNav
15978  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
15979  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15980  * way to implement custom navigation schemes for any UI component.</p>
15981  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15982  * pageUp, pageDown, del, home, end.  Usage:</p>
15983  <pre><code>
15984 var nav = new Roo.KeyNav("my-element", {
15985     "left" : function(e){
15986         this.moveLeft(e.ctrlKey);
15987     },
15988     "right" : function(e){
15989         this.moveRight(e.ctrlKey);
15990     },
15991     "enter" : function(e){
15992         this.save();
15993     },
15994     scope : this
15995 });
15996 </code></pre>
15997  * @constructor
15998  * @param {String/HTMLElement/Roo.Element} el The element to bind to
15999  * @param {Object} config The config
16000  */
16001 Roo.KeyNav = function(el, config){
16002     this.el = Roo.get(el);
16003     Roo.apply(this, config);
16004     if(!this.disabled){
16005         this.disabled = true;
16006         this.enable();
16007     }
16008 };
16009
16010 Roo.KeyNav.prototype = {
16011     /**
16012      * @cfg {Boolean} disabled
16013      * True to disable this KeyNav instance (defaults to false)
16014      */
16015     disabled : false,
16016     /**
16017      * @cfg {String} defaultEventAction
16018      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
16019      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
16020      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
16021      */
16022     defaultEventAction: "stopEvent",
16023     /**
16024      * @cfg {Boolean} forceKeyDown
16025      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
16026      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
16027      * handle keydown instead of keypress.
16028      */
16029     forceKeyDown : false,
16030
16031     // private
16032     prepareEvent : function(e){
16033         var k = e.getKey();
16034         var h = this.keyToHandler[k];
16035         //if(h && this[h]){
16036         //    e.stopPropagation();
16037         //}
16038         if(Roo.isSafari && h && k >= 37 && k <= 40){
16039             e.stopEvent();
16040         }
16041     },
16042
16043     // private
16044     relay : function(e){
16045         var k = e.getKey();
16046         var h = this.keyToHandler[k];
16047         if(h && this[h]){
16048             if(this.doRelay(e, this[h], h) !== true){
16049                 e[this.defaultEventAction]();
16050             }
16051         }
16052     },
16053
16054     // private
16055     doRelay : function(e, h, hname){
16056         return h.call(this.scope || this, e);
16057     },
16058
16059     // possible handlers
16060     enter : false,
16061     left : false,
16062     right : false,
16063     up : false,
16064     down : false,
16065     tab : false,
16066     esc : false,
16067     pageUp : false,
16068     pageDown : false,
16069     del : false,
16070     home : false,
16071     end : false,
16072
16073     // quick lookup hash
16074     keyToHandler : {
16075         37 : "left",
16076         39 : "right",
16077         38 : "up",
16078         40 : "down",
16079         33 : "pageUp",
16080         34 : "pageDown",
16081         46 : "del",
16082         36 : "home",
16083         35 : "end",
16084         13 : "enter",
16085         27 : "esc",
16086         9  : "tab"
16087     },
16088
16089         /**
16090          * Enable this KeyNav
16091          */
16092         enable: function(){
16093                 if(this.disabled){
16094             // ie won't do special keys on keypress, no one else will repeat keys with keydown
16095             // the EventObject will normalize Safari automatically
16096             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16097                 this.el.on("keydown", this.relay,  this);
16098             }else{
16099                 this.el.on("keydown", this.prepareEvent,  this);
16100                 this.el.on("keypress", this.relay,  this);
16101             }
16102                     this.disabled = false;
16103                 }
16104         },
16105
16106         /**
16107          * Disable this KeyNav
16108          */
16109         disable: function(){
16110                 if(!this.disabled){
16111                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
16112                 this.el.un("keydown", this.relay);
16113             }else{
16114                 this.el.un("keydown", this.prepareEvent);
16115                 this.el.un("keypress", this.relay);
16116             }
16117                     this.disabled = true;
16118                 }
16119         }
16120 };/*
16121  * Based on:
16122  * Ext JS Library 1.1.1
16123  * Copyright(c) 2006-2007, Ext JS, LLC.
16124  *
16125  * Originally Released Under LGPL - original licence link has changed is not relivant.
16126  *
16127  * Fork - LGPL
16128  * <script type="text/javascript">
16129  */
16130
16131  
16132 /**
16133  * @class Roo.KeyMap
16134  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
16135  * The constructor accepts the same config object as defined by {@link #addBinding}.
16136  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
16137  * combination it will call the function with this signature (if the match is a multi-key
16138  * combination the callback will still be called only once): (String key, Roo.EventObject e)
16139  * A KeyMap can also handle a string representation of keys.<br />
16140  * Usage:
16141  <pre><code>
16142 // map one key by key code
16143 var map = new Roo.KeyMap("my-element", {
16144     key: 13, // or Roo.EventObject.ENTER
16145     fn: myHandler,
16146     scope: myObject
16147 });
16148
16149 // map multiple keys to one action by string
16150 var map = new Roo.KeyMap("my-element", {
16151     key: "a\r\n\t",
16152     fn: myHandler,
16153     scope: myObject
16154 });
16155
16156 // map multiple keys to multiple actions by strings and array of codes
16157 var map = new Roo.KeyMap("my-element", [
16158     {
16159         key: [10,13],
16160         fn: function(){ alert("Return was pressed"); }
16161     }, {
16162         key: "abc",
16163         fn: function(){ alert('a, b or c was pressed'); }
16164     }, {
16165         key: "\t",
16166         ctrl:true,
16167         shift:true,
16168         fn: function(){ alert('Control + shift + tab was pressed.'); }
16169     }
16170 ]);
16171 </code></pre>
16172  * <b>Note: A KeyMap starts enabled</b>
16173  * @constructor
16174  * @param {String/HTMLElement/Roo.Element} el The element to bind to
16175  * @param {Object} config The config (see {@link #addBinding})
16176  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
16177  */
16178 Roo.KeyMap = function(el, config, eventName){
16179     this.el  = Roo.get(el);
16180     this.eventName = eventName || "keydown";
16181     this.bindings = [];
16182     if(config){
16183         this.addBinding(config);
16184     }
16185     this.enable();
16186 };
16187
16188 Roo.KeyMap.prototype = {
16189     /**
16190      * True to stop the event from bubbling and prevent the default browser action if the
16191      * key was handled by the KeyMap (defaults to false)
16192      * @type Boolean
16193      */
16194     stopEvent : false,
16195
16196     /**
16197      * Add a new binding to this KeyMap. The following config object properties are supported:
16198      * <pre>
16199 Property    Type             Description
16200 ----------  ---------------  ----------------------------------------------------------------------
16201 key         String/Array     A single keycode or an array of keycodes to handle
16202 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
16203 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
16204 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
16205 fn          Function         The function to call when KeyMap finds the expected key combination
16206 scope       Object           The scope of the callback function
16207 </pre>
16208      *
16209      * Usage:
16210      * <pre><code>
16211 // Create a KeyMap
16212 var map = new Roo.KeyMap(document, {
16213     key: Roo.EventObject.ENTER,
16214     fn: handleKey,
16215     scope: this
16216 });
16217
16218 //Add a new binding to the existing KeyMap later
16219 map.addBinding({
16220     key: 'abc',
16221     shift: true,
16222     fn: handleKey,
16223     scope: this
16224 });
16225 </code></pre>
16226      * @param {Object/Array} config A single KeyMap config or an array of configs
16227      */
16228         addBinding : function(config){
16229         if(config instanceof Array){
16230             for(var i = 0, len = config.length; i < len; i++){
16231                 this.addBinding(config[i]);
16232             }
16233             return;
16234         }
16235         var keyCode = config.key,
16236             shift = config.shift, 
16237             ctrl = config.ctrl, 
16238             alt = config.alt,
16239             fn = config.fn,
16240             scope = config.scope;
16241         if(typeof keyCode == "string"){
16242             var ks = [];
16243             var keyString = keyCode.toUpperCase();
16244             for(var j = 0, len = keyString.length; j < len; j++){
16245                 ks.push(keyString.charCodeAt(j));
16246             }
16247             keyCode = ks;
16248         }
16249         var keyArray = keyCode instanceof Array;
16250         var handler = function(e){
16251             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
16252                 var k = e.getKey();
16253                 if(keyArray){
16254                     for(var i = 0, len = keyCode.length; i < len; i++){
16255                         if(keyCode[i] == k){
16256                           if(this.stopEvent){
16257                               e.stopEvent();
16258                           }
16259                           fn.call(scope || window, k, e);
16260                           return;
16261                         }
16262                     }
16263                 }else{
16264                     if(k == keyCode){
16265                         if(this.stopEvent){
16266                            e.stopEvent();
16267                         }
16268                         fn.call(scope || window, k, e);
16269                     }
16270                 }
16271             }
16272         };
16273         this.bindings.push(handler);  
16274         },
16275
16276     /**
16277      * Shorthand for adding a single key listener
16278      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
16279      * following options:
16280      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
16281      * @param {Function} fn The function to call
16282      * @param {Object} scope (optional) The scope of the function
16283      */
16284     on : function(key, fn, scope){
16285         var keyCode, shift, ctrl, alt;
16286         if(typeof key == "object" && !(key instanceof Array)){
16287             keyCode = key.key;
16288             shift = key.shift;
16289             ctrl = key.ctrl;
16290             alt = key.alt;
16291         }else{
16292             keyCode = key;
16293         }
16294         this.addBinding({
16295             key: keyCode,
16296             shift: shift,
16297             ctrl: ctrl,
16298             alt: alt,
16299             fn: fn,
16300             scope: scope
16301         })
16302     },
16303
16304     // private
16305     handleKeyDown : function(e){
16306             if(this.enabled){ //just in case
16307             var b = this.bindings;
16308             for(var i = 0, len = b.length; i < len; i++){
16309                 b[i].call(this, e);
16310             }
16311             }
16312         },
16313         
16314         /**
16315          * Returns true if this KeyMap is enabled
16316          * @return {Boolean} 
16317          */
16318         isEnabled : function(){
16319             return this.enabled;  
16320         },
16321         
16322         /**
16323          * Enables this KeyMap
16324          */
16325         enable: function(){
16326                 if(!this.enabled){
16327                     this.el.on(this.eventName, this.handleKeyDown, this);
16328                     this.enabled = true;
16329                 }
16330         },
16331
16332         /**
16333          * Disable this KeyMap
16334          */
16335         disable: function(){
16336                 if(this.enabled){
16337                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
16338                     this.enabled = false;
16339                 }
16340         }
16341 };/*
16342  * Based on:
16343  * Ext JS Library 1.1.1
16344  * Copyright(c) 2006-2007, Ext JS, LLC.
16345  *
16346  * Originally Released Under LGPL - original licence link has changed is not relivant.
16347  *
16348  * Fork - LGPL
16349  * <script type="text/javascript">
16350  */
16351
16352  
16353 /**
16354  * @class Roo.util.TextMetrics
16355  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
16356  * wide, in pixels, a given block of text will be.
16357  * @static
16358  */
16359 Roo.util.TextMetrics = function(){
16360     var shared;
16361     return {
16362         /**
16363          * Measures the size of the specified text
16364          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
16365          * that can affect the size of the rendered text
16366          * @param {String} text The text to measure
16367          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16368          * in order to accurately measure the text height
16369          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16370          */
16371         measure : function(el, text, fixedWidth){
16372             if(!shared){
16373                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
16374             }
16375             shared.bind(el);
16376             shared.setFixedWidth(fixedWidth || 'auto');
16377             return shared.getSize(text);
16378         },
16379
16380         /**
16381          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
16382          * the overhead of multiple calls to initialize the style properties on each measurement.
16383          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
16384          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
16385          * in order to accurately measure the text height
16386          * @return {Roo.util.TextMetrics.Instance} instance The new instance
16387          */
16388         createInstance : function(el, fixedWidth){
16389             return Roo.util.TextMetrics.Instance(el, fixedWidth);
16390         }
16391     };
16392 }();
16393
16394 /**
16395  * @class Roo.util.TextMetrics.Instance
16396  * Instance of  TextMetrics Calcuation
16397  * @constructor
16398  * Create a new TextMetrics Instance
16399  * @param {Object} bindto
16400  * @param {Boolean} fixedWidth
16401  */
16402
16403 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
16404 {
16405     var ml = new Roo.Element(document.createElement('div'));
16406     document.body.appendChild(ml.dom);
16407     ml.position('absolute');
16408     ml.setLeftTop(-1000, -1000);
16409     ml.hide();
16410
16411     if(fixedWidth){
16412         ml.setWidth(fixedWidth);
16413     }
16414      
16415     var instance = {
16416         /**
16417          * Returns the size of the specified text based on the internal element's style and width properties
16418          * @param {String} text The text to measure
16419          * @return {Object} An object containing the text's size {width: (width), height: (height)}
16420          */
16421         getSize : function(text){
16422             ml.update(text);
16423             var s = ml.getSize();
16424             ml.update('');
16425             return s;
16426         },
16427
16428         /**
16429          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
16430          * that can affect the size of the rendered text
16431          * @param {String/HTMLElement} el The element, dom node or id
16432          */
16433         bind : function(el){
16434             ml.setStyle(
16435                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
16436             );
16437         },
16438
16439         /**
16440          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
16441          * to set a fixed width in order to accurately measure the text height.
16442          * @param {Number} width The width to set on the element
16443          */
16444         setFixedWidth : function(width){
16445             ml.setWidth(width);
16446         },
16447
16448         /**
16449          * Returns the measured width of the specified text
16450          * @param {String} text The text to measure
16451          * @return {Number} width The width in pixels
16452          */
16453         getWidth : function(text){
16454             ml.dom.style.width = 'auto';
16455             return this.getSize(text).width;
16456         },
16457
16458         /**
16459          * Returns the measured height of the specified text.  For multiline text, be sure to call
16460          * {@link #setFixedWidth} if necessary.
16461          * @param {String} text The text to measure
16462          * @return {Number} height The height in pixels
16463          */
16464         getHeight : function(text){
16465             return this.getSize(text).height;
16466         }
16467     };
16468
16469     instance.bind(bindTo);
16470
16471     return instance;
16472 };
16473
16474 // backwards compat
16475 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
16476  * Based on:
16477  * Ext JS Library 1.1.1
16478  * Copyright(c) 2006-2007, Ext JS, LLC.
16479  *
16480  * Originally Released Under LGPL - original licence link has changed is not relivant.
16481  *
16482  * Fork - LGPL
16483  * <script type="text/javascript">
16484  */
16485
16486 /**
16487  * @class Roo.state.Provider
16488  * Abstract base class for state provider implementations. This class provides methods
16489  * for encoding and decoding <b>typed</b> variables including dates and defines the 
16490  * Provider interface.
16491  */
16492 Roo.state.Provider = function(){
16493     /**
16494      * @event statechange
16495      * Fires when a state change occurs.
16496      * @param {Provider} this This state provider
16497      * @param {String} key The state key which was changed
16498      * @param {String} value The encoded value for the state
16499      */
16500     this.addEvents({
16501         "statechange": true
16502     });
16503     this.state = {};
16504     Roo.state.Provider.superclass.constructor.call(this);
16505 };
16506 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
16507     /**
16508      * Returns the current value for a key
16509      * @param {String} name The key name
16510      * @param {Mixed} defaultValue A default value to return if the key's value is not found
16511      * @return {Mixed} The state data
16512      */
16513     get : function(name, defaultValue){
16514         return typeof this.state[name] == "undefined" ?
16515             defaultValue : this.state[name];
16516     },
16517     
16518     /**
16519      * Clears a value from the state
16520      * @param {String} name The key name
16521      */
16522     clear : function(name){
16523         delete this.state[name];
16524         this.fireEvent("statechange", this, name, null);
16525     },
16526     
16527     /**
16528      * Sets the value for a key
16529      * @param {String} name The key name
16530      * @param {Mixed} value The value to set
16531      */
16532     set : function(name, value){
16533         this.state[name] = value;
16534         this.fireEvent("statechange", this, name, value);
16535     },
16536     
16537     /**
16538      * Decodes a string previously encoded with {@link #encodeValue}.
16539      * @param {String} value The value to decode
16540      * @return {Mixed} The decoded value
16541      */
16542     decodeValue : function(cookie){
16543         var re = /^(a|n|d|b|s|o)\:(.*)$/;
16544         var matches = re.exec(unescape(cookie));
16545         if(!matches || !matches[1]) {
16546             return; // non state cookie
16547         }
16548         var type = matches[1];
16549         var v = matches[2];
16550         switch(type){
16551             case "n":
16552                 return parseFloat(v);
16553             case "d":
16554                 return new Date(Date.parse(v));
16555             case "b":
16556                 return (v == "1");
16557             case "a":
16558                 var all = [];
16559                 var values = v.split("^");
16560                 for(var i = 0, len = values.length; i < len; i++){
16561                     all.push(this.decodeValue(values[i]));
16562                 }
16563                 return all;
16564            case "o":
16565                 var all = {};
16566                 var values = v.split("^");
16567                 for(var i = 0, len = values.length; i < len; i++){
16568                     var kv = values[i].split("=");
16569                     all[kv[0]] = this.decodeValue(kv[1]);
16570                 }
16571                 return all;
16572            default:
16573                 return v;
16574         }
16575     },
16576     
16577     /**
16578      * Encodes a value including type information.  Decode with {@link #decodeValue}.
16579      * @param {Mixed} value The value to encode
16580      * @return {String} The encoded value
16581      */
16582     encodeValue : function(v){
16583         var enc;
16584         if(typeof v == "number"){
16585             enc = "n:" + v;
16586         }else if(typeof v == "boolean"){
16587             enc = "b:" + (v ? "1" : "0");
16588         }else if(v instanceof Date){
16589             enc = "d:" + v.toGMTString();
16590         }else if(v instanceof Array){
16591             var flat = "";
16592             for(var i = 0, len = v.length; i < len; i++){
16593                 flat += this.encodeValue(v[i]);
16594                 if(i != len-1) {
16595                     flat += "^";
16596                 }
16597             }
16598             enc = "a:" + flat;
16599         }else if(typeof v == "object"){
16600             var flat = "";
16601             for(var key in v){
16602                 if(typeof v[key] != "function"){
16603                     flat += key + "=" + this.encodeValue(v[key]) + "^";
16604                 }
16605             }
16606             enc = "o:" + flat.substring(0, flat.length-1);
16607         }else{
16608             enc = "s:" + v;
16609         }
16610         return escape(enc);        
16611     }
16612 });
16613
16614 /*
16615  * Based on:
16616  * Ext JS Library 1.1.1
16617  * Copyright(c) 2006-2007, Ext JS, LLC.
16618  *
16619  * Originally Released Under LGPL - original licence link has changed is not relivant.
16620  *
16621  * Fork - LGPL
16622  * <script type="text/javascript">
16623  */
16624 /**
16625  * @class Roo.state.Manager
16626  * This is the global state manager. By default all components that are "state aware" check this class
16627  * for state information if you don't pass them a custom state provider. In order for this class
16628  * to be useful, it must be initialized with a provider when your application initializes.
16629  <pre><code>
16630 // in your initialization function
16631 init : function(){
16632    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16633    ...
16634    // supposed you have a {@link Roo.BorderLayout}
16635    var layout = new Roo.BorderLayout(...);
16636    layout.restoreState();
16637    // or a {Roo.BasicDialog}
16638    var dialog = new Roo.BasicDialog(...);
16639    dialog.restoreState();
16640  </code></pre>
16641  * @static
16642  */
16643 Roo.state.Manager = function(){
16644     var provider = new Roo.state.Provider();
16645     
16646     return {
16647         /**
16648          * Configures the default state provider for your application
16649          * @param {Provider} stateProvider The state provider to set
16650          */
16651         setProvider : function(stateProvider){
16652             provider = stateProvider;
16653         },
16654         
16655         /**
16656          * Returns the current value for a key
16657          * @param {String} name The key name
16658          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16659          * @return {Mixed} The state data
16660          */
16661         get : function(key, defaultValue){
16662             return provider.get(key, defaultValue);
16663         },
16664         
16665         /**
16666          * Sets the value for a key
16667          * @param {String} name The key name
16668          * @param {Mixed} value The state data
16669          */
16670          set : function(key, value){
16671             provider.set(key, value);
16672         },
16673         
16674         /**
16675          * Clears a value from the state
16676          * @param {String} name The key name
16677          */
16678         clear : function(key){
16679             provider.clear(key);
16680         },
16681         
16682         /**
16683          * Gets the currently configured state provider
16684          * @return {Provider} The state provider
16685          */
16686         getProvider : function(){
16687             return provider;
16688         }
16689     };
16690 }();
16691 /*
16692  * Based on:
16693  * Ext JS Library 1.1.1
16694  * Copyright(c) 2006-2007, Ext JS, LLC.
16695  *
16696  * Originally Released Under LGPL - original licence link has changed is not relivant.
16697  *
16698  * Fork - LGPL
16699  * <script type="text/javascript">
16700  */
16701 /**
16702  * @class Roo.state.CookieProvider
16703  * @extends Roo.state.Provider
16704  * The default Provider implementation which saves state via cookies.
16705  * <br />Usage:
16706  <pre><code>
16707    var cp = new Roo.state.CookieProvider({
16708        path: "/cgi-bin/",
16709        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16710        domain: "roojs.com"
16711    })
16712    Roo.state.Manager.setProvider(cp);
16713  </code></pre>
16714  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16715  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16716  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
16717  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16718  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16719  * domain the page is running on including the 'www' like 'www.roojs.com')
16720  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16721  * @constructor
16722  * Create a new CookieProvider
16723  * @param {Object} config The configuration object
16724  */
16725 Roo.state.CookieProvider = function(config){
16726     Roo.state.CookieProvider.superclass.constructor.call(this);
16727     this.path = "/";
16728     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16729     this.domain = null;
16730     this.secure = false;
16731     Roo.apply(this, config);
16732     this.state = this.readCookies();
16733 };
16734
16735 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16736     // private
16737     set : function(name, value){
16738         if(typeof value == "undefined" || value === null){
16739             this.clear(name);
16740             return;
16741         }
16742         this.setCookie(name, value);
16743         Roo.state.CookieProvider.superclass.set.call(this, name, value);
16744     },
16745
16746     // private
16747     clear : function(name){
16748         this.clearCookie(name);
16749         Roo.state.CookieProvider.superclass.clear.call(this, name);
16750     },
16751
16752     // private
16753     readCookies : function(){
16754         var cookies = {};
16755         var c = document.cookie + ";";
16756         var re = /\s?(.*?)=(.*?);/g;
16757         var matches;
16758         while((matches = re.exec(c)) != null){
16759             var name = matches[1];
16760             var value = matches[2];
16761             if(name && name.substring(0,3) == "ys-"){
16762                 cookies[name.substr(3)] = this.decodeValue(value);
16763             }
16764         }
16765         return cookies;
16766     },
16767
16768     // private
16769     setCookie : function(name, value){
16770         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16771            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16772            ((this.path == null) ? "" : ("; path=" + this.path)) +
16773            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16774            ((this.secure == true) ? "; secure" : "");
16775     },
16776
16777     // private
16778     clearCookie : function(name){
16779         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16780            ((this.path == null) ? "" : ("; path=" + this.path)) +
16781            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16782            ((this.secure == true) ? "; secure" : "");
16783     }
16784 });/*
16785  * Based on:
16786  * Ext JS Library 1.1.1
16787  * Copyright(c) 2006-2007, Ext JS, LLC.
16788  *
16789  * Originally Released Under LGPL - original licence link has changed is not relivant.
16790  *
16791  * Fork - LGPL
16792  * <script type="text/javascript">
16793  */
16794  
16795
16796 /**
16797  * @class Roo.ComponentMgr
16798  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16799  * @static
16800  */
16801 Roo.ComponentMgr = function(){
16802     var all = new Roo.util.MixedCollection();
16803
16804     return {
16805         /**
16806          * Registers a component.
16807          * @param {Roo.Component} c The component
16808          */
16809         register : function(c){
16810             all.add(c);
16811         },
16812
16813         /**
16814          * Unregisters a component.
16815          * @param {Roo.Component} c The component
16816          */
16817         unregister : function(c){
16818             all.remove(c);
16819         },
16820
16821         /**
16822          * Returns a component by id
16823          * @param {String} id The component id
16824          */
16825         get : function(id){
16826             return all.get(id);
16827         },
16828
16829         /**
16830          * Registers a function that will be called when a specified component is added to ComponentMgr
16831          * @param {String} id The component id
16832          * @param {Funtction} fn The callback function
16833          * @param {Object} scope The scope of the callback
16834          */
16835         onAvailable : function(id, fn, scope){
16836             all.on("add", function(index, o){
16837                 if(o.id == id){
16838                     fn.call(scope || o, o);
16839                     all.un("add", fn, scope);
16840                 }
16841             });
16842         }
16843     };
16844 }();/*
16845  * Based on:
16846  * Ext JS Library 1.1.1
16847  * Copyright(c) 2006-2007, Ext JS, LLC.
16848  *
16849  * Originally Released Under LGPL - original licence link has changed is not relivant.
16850  *
16851  * Fork - LGPL
16852  * <script type="text/javascript">
16853  */
16854  
16855 /**
16856  * @class Roo.Component
16857  * @extends Roo.util.Observable
16858  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
16859  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
16860  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16861  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16862  * All visual components (widgets) that require rendering into a layout should subclass Component.
16863  * @constructor
16864  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
16865  * 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
16866  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
16867  */
16868 Roo.Component = function(config){
16869     console.log("COMPONENT CONSTRUCTOR");
16870     config = config || {};
16871     if(config.tagName || config.dom || typeof config == "string"){ // element object
16872         config = {el: config, id: config.id || config};
16873     }
16874     this.initialConfig = config;
16875
16876     Roo.apply(this, config);
16877     this.addEvents({
16878         /**
16879          * @event disable
16880          * Fires after the component is disabled.
16881              * @param {Roo.Component} this
16882              */
16883         disable : true,
16884         /**
16885          * @event enable
16886          * Fires after the component is enabled.
16887              * @param {Roo.Component} this
16888              */
16889         enable : true,
16890         /**
16891          * @event beforeshow
16892          * Fires before the component is shown.  Return false to stop the show.
16893              * @param {Roo.Component} this
16894              */
16895         beforeshow : true,
16896         /**
16897          * @event show
16898          * Fires after the component is shown.
16899              * @param {Roo.Component} this
16900              */
16901         show : true,
16902         /**
16903          * @event beforehide
16904          * Fires before the component is hidden. Return false to stop the hide.
16905              * @param {Roo.Component} this
16906              */
16907         beforehide : true,
16908         /**
16909          * @event hide
16910          * Fires after the component is hidden.
16911              * @param {Roo.Component} this
16912              */
16913         hide : true,
16914         /**
16915          * @event beforerender
16916          * Fires before the component is rendered. Return false to stop the render.
16917              * @param {Roo.Component} this
16918              */
16919         beforerender : true,
16920         /**
16921          * @event render
16922          * Fires after the component is rendered.
16923              * @param {Roo.Component} this
16924              */
16925         render : true,
16926         /**
16927          * @event beforedestroy
16928          * Fires before the component is destroyed. Return false to stop the destroy.
16929              * @param {Roo.Component} this
16930              */
16931         beforedestroy : true,
16932         /**
16933          * @event destroy
16934          * Fires after the component is destroyed.
16935              * @param {Roo.Component} this
16936              */
16937         destroy : true
16938     });
16939     if(!this.id){
16940         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16941     }
16942     Roo.ComponentMgr.register(this);
16943     Roo.Component.superclass.constructor.call(this);
16944     this.initComponent();
16945     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16946         this.render(this.renderTo);
16947         delete this.renderTo;
16948     }
16949 };
16950
16951 /** @private */
16952 Roo.Component.AUTO_ID = 1000;
16953
16954 Roo.extend(Roo.Component, Roo.util.Observable, {
16955     /**
16956      * @scope Roo.Component.prototype
16957      * @type {Boolean}
16958      * true if this component is hidden. Read-only.
16959      */
16960     hidden : false,
16961     /**
16962      * @type {Boolean}
16963      * true if this component is disabled. Read-only.
16964      */
16965     disabled : false,
16966     /**
16967      * @type {Boolean}
16968      * true if this component has been rendered. Read-only.
16969      */
16970     rendered : false,
16971     
16972     /** @cfg {String} disableClass
16973      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16974      */
16975     disabledClass : "x-item-disabled",
16976         /** @cfg {Boolean} allowDomMove
16977          * Whether the component can move the Dom node when rendering (defaults to true).
16978          */
16979     allowDomMove : true,
16980     /** @cfg {String} hideMode (display|visibility)
16981      * How this component should hidden. Supported values are
16982      * "visibility" (css visibility), "offsets" (negative offset position) and
16983      * "display" (css display) - defaults to "display".
16984      */
16985     hideMode: 'display',
16986
16987     /** @private */
16988     ctype : "Roo.Component",
16989
16990     /**
16991      * @cfg {String} actionMode 
16992      * which property holds the element that used for  hide() / show() / disable() / enable()
16993      * default is 'el' for forms you probably want to set this to fieldEl 
16994      */
16995     actionMode : "el",
16996
16997     /** @private */
16998     getActionEl : function(){
16999         return this[this.actionMode];
17000     },
17001
17002     initComponent : Roo.emptyFn,
17003     /**
17004      * If this is a lazy rendering component, render it to its container element.
17005      * @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.
17006      */
17007     render : function(container, position){
17008         
17009         if(this.rendered){
17010             return this;
17011         }
17012         
17013         if(this.fireEvent("beforerender", this) === false){
17014             return false;
17015         }
17016         
17017         if(!container && this.el){
17018             this.el = Roo.get(this.el);
17019             container = this.el.dom.parentNode;
17020             this.allowDomMove = false;
17021         }
17022         this.container = Roo.get(container);
17023         this.rendered = true;
17024         if(position !== undefined){
17025             if(typeof position == 'number'){
17026                 position = this.container.dom.childNodes[position];
17027             }else{
17028                 position = Roo.getDom(position);
17029             }
17030         }
17031         this.onRender(this.container, position || null);
17032         if(this.cls){
17033             this.el.addClass(this.cls);
17034             delete this.cls;
17035         }
17036         if(this.style){
17037             this.el.applyStyles(this.style);
17038             delete this.style;
17039         }
17040         this.fireEvent("render", this);
17041         this.afterRender(this.container);
17042         if(this.hidden){
17043             this.hide();
17044         }
17045         if(this.disabled){
17046             this.disable();
17047         }
17048
17049         return this;
17050         
17051     },
17052
17053     /** @private */
17054     // default function is not really useful
17055     onRender : function(ct, position){
17056         if(this.el){
17057             this.el = Roo.get(this.el);
17058             if(this.allowDomMove !== false){
17059                 ct.dom.insertBefore(this.el.dom, position);
17060             }
17061         }
17062     },
17063
17064     /** @private */
17065     getAutoCreate : function(){
17066         var cfg = typeof this.autoCreate == "object" ?
17067                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
17068         if(this.id && !cfg.id){
17069             cfg.id = this.id;
17070         }
17071         return cfg;
17072     },
17073
17074     /** @private */
17075     afterRender : Roo.emptyFn,
17076
17077     /**
17078      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
17079      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
17080      */
17081     destroy : function(){
17082         if(this.fireEvent("beforedestroy", this) !== false){
17083             this.purgeListeners();
17084             this.beforeDestroy();
17085             if(this.rendered){
17086                 this.el.removeAllListeners();
17087                 this.el.remove();
17088                 if(this.actionMode == "container"){
17089                     this.container.remove();
17090                 }
17091             }
17092             this.onDestroy();
17093             Roo.ComponentMgr.unregister(this);
17094             this.fireEvent("destroy", this);
17095         }
17096     },
17097
17098         /** @private */
17099     beforeDestroy : function(){
17100
17101     },
17102
17103         /** @private */
17104         onDestroy : function(){
17105
17106     },
17107
17108     /**
17109      * Returns the underlying {@link Roo.Element}.
17110      * @return {Roo.Element} The element
17111      */
17112     getEl : function(){
17113         return this.el;
17114     },
17115
17116     /**
17117      * Returns the id of this component.
17118      * @return {String}
17119      */
17120     getId : function(){
17121         return this.id;
17122     },
17123
17124     /**
17125      * Try to focus this component.
17126      * @param {Boolean} selectText True to also select the text in this component (if applicable)
17127      * @return {Roo.Component} this
17128      */
17129     focus : function(selectText){
17130         if(this.rendered){
17131             this.el.focus();
17132             if(selectText === true){
17133                 this.el.dom.select();
17134             }
17135         }
17136         return this;
17137     },
17138
17139     /** @private */
17140     blur : function(){
17141         if(this.rendered){
17142             this.el.blur();
17143         }
17144         return this;
17145     },
17146
17147     /**
17148      * Disable this component.
17149      * @return {Roo.Component} this
17150      */
17151     disable : function(){
17152         if(this.rendered){
17153             this.onDisable();
17154         }
17155         this.disabled = true;
17156         this.fireEvent("disable", this);
17157         return this;
17158     },
17159
17160         // private
17161     onDisable : function(){
17162         this.getActionEl().addClass(this.disabledClass);
17163         this.el.dom.disabled = true;
17164     },
17165
17166     /**
17167      * Enable this component.
17168      * @return {Roo.Component} this
17169      */
17170     enable : function(){
17171         if(this.rendered){
17172             this.onEnable();
17173         }
17174         this.disabled = false;
17175         this.fireEvent("enable", this);
17176         return this;
17177     },
17178
17179         // private
17180     onEnable : function(){
17181         this.getActionEl().removeClass(this.disabledClass);
17182         this.el.dom.disabled = false;
17183     },
17184
17185     /**
17186      * Convenience function for setting disabled/enabled by boolean.
17187      * @param {Boolean} disabled
17188      */
17189     setDisabled : function(disabled){
17190         this[disabled ? "disable" : "enable"]();
17191     },
17192
17193     /**
17194      * Show this component.
17195      * @return {Roo.Component} this
17196      */
17197     show: function(){
17198         if(this.fireEvent("beforeshow", this) !== false){
17199             this.hidden = false;
17200             if(this.rendered){
17201                 this.onShow();
17202             }
17203             this.fireEvent("show", this);
17204         }
17205         return this;
17206     },
17207
17208     // private
17209     onShow : function(){
17210         var ae = this.getActionEl();
17211         if(this.hideMode == 'visibility'){
17212             ae.dom.style.visibility = "visible";
17213         }else if(this.hideMode == 'offsets'){
17214             ae.removeClass('x-hidden');
17215         }else{
17216             ae.dom.style.display = "";
17217         }
17218     },
17219
17220     /**
17221      * Hide this component.
17222      * @return {Roo.Component} this
17223      */
17224     hide: function(){
17225         if(this.fireEvent("beforehide", this) !== false){
17226             this.hidden = true;
17227             if(this.rendered){
17228                 this.onHide();
17229             }
17230             this.fireEvent("hide", this);
17231         }
17232         return this;
17233     },
17234
17235     // private
17236     onHide : function(){
17237         var ae = this.getActionEl();
17238         if(this.hideMode == 'visibility'){
17239             ae.dom.style.visibility = "hidden";
17240         }else if(this.hideMode == 'offsets'){
17241             ae.addClass('x-hidden');
17242         }else{
17243             ae.dom.style.display = "none";
17244         }
17245     },
17246
17247     /**
17248      * Convenience function to hide or show this component by boolean.
17249      * @param {Boolean} visible True to show, false to hide
17250      * @return {Roo.Component} this
17251      */
17252     setVisible: function(visible){
17253         if(visible) {
17254             this.show();
17255         }else{
17256             this.hide();
17257         }
17258         return this;
17259     },
17260
17261     /**
17262      * Returns true if this component is visible.
17263      */
17264     isVisible : function(){
17265         return this.getActionEl().isVisible();
17266     },
17267
17268     cloneConfig : function(overrides){
17269         overrides = overrides || {};
17270         var id = overrides.id || Roo.id();
17271         var cfg = Roo.applyIf(overrides, this.initialConfig);
17272         cfg.id = id; // prevent dup id
17273         return new this.constructor(cfg);
17274     }
17275 });/*
17276  * Based on:
17277  * Ext JS Library 1.1.1
17278  * Copyright(c) 2006-2007, Ext JS, LLC.
17279  *
17280  * Originally Released Under LGPL - original licence link has changed is not relivant.
17281  *
17282  * Fork - LGPL
17283  * <script type="text/javascript">
17284  */
17285
17286 /**
17287  * @class Roo.BoxComponent
17288  * @extends Roo.Component
17289  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
17290  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
17291  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17292  * layout containers.
17293  * @constructor
17294  * @param {Roo.Element/String/Object} config The configuration options.
17295  */
17296 Roo.BoxComponent = function(config){
17297     Roo.Component.call(this, config);
17298     this.addEvents({
17299         /**
17300          * @event resize
17301          * Fires after the component is resized.
17302              * @param {Roo.Component} this
17303              * @param {Number} adjWidth The box-adjusted width that was set
17304              * @param {Number} adjHeight The box-adjusted height that was set
17305              * @param {Number} rawWidth The width that was originally specified
17306              * @param {Number} rawHeight The height that was originally specified
17307              */
17308         resize : true,
17309         /**
17310          * @event move
17311          * Fires after the component is moved.
17312              * @param {Roo.Component} this
17313              * @param {Number} x The new x position
17314              * @param {Number} y The new y position
17315              */
17316         move : true
17317     });
17318 };
17319
17320 Roo.extend(Roo.BoxComponent, Roo.Component, {
17321     // private, set in afterRender to signify that the component has been rendered
17322     boxReady : false,
17323     // private, used to defer height settings to subclasses
17324     deferHeight: false,
17325     /** @cfg {Number} width
17326      * width (optional) size of component
17327      */
17328      /** @cfg {Number} height
17329      * height (optional) size of component
17330      */
17331      
17332     /**
17333      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
17334      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17335      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17336      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17337      * @return {Roo.BoxComponent} this
17338      */
17339     setSize : function(w, h){
17340         // support for standard size objects
17341         if(typeof w == 'object'){
17342             h = w.height;
17343             w = w.width;
17344         }
17345         // not rendered
17346         if(!this.boxReady){
17347             this.width = w;
17348             this.height = h;
17349             return this;
17350         }
17351
17352         // prevent recalcs when not needed
17353         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17354             return this;
17355         }
17356         this.lastSize = {width: w, height: h};
17357
17358         var adj = this.adjustSize(w, h);
17359         var aw = adj.width, ah = adj.height;
17360         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17361             var rz = this.getResizeEl();
17362             if(!this.deferHeight && aw !== undefined && ah !== undefined){
17363                 rz.setSize(aw, ah);
17364             }else if(!this.deferHeight && ah !== undefined){
17365                 rz.setHeight(ah);
17366             }else if(aw !== undefined){
17367                 rz.setWidth(aw);
17368             }
17369             this.onResize(aw, ah, w, h);
17370             this.fireEvent('resize', this, aw, ah, w, h);
17371         }
17372         return this;
17373     },
17374
17375     /**
17376      * Gets the current size of the component's underlying element.
17377      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17378      */
17379     getSize : function(){
17380         return this.el.getSize();
17381     },
17382
17383     /**
17384      * Gets the current XY position of the component's underlying element.
17385      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17386      * @return {Array} The XY position of the element (e.g., [100, 200])
17387      */
17388     getPosition : function(local){
17389         if(local === true){
17390             return [this.el.getLeft(true), this.el.getTop(true)];
17391         }
17392         return this.xy || this.el.getXY();
17393     },
17394
17395     /**
17396      * Gets the current box measurements of the component's underlying element.
17397      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17398      * @returns {Object} box An object in the format {x, y, width, height}
17399      */
17400     getBox : function(local){
17401         var s = this.el.getSize();
17402         if(local){
17403             s.x = this.el.getLeft(true);
17404             s.y = this.el.getTop(true);
17405         }else{
17406             var xy = this.xy || this.el.getXY();
17407             s.x = xy[0];
17408             s.y = xy[1];
17409         }
17410         return s;
17411     },
17412
17413     /**
17414      * Sets the current box measurements of the component's underlying element.
17415      * @param {Object} box An object in the format {x, y, width, height}
17416      * @returns {Roo.BoxComponent} this
17417      */
17418     updateBox : function(box){
17419         this.setSize(box.width, box.height);
17420         this.setPagePosition(box.x, box.y);
17421         return this;
17422     },
17423
17424     // protected
17425     getResizeEl : function(){
17426         return this.resizeEl || this.el;
17427     },
17428
17429     // protected
17430     getPositionEl : function(){
17431         return this.positionEl || this.el;
17432     },
17433
17434     /**
17435      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
17436      * This method fires the move event.
17437      * @param {Number} left The new left
17438      * @param {Number} top The new top
17439      * @returns {Roo.BoxComponent} this
17440      */
17441     setPosition : function(x, y){
17442         this.x = x;
17443         this.y = y;
17444         if(!this.boxReady){
17445             return this;
17446         }
17447         var adj = this.adjustPosition(x, y);
17448         var ax = adj.x, ay = adj.y;
17449
17450         var el = this.getPositionEl();
17451         if(ax !== undefined || ay !== undefined){
17452             if(ax !== undefined && ay !== undefined){
17453                 el.setLeftTop(ax, ay);
17454             }else if(ax !== undefined){
17455                 el.setLeft(ax);
17456             }else if(ay !== undefined){
17457                 el.setTop(ay);
17458             }
17459             this.onPosition(ax, ay);
17460             this.fireEvent('move', this, ax, ay);
17461         }
17462         return this;
17463     },
17464
17465     /**
17466      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
17467      * This method fires the move event.
17468      * @param {Number} x The new x position
17469      * @param {Number} y The new y position
17470      * @returns {Roo.BoxComponent} this
17471      */
17472     setPagePosition : function(x, y){
17473         this.pageX = x;
17474         this.pageY = y;
17475         if(!this.boxReady){
17476             return;
17477         }
17478         if(x === undefined || y === undefined){ // cannot translate undefined points
17479             return;
17480         }
17481         var p = this.el.translatePoints(x, y);
17482         this.setPosition(p.left, p.top);
17483         return this;
17484     },
17485
17486     // private
17487     onRender : function(ct, position){
17488         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17489         if(this.resizeEl){
17490             this.resizeEl = Roo.get(this.resizeEl);
17491         }
17492         if(this.positionEl){
17493             this.positionEl = Roo.get(this.positionEl);
17494         }
17495     },
17496
17497     // private
17498     afterRender : function(){
17499         Roo.BoxComponent.superclass.afterRender.call(this);
17500         this.boxReady = true;
17501         this.setSize(this.width, this.height);
17502         if(this.x || this.y){
17503             this.setPosition(this.x, this.y);
17504         }
17505         if(this.pageX || this.pageY){
17506             this.setPagePosition(this.pageX, this.pageY);
17507         }
17508     },
17509
17510     /**
17511      * Force the component's size to recalculate based on the underlying element's current height and width.
17512      * @returns {Roo.BoxComponent} this
17513      */
17514     syncSize : function(){
17515         delete this.lastSize;
17516         this.setSize(this.el.getWidth(), this.el.getHeight());
17517         return this;
17518     },
17519
17520     /**
17521      * Called after the component is resized, this method is empty by default but can be implemented by any
17522      * subclass that needs to perform custom logic after a resize occurs.
17523      * @param {Number} adjWidth The box-adjusted width that was set
17524      * @param {Number} adjHeight The box-adjusted height that was set
17525      * @param {Number} rawWidth The width that was originally specified
17526      * @param {Number} rawHeight The height that was originally specified
17527      */
17528     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17529
17530     },
17531
17532     /**
17533      * Called after the component is moved, this method is empty by default but can be implemented by any
17534      * subclass that needs to perform custom logic after a move occurs.
17535      * @param {Number} x The new x position
17536      * @param {Number} y The new y position
17537      */
17538     onPosition : function(x, y){
17539
17540     },
17541
17542     // private
17543     adjustSize : function(w, h){
17544         if(this.autoWidth){
17545             w = 'auto';
17546         }
17547         if(this.autoHeight){
17548             h = 'auto';
17549         }
17550         return {width : w, height: h};
17551     },
17552
17553     // private
17554     adjustPosition : function(x, y){
17555         return {x : x, y: y};
17556     }
17557 });/*
17558  * Based on:
17559  * Ext JS Library 1.1.1
17560  * Copyright(c) 2006-2007, Ext JS, LLC.
17561  *
17562  * Originally Released Under LGPL - original licence link has changed is not relivant.
17563  *
17564  * Fork - LGPL
17565  * <script type="text/javascript">
17566  */
17567  (function(){ 
17568 /**
17569  * @class Roo.Layer
17570  * @extends Roo.Element
17571  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17572  * automatic maintaining of shadow/shim positions.
17573  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17574  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17575  * you can pass a string with a CSS class name. False turns off the shadow.
17576  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17577  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17578  * @cfg {String} cls CSS class to add to the element
17579  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17580  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17581  * @constructor
17582  * @param {Object} config An object with config options.
17583  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17584  */
17585
17586 Roo.Layer = function(config, existingEl){
17587     config = config || {};
17588     var dh = Roo.DomHelper;
17589     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17590     if(existingEl){
17591         this.dom = Roo.getDom(existingEl);
17592     }
17593     if(!this.dom){
17594         var o = config.dh || {tag: "div", cls: "x-layer"};
17595         this.dom = dh.append(pel, o);
17596     }
17597     if(config.cls){
17598         this.addClass(config.cls);
17599     }
17600     this.constrain = config.constrain !== false;
17601     this.visibilityMode = Roo.Element.VISIBILITY;
17602     if(config.id){
17603         this.id = this.dom.id = config.id;
17604     }else{
17605         this.id = Roo.id(this.dom);
17606     }
17607     this.zindex = config.zindex || this.getZIndex();
17608     this.position("absolute", this.zindex);
17609     if(config.shadow){
17610         this.shadowOffset = config.shadowOffset || 4;
17611         this.shadow = new Roo.Shadow({
17612             offset : this.shadowOffset,
17613             mode : config.shadow
17614         });
17615     }else{
17616         this.shadowOffset = 0;
17617     }
17618     this.useShim = config.shim !== false && Roo.useShims;
17619     this.useDisplay = config.useDisplay;
17620     this.hide();
17621 };
17622
17623 var supr = Roo.Element.prototype;
17624
17625 // shims are shared among layer to keep from having 100 iframes
17626 var shims = [];
17627
17628 Roo.extend(Roo.Layer, Roo.Element, {
17629
17630     getZIndex : function(){
17631         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17632     },
17633
17634     getShim : function(){
17635         if(!this.useShim){
17636             return null;
17637         }
17638         if(this.shim){
17639             return this.shim;
17640         }
17641         var shim = shims.shift();
17642         if(!shim){
17643             shim = this.createShim();
17644             shim.enableDisplayMode('block');
17645             shim.dom.style.display = 'none';
17646             shim.dom.style.visibility = 'visible';
17647         }
17648         var pn = this.dom.parentNode;
17649         if(shim.dom.parentNode != pn){
17650             pn.insertBefore(shim.dom, this.dom);
17651         }
17652         shim.setStyle('z-index', this.getZIndex()-2);
17653         this.shim = shim;
17654         return shim;
17655     },
17656
17657     hideShim : function(){
17658         if(this.shim){
17659             this.shim.setDisplayed(false);
17660             shims.push(this.shim);
17661             delete this.shim;
17662         }
17663     },
17664
17665     disableShadow : function(){
17666         if(this.shadow){
17667             this.shadowDisabled = true;
17668             this.shadow.hide();
17669             this.lastShadowOffset = this.shadowOffset;
17670             this.shadowOffset = 0;
17671         }
17672     },
17673
17674     enableShadow : function(show){
17675         if(this.shadow){
17676             this.shadowDisabled = false;
17677             this.shadowOffset = this.lastShadowOffset;
17678             delete this.lastShadowOffset;
17679             if(show){
17680                 this.sync(true);
17681             }
17682         }
17683     },
17684
17685     // private
17686     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17687     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17688     sync : function(doShow){
17689         var sw = this.shadow;
17690         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17691             var sh = this.getShim();
17692
17693             var w = this.getWidth(),
17694                 h = this.getHeight();
17695
17696             var l = this.getLeft(true),
17697                 t = this.getTop(true);
17698
17699             if(sw && !this.shadowDisabled){
17700                 if(doShow && !sw.isVisible()){
17701                     sw.show(this);
17702                 }else{
17703                     sw.realign(l, t, w, h);
17704                 }
17705                 if(sh){
17706                     if(doShow){
17707                        sh.show();
17708                     }
17709                     // fit the shim behind the shadow, so it is shimmed too
17710                     var a = sw.adjusts, s = sh.dom.style;
17711                     s.left = (Math.min(l, l+a.l))+"px";
17712                     s.top = (Math.min(t, t+a.t))+"px";
17713                     s.width = (w+a.w)+"px";
17714                     s.height = (h+a.h)+"px";
17715                 }
17716             }else if(sh){
17717                 if(doShow){
17718                    sh.show();
17719                 }
17720                 sh.setSize(w, h);
17721                 sh.setLeftTop(l, t);
17722             }
17723             
17724         }
17725     },
17726
17727     // private
17728     destroy : function(){
17729         this.hideShim();
17730         if(this.shadow){
17731             this.shadow.hide();
17732         }
17733         this.removeAllListeners();
17734         var pn = this.dom.parentNode;
17735         if(pn){
17736             pn.removeChild(this.dom);
17737         }
17738         Roo.Element.uncache(this.id);
17739     },
17740
17741     remove : function(){
17742         this.destroy();
17743     },
17744
17745     // private
17746     beginUpdate : function(){
17747         this.updating = true;
17748     },
17749
17750     // private
17751     endUpdate : function(){
17752         this.updating = false;
17753         this.sync(true);
17754     },
17755
17756     // private
17757     hideUnders : function(negOffset){
17758         if(this.shadow){
17759             this.shadow.hide();
17760         }
17761         this.hideShim();
17762     },
17763
17764     // private
17765     constrainXY : function(){
17766         if(this.constrain){
17767             var vw = Roo.lib.Dom.getViewWidth(),
17768                 vh = Roo.lib.Dom.getViewHeight();
17769             var s = Roo.get(document).getScroll();
17770
17771             var xy = this.getXY();
17772             var x = xy[0], y = xy[1];   
17773             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17774             // only move it if it needs it
17775             var moved = false;
17776             // first validate right/bottom
17777             if((x + w) > vw+s.left){
17778                 x = vw - w - this.shadowOffset;
17779                 moved = true;
17780             }
17781             if((y + h) > vh+s.top){
17782                 y = vh - h - this.shadowOffset;
17783                 moved = true;
17784             }
17785             // then make sure top/left isn't negative
17786             if(x < s.left){
17787                 x = s.left;
17788                 moved = true;
17789             }
17790             if(y < s.top){
17791                 y = s.top;
17792                 moved = true;
17793             }
17794             if(moved){
17795                 if(this.avoidY){
17796                     var ay = this.avoidY;
17797                     if(y <= ay && (y+h) >= ay){
17798                         y = ay-h-5;   
17799                     }
17800                 }
17801                 xy = [x, y];
17802                 this.storeXY(xy);
17803                 supr.setXY.call(this, xy);
17804                 this.sync();
17805             }
17806         }
17807     },
17808
17809     isVisible : function(){
17810         return this.visible;    
17811     },
17812
17813     // private
17814     showAction : function(){
17815         this.visible = true; // track visibility to prevent getStyle calls
17816         if(this.useDisplay === true){
17817             this.setDisplayed("");
17818         }else if(this.lastXY){
17819             supr.setXY.call(this, this.lastXY);
17820         }else if(this.lastLT){
17821             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17822         }
17823     },
17824
17825     // private
17826     hideAction : function(){
17827         this.visible = false;
17828         if(this.useDisplay === true){
17829             this.setDisplayed(false);
17830         }else{
17831             this.setLeftTop(-10000,-10000);
17832         }
17833     },
17834
17835     // overridden Element method
17836     setVisible : function(v, a, d, c, e){
17837         if(v){
17838             this.showAction();
17839         }
17840         if(a && v){
17841             var cb = function(){
17842                 this.sync(true);
17843                 if(c){
17844                     c();
17845                 }
17846             }.createDelegate(this);
17847             supr.setVisible.call(this, true, true, d, cb, e);
17848         }else{
17849             if(!v){
17850                 this.hideUnders(true);
17851             }
17852             var cb = c;
17853             if(a){
17854                 cb = function(){
17855                     this.hideAction();
17856                     if(c){
17857                         c();
17858                     }
17859                 }.createDelegate(this);
17860             }
17861             supr.setVisible.call(this, v, a, d, cb, e);
17862             if(v){
17863                 this.sync(true);
17864             }else if(!a){
17865                 this.hideAction();
17866             }
17867         }
17868     },
17869
17870     storeXY : function(xy){
17871         delete this.lastLT;
17872         this.lastXY = xy;
17873     },
17874
17875     storeLeftTop : function(left, top){
17876         delete this.lastXY;
17877         this.lastLT = [left, top];
17878     },
17879
17880     // private
17881     beforeFx : function(){
17882         this.beforeAction();
17883         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17884     },
17885
17886     // private
17887     afterFx : function(){
17888         Roo.Layer.superclass.afterFx.apply(this, arguments);
17889         this.sync(this.isVisible());
17890     },
17891
17892     // private
17893     beforeAction : function(){
17894         if(!this.updating && this.shadow){
17895             this.shadow.hide();
17896         }
17897     },
17898
17899     // overridden Element method
17900     setLeft : function(left){
17901         this.storeLeftTop(left, this.getTop(true));
17902         supr.setLeft.apply(this, arguments);
17903         this.sync();
17904     },
17905
17906     setTop : function(top){
17907         this.storeLeftTop(this.getLeft(true), top);
17908         supr.setTop.apply(this, arguments);
17909         this.sync();
17910     },
17911
17912     setLeftTop : function(left, top){
17913         this.storeLeftTop(left, top);
17914         supr.setLeftTop.apply(this, arguments);
17915         this.sync();
17916     },
17917
17918     setXY : function(xy, a, d, c, e){
17919         this.fixDisplay();
17920         this.beforeAction();
17921         this.storeXY(xy);
17922         var cb = this.createCB(c);
17923         supr.setXY.call(this, xy, a, d, cb, e);
17924         if(!a){
17925             cb();
17926         }
17927     },
17928
17929     // private
17930     createCB : function(c){
17931         var el = this;
17932         return function(){
17933             el.constrainXY();
17934             el.sync(true);
17935             if(c){
17936                 c();
17937             }
17938         };
17939     },
17940
17941     // overridden Element method
17942     setX : function(x, a, d, c, e){
17943         this.setXY([x, this.getY()], a, d, c, e);
17944     },
17945
17946     // overridden Element method
17947     setY : function(y, a, d, c, e){
17948         this.setXY([this.getX(), y], a, d, c, e);
17949     },
17950
17951     // overridden Element method
17952     setSize : function(w, h, a, d, c, e){
17953         this.beforeAction();
17954         var cb = this.createCB(c);
17955         supr.setSize.call(this, w, h, a, d, cb, e);
17956         if(!a){
17957             cb();
17958         }
17959     },
17960
17961     // overridden Element method
17962     setWidth : function(w, a, d, c, e){
17963         this.beforeAction();
17964         var cb = this.createCB(c);
17965         supr.setWidth.call(this, w, a, d, cb, e);
17966         if(!a){
17967             cb();
17968         }
17969     },
17970
17971     // overridden Element method
17972     setHeight : function(h, a, d, c, e){
17973         this.beforeAction();
17974         var cb = this.createCB(c);
17975         supr.setHeight.call(this, h, a, d, cb, e);
17976         if(!a){
17977             cb();
17978         }
17979     },
17980
17981     // overridden Element method
17982     setBounds : function(x, y, w, h, a, d, c, e){
17983         this.beforeAction();
17984         var cb = this.createCB(c);
17985         if(!a){
17986             this.storeXY([x, y]);
17987             supr.setXY.call(this, [x, y]);
17988             supr.setSize.call(this, w, h, a, d, cb, e);
17989             cb();
17990         }else{
17991             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17992         }
17993         return this;
17994     },
17995     
17996     /**
17997      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17998      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17999      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
18000      * @param {Number} zindex The new z-index to set
18001      * @return {this} The Layer
18002      */
18003     setZIndex : function(zindex){
18004         this.zindex = zindex;
18005         this.setStyle("z-index", zindex + 2);
18006         if(this.shadow){
18007             this.shadow.setZIndex(zindex + 1);
18008         }
18009         if(this.shim){
18010             this.shim.setStyle("z-index", zindex);
18011         }
18012     }
18013 });
18014 })();/*
18015  * Original code for Roojs - LGPL
18016  * <script type="text/javascript">
18017  */
18018  
18019 /**
18020  * @class Roo.XComponent
18021  * A delayed Element creator...
18022  * Or a way to group chunks of interface together.
18023  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
18024  *  used in conjunction with XComponent.build() it will create an instance of each element,
18025  *  then call addxtype() to build the User interface.
18026  * 
18027  * Mypart.xyx = new Roo.XComponent({
18028
18029     parent : 'Mypart.xyz', // empty == document.element.!!
18030     order : '001',
18031     name : 'xxxx'
18032     region : 'xxxx'
18033     disabled : function() {} 
18034      
18035     tree : function() { // return an tree of xtype declared components
18036         var MODULE = this;
18037         return 
18038         {
18039             xtype : 'NestedLayoutPanel',
18040             // technicall
18041         }
18042      ]
18043  *})
18044  *
18045  *
18046  * It can be used to build a big heiracy, with parent etc.
18047  * or you can just use this to render a single compoent to a dom element
18048  * MYPART.render(Roo.Element | String(id) | dom_element )
18049  *
18050  *
18051  * Usage patterns.
18052  *
18053  * Classic Roo
18054  *
18055  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
18056  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
18057  *
18058  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
18059  *
18060  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
18061  * - if mulitple topModules exist, the last one is defined as the top module.
18062  *
18063  * Embeded Roo
18064  * 
18065  * When the top level or multiple modules are to embedded into a existing HTML page,
18066  * the parent element can container '#id' of the element where the module will be drawn.
18067  *
18068  * Bootstrap Roo
18069  *
18070  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
18071  * it relies more on a include mechanism, where sub modules are included into an outer page.
18072  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
18073  * 
18074  * Bootstrap Roo Included elements
18075  *
18076  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
18077  * hence confusing the component builder as it thinks there are multiple top level elements. 
18078  *
18079  * String Over-ride & Translations
18080  *
18081  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
18082  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
18083  * are needed. @see Roo.XComponent.overlayString  
18084  * 
18085  * 
18086  * 
18087  * @extends Roo.util.Observable
18088  * @constructor
18089  * @param cfg {Object} configuration of component
18090  * 
18091  */
18092 Roo.XComponent = function(cfg) {
18093     Roo.apply(this, cfg);
18094     this.addEvents({ 
18095         /**
18096              * @event built
18097              * Fires when this the componnt is built
18098              * @param {Roo.XComponent} c the component
18099              */
18100         'built' : true
18101         
18102     });
18103     this.region = this.region || 'center'; // default..
18104     Roo.XComponent.register(this);
18105     this.modules = false;
18106     this.el = false; // where the layout goes..
18107     
18108     
18109 }
18110 Roo.extend(Roo.XComponent, Roo.util.Observable, {
18111     /**
18112      * @property el
18113      * The created element (with Roo.factory())
18114      * @type {Roo.Layout}
18115      */
18116     el  : false,
18117     
18118     /**
18119      * @property el
18120      * for BC  - use el in new code
18121      * @type {Roo.Layout}
18122      */
18123     panel : false,
18124     
18125     /**
18126      * @property layout
18127      * for BC  - use el in new code
18128      * @type {Roo.Layout}
18129      */
18130     layout : false,
18131     
18132      /**
18133      * @cfg {Function|boolean} disabled
18134      * If this module is disabled by some rule, return true from the funtion
18135      */
18136     disabled : false,
18137     
18138     /**
18139      * @cfg {String} parent 
18140      * Name of parent element which it get xtype added to..
18141      */
18142     parent: false,
18143     
18144     /**
18145      * @cfg {String} order
18146      * Used to set the order in which elements are created (usefull for multiple tabs)
18147      */
18148     
18149     order : false,
18150     /**
18151      * @cfg {String} name
18152      * String to display while loading.
18153      */
18154     name : false,
18155     /**
18156      * @cfg {String} region
18157      * Region to render component to (defaults to center)
18158      */
18159     region : 'center',
18160     
18161     /**
18162      * @cfg {Array} items
18163      * A single item array - the first element is the root of the tree..
18164      * It's done this way to stay compatible with the Xtype system...
18165      */
18166     items : false,
18167     
18168     /**
18169      * @property _tree
18170      * The method that retuns the tree of parts that make up this compoennt 
18171      * @type {function}
18172      */
18173     _tree  : false,
18174     
18175      /**
18176      * render
18177      * render element to dom or tree
18178      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
18179      */
18180     
18181     render : function(el)
18182     {
18183         
18184         el = el || false;
18185         var hp = this.parent ? 1 : 0;
18186         Roo.debug &&  Roo.log(this);
18187         
18188         var tree = this._tree ? this._tree() : this.tree();
18189
18190         
18191         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
18192             // if parent is a '#.....' string, then let's use that..
18193             var ename = this.parent.substr(1);
18194             this.parent = false;
18195             Roo.debug && Roo.log(ename);
18196             switch (ename) {
18197                 case 'bootstrap-body':
18198                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
18199                         // this is the BorderLayout standard?
18200                        this.parent = { el : true };
18201                        break;
18202                     }
18203                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
18204                         // need to insert stuff...
18205                         this.parent =  {
18206                              el : new Roo.bootstrap.layout.Border({
18207                                  el : document.body, 
18208                      
18209                                  center: {
18210                                     titlebar: false,
18211                                     autoScroll:false,
18212                                     closeOnTab: true,
18213                                     tabPosition: 'top',
18214                                       //resizeTabs: true,
18215                                     alwaysShowTabs: true,
18216                                     hideTabs: false
18217                                      //minTabWidth: 140
18218                                  }
18219                              })
18220                         
18221                          };
18222                          break;
18223                     }
18224                          
18225                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18226                         this.parent = { el :  new  Roo.bootstrap.Body() };
18227                         Roo.debug && Roo.log("setting el to doc body");
18228                          
18229                     } else {
18230                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18231                     }
18232                     break;
18233                 case 'bootstrap':
18234                     this.parent = { el : true};
18235                     // fall through
18236                 default:
18237                     el = Roo.get(ename);
18238                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18239                         this.parent = { el : true};
18240                     }
18241                     
18242                     break;
18243             }
18244                 
18245             
18246             if (!el && !this.parent) {
18247                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18248                 return;
18249             }
18250         }
18251         
18252         Roo.debug && Roo.log("EL:");
18253         Roo.debug && Roo.log(el);
18254         Roo.debug && Roo.log("this.parent.el:");
18255         Roo.debug && Roo.log(this.parent.el);
18256         
18257
18258         // altertive root elements ??? - we need a better way to indicate these.
18259         var is_alt = Roo.XComponent.is_alt ||
18260                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18261                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18262                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18263         
18264         
18265         
18266         if (!this.parent && is_alt) {
18267             //el = Roo.get(document.body);
18268             this.parent = { el : true };
18269         }
18270             
18271             
18272         
18273         if (!this.parent) {
18274             
18275             Roo.debug && Roo.log("no parent - creating one");
18276             
18277             el = el ? Roo.get(el) : false;      
18278             
18279             if (typeof(Roo.BorderLayout) == 'undefined' ) {
18280                 
18281                 this.parent =  {
18282                     el : new Roo.bootstrap.layout.Border({
18283                         el: el || document.body,
18284                     
18285                         center: {
18286                             titlebar: false,
18287                             autoScroll:false,
18288                             closeOnTab: true,
18289                             tabPosition: 'top',
18290                              //resizeTabs: true,
18291                             alwaysShowTabs: false,
18292                             hideTabs: true,
18293                             minTabWidth: 140,
18294                             overflow: 'visible'
18295                          }
18296                      })
18297                 };
18298             } else {
18299             
18300                 // it's a top level one..
18301                 this.parent =  {
18302                     el : new Roo.BorderLayout(el || document.body, {
18303                         center: {
18304                             titlebar: false,
18305                             autoScroll:false,
18306                             closeOnTab: true,
18307                             tabPosition: 'top',
18308                              //resizeTabs: true,
18309                             alwaysShowTabs: el && hp? false :  true,
18310                             hideTabs: el || !hp ? true :  false,
18311                             minTabWidth: 140
18312                          }
18313                     })
18314                 };
18315             }
18316         }
18317         
18318         if (!this.parent.el) {
18319                 // probably an old style ctor, which has been disabled.
18320                 return;
18321
18322         }
18323                 // The 'tree' method is  '_tree now' 
18324             
18325         tree.region = tree.region || this.region;
18326         var is_body = false;
18327         if (this.parent.el === true) {
18328             // bootstrap... - body..
18329             if (el) {
18330                 tree.el = el;
18331             }
18332             this.parent.el = Roo.factory(tree);
18333             is_body = true;
18334         }
18335         
18336         this.el = this.parent.el.addxtype(tree, undefined, is_body);
18337         this.fireEvent('built', this);
18338         
18339         this.panel = this.el;
18340         this.layout = this.panel.layout;
18341         this.parentLayout = this.parent.layout  || false;  
18342          
18343     }
18344     
18345 });
18346
18347 Roo.apply(Roo.XComponent, {
18348     /**
18349      * @property  hideProgress
18350      * true to disable the building progress bar.. usefull on single page renders.
18351      * @type Boolean
18352      */
18353     hideProgress : false,
18354     /**
18355      * @property  buildCompleted
18356      * True when the builder has completed building the interface.
18357      * @type Boolean
18358      */
18359     buildCompleted : false,
18360      
18361     /**
18362      * @property  topModule
18363      * the upper most module - uses document.element as it's constructor.
18364      * @type Object
18365      */
18366      
18367     topModule  : false,
18368       
18369     /**
18370      * @property  modules
18371      * array of modules to be created by registration system.
18372      * @type {Array} of Roo.XComponent
18373      */
18374     
18375     modules : [],
18376     /**
18377      * @property  elmodules
18378      * array of modules to be created by which use #ID 
18379      * @type {Array} of Roo.XComponent
18380      */
18381      
18382     elmodules : [],
18383
18384      /**
18385      * @property  is_alt
18386      * Is an alternative Root - normally used by bootstrap or other systems,
18387      *    where the top element in the tree can wrap 'body' 
18388      * @type {boolean}  (default false)
18389      */
18390      
18391     is_alt : false,
18392     /**
18393      * @property  build_from_html
18394      * Build elements from html - used by bootstrap HTML stuff 
18395      *    - this is cleared after build is completed
18396      * @type {boolean}    (default false)
18397      */
18398      
18399     build_from_html : false,
18400     /**
18401      * Register components to be built later.
18402      *
18403      * This solves the following issues
18404      * - Building is not done on page load, but after an authentication process has occured.
18405      * - Interface elements are registered on page load
18406      * - Parent Interface elements may not be loaded before child, so this handles that..
18407      * 
18408      *
18409      * example:
18410      * 
18411      * MyApp.register({
18412           order : '000001',
18413           module : 'Pman.Tab.projectMgr',
18414           region : 'center',
18415           parent : 'Pman.layout',
18416           disabled : false,  // or use a function..
18417         })
18418      
18419      * * @param {Object} details about module
18420      */
18421     register : function(obj) {
18422                 
18423         Roo.XComponent.event.fireEvent('register', obj);
18424         switch(typeof(obj.disabled) ) {
18425                 
18426             case 'undefined':
18427                 break;
18428             
18429             case 'function':
18430                 if ( obj.disabled() ) {
18431                         return;
18432                 }
18433                 break;
18434             
18435             default:
18436                 if (obj.disabled || obj.region == '#disabled') {
18437                         return;
18438                 }
18439                 break;
18440         }
18441                 
18442         this.modules.push(obj);
18443          
18444     },
18445     /**
18446      * convert a string to an object..
18447      * eg. 'AAA.BBB' -> finds AAA.BBB
18448
18449      */
18450     
18451     toObject : function(str)
18452     {
18453         if (!str || typeof(str) == 'object') {
18454             return str;
18455         }
18456         if (str.substring(0,1) == '#') {
18457             return str;
18458         }
18459
18460         var ar = str.split('.');
18461         var rt, o;
18462         rt = ar.shift();
18463             /** eval:var:o */
18464         try {
18465             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18466         } catch (e) {
18467             throw "Module not found : " + str;
18468         }
18469         
18470         if (o === false) {
18471             throw "Module not found : " + str;
18472         }
18473         Roo.each(ar, function(e) {
18474             if (typeof(o[e]) == 'undefined') {
18475                 throw "Module not found : " + str;
18476             }
18477             o = o[e];
18478         });
18479         
18480         return o;
18481         
18482     },
18483     
18484     
18485     /**
18486      * move modules into their correct place in the tree..
18487      * 
18488      */
18489     preBuild : function ()
18490     {
18491         var _t = this;
18492         Roo.each(this.modules , function (obj)
18493         {
18494             Roo.XComponent.event.fireEvent('beforebuild', obj);
18495             
18496             var opar = obj.parent;
18497             try { 
18498                 obj.parent = this.toObject(opar);
18499             } catch(e) {
18500                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18501                 return;
18502             }
18503             
18504             if (!obj.parent) {
18505                 Roo.debug && Roo.log("GOT top level module");
18506                 Roo.debug && Roo.log(obj);
18507                 obj.modules = new Roo.util.MixedCollection(false, 
18508                     function(o) { return o.order + '' }
18509                 );
18510                 this.topModule = obj;
18511                 return;
18512             }
18513                         // parent is a string (usually a dom element name..)
18514             if (typeof(obj.parent) == 'string') {
18515                 this.elmodules.push(obj);
18516                 return;
18517             }
18518             if (obj.parent.constructor != Roo.XComponent) {
18519                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18520             }
18521             if (!obj.parent.modules) {
18522                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18523                     function(o) { return o.order + '' }
18524                 );
18525             }
18526             if (obj.parent.disabled) {
18527                 obj.disabled = true;
18528             }
18529             obj.parent.modules.add(obj);
18530         }, this);
18531     },
18532     
18533      /**
18534      * make a list of modules to build.
18535      * @return {Array} list of modules. 
18536      */ 
18537     
18538     buildOrder : function()
18539     {
18540         var _this = this;
18541         var cmp = function(a,b) {   
18542             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18543         };
18544         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18545             throw "No top level modules to build";
18546         }
18547         
18548         // make a flat list in order of modules to build.
18549         var mods = this.topModule ? [ this.topModule ] : [];
18550                 
18551         
18552         // elmodules (is a list of DOM based modules )
18553         Roo.each(this.elmodules, function(e) {
18554             mods.push(e);
18555             if (!this.topModule &&
18556                 typeof(e.parent) == 'string' &&
18557                 e.parent.substring(0,1) == '#' &&
18558                 Roo.get(e.parent.substr(1))
18559                ) {
18560                 
18561                 _this.topModule = e;
18562             }
18563             
18564         });
18565
18566         
18567         // add modules to their parents..
18568         var addMod = function(m) {
18569             Roo.debug && Roo.log("build Order: add: " + m.name);
18570                 
18571             mods.push(m);
18572             if (m.modules && !m.disabled) {
18573                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18574                 m.modules.keySort('ASC',  cmp );
18575                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18576     
18577                 m.modules.each(addMod);
18578             } else {
18579                 Roo.debug && Roo.log("build Order: no child modules");
18580             }
18581             // not sure if this is used any more..
18582             if (m.finalize) {
18583                 m.finalize.name = m.name + " (clean up) ";
18584                 mods.push(m.finalize);
18585             }
18586             
18587         }
18588         if (this.topModule && this.topModule.modules) { 
18589             this.topModule.modules.keySort('ASC',  cmp );
18590             this.topModule.modules.each(addMod);
18591         } 
18592         return mods;
18593     },
18594     
18595      /**
18596      * Build the registered modules.
18597      * @param {Object} parent element.
18598      * @param {Function} optional method to call after module has been added.
18599      * 
18600      */ 
18601    
18602     build : function(opts) 
18603     {
18604         
18605         if (typeof(opts) != 'undefined') {
18606             Roo.apply(this,opts);
18607         }
18608         
18609         this.preBuild();
18610         var mods = this.buildOrder();
18611       
18612         //this.allmods = mods;
18613         //Roo.debug && Roo.log(mods);
18614         //return;
18615         if (!mods.length) { // should not happen
18616             throw "NO modules!!!";
18617         }
18618         
18619         
18620         var msg = "Building Interface...";
18621         // flash it up as modal - so we store the mask!?
18622         if (!this.hideProgress && Roo.MessageBox) {
18623             Roo.MessageBox.show({ title: 'loading' });
18624             Roo.MessageBox.show({
18625                title: "Please wait...",
18626                msg: msg,
18627                width:450,
18628                progress:true,
18629                buttons : false,
18630                closable:false,
18631                modal: false
18632               
18633             });
18634         }
18635         var total = mods.length;
18636         
18637         var _this = this;
18638         var progressRun = function() {
18639             if (!mods.length) {
18640                 Roo.debug && Roo.log('hide?');
18641                 if (!this.hideProgress && Roo.MessageBox) {
18642                     Roo.MessageBox.hide();
18643                 }
18644                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18645                 
18646                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18647                 
18648                 // THE END...
18649                 return false;   
18650             }
18651             
18652             var m = mods.shift();
18653             
18654             
18655             Roo.debug && Roo.log(m);
18656             // not sure if this is supported any more.. - modules that are are just function
18657             if (typeof(m) == 'function') { 
18658                 m.call(this);
18659                 return progressRun.defer(10, _this);
18660             } 
18661             
18662             
18663             msg = "Building Interface " + (total  - mods.length) + 
18664                     " of " + total + 
18665                     (m.name ? (' - ' + m.name) : '');
18666                         Roo.debug && Roo.log(msg);
18667             if (!_this.hideProgress &&  Roo.MessageBox) { 
18668                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18669             }
18670             
18671          
18672             // is the module disabled?
18673             var disabled = (typeof(m.disabled) == 'function') ?
18674                 m.disabled.call(m.module.disabled) : m.disabled;    
18675             
18676             
18677             if (disabled) {
18678                 return progressRun(); // we do not update the display!
18679             }
18680             
18681             // now build 
18682             
18683                         
18684                         
18685             m.render();
18686             // it's 10 on top level, and 1 on others??? why...
18687             return progressRun.defer(10, _this);
18688              
18689         }
18690         progressRun.defer(1, _this);
18691      
18692         
18693         
18694     },
18695     /**
18696      * Overlay a set of modified strings onto a component
18697      * This is dependant on our builder exporting the strings and 'named strings' elements.
18698      * 
18699      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18700      * @param {Object} associative array of 'named' string and it's new value.
18701      * 
18702      */
18703         overlayStrings : function( component, strings )
18704     {
18705         if (typeof(component['_named_strings']) == 'undefined') {
18706             throw "ERROR: component does not have _named_strings";
18707         }
18708         for ( var k in strings ) {
18709             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18710             if (md !== false) {
18711                 component['_strings'][md] = strings[k];
18712             } else {
18713                 Roo.log('could not find named string: ' + k + ' in');
18714                 Roo.log(component);
18715             }
18716             
18717         }
18718         
18719     },
18720     
18721         
18722         /**
18723          * Event Object.
18724          *
18725          *
18726          */
18727         event: false, 
18728     /**
18729          * wrapper for event.on - aliased later..  
18730          * Typically use to register a event handler for register:
18731          *
18732          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18733          *
18734          */
18735     on : false
18736    
18737     
18738     
18739 });
18740
18741 Roo.XComponent.event = new Roo.util.Observable({
18742                 events : { 
18743                         /**
18744                          * @event register
18745                          * Fires when an Component is registered,
18746                          * set the disable property on the Component to stop registration.
18747                          * @param {Roo.XComponent} c the component being registerd.
18748                          * 
18749                          */
18750                         'register' : true,
18751             /**
18752                          * @event beforebuild
18753                          * Fires before each Component is built
18754                          * can be used to apply permissions.
18755                          * @param {Roo.XComponent} c the component being registerd.
18756                          * 
18757                          */
18758                         'beforebuild' : true,
18759                         /**
18760                          * @event buildcomplete
18761                          * Fires on the top level element when all elements have been built
18762                          * @param {Roo.XComponent} the top level component.
18763                          */
18764                         'buildcomplete' : true
18765                         
18766                 }
18767 });
18768
18769 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18770  //
18771  /**
18772  * marked - a markdown parser
18773  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18774  * https://github.com/chjj/marked
18775  */
18776
18777
18778 /**
18779  *
18780  * Roo.Markdown - is a very crude wrapper around marked..
18781  *
18782  * usage:
18783  * 
18784  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18785  * 
18786  * Note: move the sample code to the bottom of this
18787  * file before uncommenting it.
18788  *
18789  */
18790
18791 Roo.Markdown = {};
18792 Roo.Markdown.toHtml = function(text) {
18793     
18794     var c = new Roo.Markdown.marked.setOptions({
18795             renderer: new Roo.Markdown.marked.Renderer(),
18796             gfm: true,
18797             tables: true,
18798             breaks: false,
18799             pedantic: false,
18800             sanitize: false,
18801             smartLists: true,
18802             smartypants: false
18803           });
18804     // A FEW HACKS!!?
18805     
18806     text = text.replace(/\\\n/g,' ');
18807     return Roo.Markdown.marked(text);
18808 };
18809 //
18810 // converter
18811 //
18812 // Wraps all "globals" so that the only thing
18813 // exposed is makeHtml().
18814 //
18815 (function() {
18816     
18817      /**
18818          * eval:var:escape
18819          * eval:var:unescape
18820          * eval:var:replace
18821          */
18822       
18823     /**
18824      * Helpers
18825      */
18826     
18827     var escape = function (html, encode) {
18828       return html
18829         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18830         .replace(/</g, '&lt;')
18831         .replace(/>/g, '&gt;')
18832         .replace(/"/g, '&quot;')
18833         .replace(/'/g, '&#39;');
18834     }
18835     
18836     var unescape = function (html) {
18837         // explicitly match decimal, hex, and named HTML entities 
18838       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18839         n = n.toLowerCase();
18840         if (n === 'colon') { return ':'; }
18841         if (n.charAt(0) === '#') {
18842           return n.charAt(1) === 'x'
18843             ? String.fromCharCode(parseInt(n.substring(2), 16))
18844             : String.fromCharCode(+n.substring(1));
18845         }
18846         return '';
18847       });
18848     }
18849     
18850     var replace = function (regex, opt) {
18851       regex = regex.source;
18852       opt = opt || '';
18853       return function self(name, val) {
18854         if (!name) { return new RegExp(regex, opt); }
18855         val = val.source || val;
18856         val = val.replace(/(^|[^\[])\^/g, '$1');
18857         regex = regex.replace(name, val);
18858         return self;
18859       };
18860     }
18861
18862
18863          /**
18864          * eval:var:noop
18865     */
18866     var noop = function () {}
18867     noop.exec = noop;
18868     
18869          /**
18870          * eval:var:merge
18871     */
18872     var merge = function (obj) {
18873       var i = 1
18874         , target
18875         , key;
18876     
18877       for (; i < arguments.length; i++) {
18878         target = arguments[i];
18879         for (key in target) {
18880           if (Object.prototype.hasOwnProperty.call(target, key)) {
18881             obj[key] = target[key];
18882           }
18883         }
18884       }
18885     
18886       return obj;
18887     }
18888     
18889     
18890     /**
18891      * Block-Level Grammar
18892      */
18893     
18894     
18895     
18896     
18897     var block = {
18898       newline: /^\n+/,
18899       code: /^( {4}[^\n]+\n*)+/,
18900       fences: noop,
18901       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18902       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18903       nptable: noop,
18904       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18905       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18906       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18907       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18908       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18909       table: noop,
18910       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18911       text: /^[^\n]+/
18912     };
18913     
18914     block.bullet = /(?:[*+-]|\d+\.)/;
18915     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18916     block.item = replace(block.item, 'gm')
18917       (/bull/g, block.bullet)
18918       ();
18919     
18920     block.list = replace(block.list)
18921       (/bull/g, block.bullet)
18922       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18923       ('def', '\\n+(?=' + block.def.source + ')')
18924       ();
18925     
18926     block.blockquote = replace(block.blockquote)
18927       ('def', block.def)
18928       ();
18929     
18930     block._tag = '(?!(?:'
18931       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18932       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18933       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18934     
18935     block.html = replace(block.html)
18936       ('comment', /<!--[\s\S]*?-->/)
18937       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18938       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18939       (/tag/g, block._tag)
18940       ();
18941     
18942     block.paragraph = replace(block.paragraph)
18943       ('hr', block.hr)
18944       ('heading', block.heading)
18945       ('lheading', block.lheading)
18946       ('blockquote', block.blockquote)
18947       ('tag', '<' + block._tag)
18948       ('def', block.def)
18949       ();
18950     
18951     /**
18952      * Normal Block Grammar
18953      */
18954     
18955     block.normal = merge({}, block);
18956     
18957     /**
18958      * GFM Block Grammar
18959      */
18960     
18961     block.gfm = merge({}, block.normal, {
18962       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18963       paragraph: /^/,
18964       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18965     });
18966     
18967     block.gfm.paragraph = replace(block.paragraph)
18968       ('(?!', '(?!'
18969         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18970         + block.list.source.replace('\\1', '\\3') + '|')
18971       ();
18972     
18973     /**
18974      * GFM + Tables Block Grammar
18975      */
18976     
18977     block.tables = merge({}, block.gfm, {
18978       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18979       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18980     });
18981     
18982     /**
18983      * Block Lexer
18984      */
18985     
18986     var Lexer = function (options) {
18987       this.tokens = [];
18988       this.tokens.links = {};
18989       this.options = options || marked.defaults;
18990       this.rules = block.normal;
18991     
18992       if (this.options.gfm) {
18993         if (this.options.tables) {
18994           this.rules = block.tables;
18995         } else {
18996           this.rules = block.gfm;
18997         }
18998       }
18999     }
19000     
19001     /**
19002      * Expose Block Rules
19003      */
19004     
19005     Lexer.rules = block;
19006     
19007     /**
19008      * Static Lex Method
19009      */
19010     
19011     Lexer.lex = function(src, options) {
19012       var lexer = new Lexer(options);
19013       return lexer.lex(src);
19014     };
19015     
19016     /**
19017      * Preprocessing
19018      */
19019     
19020     Lexer.prototype.lex = function(src) {
19021       src = src
19022         .replace(/\r\n|\r/g, '\n')
19023         .replace(/\t/g, '    ')
19024         .replace(/\u00a0/g, ' ')
19025         .replace(/\u2424/g, '\n');
19026     
19027       return this.token(src, true);
19028     };
19029     
19030     /**
19031      * Lexing
19032      */
19033     
19034     Lexer.prototype.token = function(src, top, bq) {
19035       var src = src.replace(/^ +$/gm, '')
19036         , next
19037         , loose
19038         , cap
19039         , bull
19040         , b
19041         , item
19042         , space
19043         , i
19044         , l;
19045     
19046       while (src) {
19047         // newline
19048         if (cap = this.rules.newline.exec(src)) {
19049           src = src.substring(cap[0].length);
19050           if (cap[0].length > 1) {
19051             this.tokens.push({
19052               type: 'space'
19053             });
19054           }
19055         }
19056     
19057         // code
19058         if (cap = this.rules.code.exec(src)) {
19059           src = src.substring(cap[0].length);
19060           cap = cap[0].replace(/^ {4}/gm, '');
19061           this.tokens.push({
19062             type: 'code',
19063             text: !this.options.pedantic
19064               ? cap.replace(/\n+$/, '')
19065               : cap
19066           });
19067           continue;
19068         }
19069     
19070         // fences (gfm)
19071         if (cap = this.rules.fences.exec(src)) {
19072           src = src.substring(cap[0].length);
19073           this.tokens.push({
19074             type: 'code',
19075             lang: cap[2],
19076             text: cap[3] || ''
19077           });
19078           continue;
19079         }
19080     
19081         // heading
19082         if (cap = this.rules.heading.exec(src)) {
19083           src = src.substring(cap[0].length);
19084           this.tokens.push({
19085             type: 'heading',
19086             depth: cap[1].length,
19087             text: cap[2]
19088           });
19089           continue;
19090         }
19091     
19092         // table no leading pipe (gfm)
19093         if (top && (cap = this.rules.nptable.exec(src))) {
19094           src = src.substring(cap[0].length);
19095     
19096           item = {
19097             type: 'table',
19098             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19099             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19100             cells: cap[3].replace(/\n$/, '').split('\n')
19101           };
19102     
19103           for (i = 0; i < item.align.length; i++) {
19104             if (/^ *-+: *$/.test(item.align[i])) {
19105               item.align[i] = 'right';
19106             } else if (/^ *:-+: *$/.test(item.align[i])) {
19107               item.align[i] = 'center';
19108             } else if (/^ *:-+ *$/.test(item.align[i])) {
19109               item.align[i] = 'left';
19110             } else {
19111               item.align[i] = null;
19112             }
19113           }
19114     
19115           for (i = 0; i < item.cells.length; i++) {
19116             item.cells[i] = item.cells[i].split(/ *\| */);
19117           }
19118     
19119           this.tokens.push(item);
19120     
19121           continue;
19122         }
19123     
19124         // lheading
19125         if (cap = this.rules.lheading.exec(src)) {
19126           src = src.substring(cap[0].length);
19127           this.tokens.push({
19128             type: 'heading',
19129             depth: cap[2] === '=' ? 1 : 2,
19130             text: cap[1]
19131           });
19132           continue;
19133         }
19134     
19135         // hr
19136         if (cap = this.rules.hr.exec(src)) {
19137           src = src.substring(cap[0].length);
19138           this.tokens.push({
19139             type: 'hr'
19140           });
19141           continue;
19142         }
19143     
19144         // blockquote
19145         if (cap = this.rules.blockquote.exec(src)) {
19146           src = src.substring(cap[0].length);
19147     
19148           this.tokens.push({
19149             type: 'blockquote_start'
19150           });
19151     
19152           cap = cap[0].replace(/^ *> ?/gm, '');
19153     
19154           // Pass `top` to keep the current
19155           // "toplevel" state. This is exactly
19156           // how markdown.pl works.
19157           this.token(cap, top, true);
19158     
19159           this.tokens.push({
19160             type: 'blockquote_end'
19161           });
19162     
19163           continue;
19164         }
19165     
19166         // list
19167         if (cap = this.rules.list.exec(src)) {
19168           src = src.substring(cap[0].length);
19169           bull = cap[2];
19170     
19171           this.tokens.push({
19172             type: 'list_start',
19173             ordered: bull.length > 1
19174           });
19175     
19176           // Get each top-level item.
19177           cap = cap[0].match(this.rules.item);
19178     
19179           next = false;
19180           l = cap.length;
19181           i = 0;
19182     
19183           for (; i < l; i++) {
19184             item = cap[i];
19185     
19186             // Remove the list item's bullet
19187             // so it is seen as the next token.
19188             space = item.length;
19189             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19190     
19191             // Outdent whatever the
19192             // list item contains. Hacky.
19193             if (~item.indexOf('\n ')) {
19194               space -= item.length;
19195               item = !this.options.pedantic
19196                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19197                 : item.replace(/^ {1,4}/gm, '');
19198             }
19199     
19200             // Determine whether the next list item belongs here.
19201             // Backpedal if it does not belong in this list.
19202             if (this.options.smartLists && i !== l - 1) {
19203               b = block.bullet.exec(cap[i + 1])[0];
19204               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19205                 src = cap.slice(i + 1).join('\n') + src;
19206                 i = l - 1;
19207               }
19208             }
19209     
19210             // Determine whether item is loose or not.
19211             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19212             // for discount behavior.
19213             loose = next || /\n\n(?!\s*$)/.test(item);
19214             if (i !== l - 1) {
19215               next = item.charAt(item.length - 1) === '\n';
19216               if (!loose) { loose = next; }
19217             }
19218     
19219             this.tokens.push({
19220               type: loose
19221                 ? 'loose_item_start'
19222                 : 'list_item_start'
19223             });
19224     
19225             // Recurse.
19226             this.token(item, false, bq);
19227     
19228             this.tokens.push({
19229               type: 'list_item_end'
19230             });
19231           }
19232     
19233           this.tokens.push({
19234             type: 'list_end'
19235           });
19236     
19237           continue;
19238         }
19239     
19240         // html
19241         if (cap = this.rules.html.exec(src)) {
19242           src = src.substring(cap[0].length);
19243           this.tokens.push({
19244             type: this.options.sanitize
19245               ? 'paragraph'
19246               : 'html',
19247             pre: !this.options.sanitizer
19248               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19249             text: cap[0]
19250           });
19251           continue;
19252         }
19253     
19254         // def
19255         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19256           src = src.substring(cap[0].length);
19257           this.tokens.links[cap[1].toLowerCase()] = {
19258             href: cap[2],
19259             title: cap[3]
19260           };
19261           continue;
19262         }
19263     
19264         // table (gfm)
19265         if (top && (cap = this.rules.table.exec(src))) {
19266           src = src.substring(cap[0].length);
19267     
19268           item = {
19269             type: 'table',
19270             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19271             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19272             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19273           };
19274     
19275           for (i = 0; i < item.align.length; i++) {
19276             if (/^ *-+: *$/.test(item.align[i])) {
19277               item.align[i] = 'right';
19278             } else if (/^ *:-+: *$/.test(item.align[i])) {
19279               item.align[i] = 'center';
19280             } else if (/^ *:-+ *$/.test(item.align[i])) {
19281               item.align[i] = 'left';
19282             } else {
19283               item.align[i] = null;
19284             }
19285           }
19286     
19287           for (i = 0; i < item.cells.length; i++) {
19288             item.cells[i] = item.cells[i]
19289               .replace(/^ *\| *| *\| *$/g, '')
19290               .split(/ *\| */);
19291           }
19292     
19293           this.tokens.push(item);
19294     
19295           continue;
19296         }
19297     
19298         // top-level paragraph
19299         if (top && (cap = this.rules.paragraph.exec(src))) {
19300           src = src.substring(cap[0].length);
19301           this.tokens.push({
19302             type: 'paragraph',
19303             text: cap[1].charAt(cap[1].length - 1) === '\n'
19304               ? cap[1].slice(0, -1)
19305               : cap[1]
19306           });
19307           continue;
19308         }
19309     
19310         // text
19311         if (cap = this.rules.text.exec(src)) {
19312           // Top-level should never reach here.
19313           src = src.substring(cap[0].length);
19314           this.tokens.push({
19315             type: 'text',
19316             text: cap[0]
19317           });
19318           continue;
19319         }
19320     
19321         if (src) {
19322           throw new
19323             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19324         }
19325       }
19326     
19327       return this.tokens;
19328     };
19329     
19330     /**
19331      * Inline-Level Grammar
19332      */
19333     
19334     var inline = {
19335       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19336       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19337       url: noop,
19338       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19339       link: /^!?\[(inside)\]\(href\)/,
19340       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19341       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19342       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19343       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19344       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19345       br: /^ {2,}\n(?!\s*$)/,
19346       del: noop,
19347       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19348     };
19349     
19350     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19351     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19352     
19353     inline.link = replace(inline.link)
19354       ('inside', inline._inside)
19355       ('href', inline._href)
19356       ();
19357     
19358     inline.reflink = replace(inline.reflink)
19359       ('inside', inline._inside)
19360       ();
19361     
19362     /**
19363      * Normal Inline Grammar
19364      */
19365     
19366     inline.normal = merge({}, inline);
19367     
19368     /**
19369      * Pedantic Inline Grammar
19370      */
19371     
19372     inline.pedantic = merge({}, inline.normal, {
19373       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19374       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19375     });
19376     
19377     /**
19378      * GFM Inline Grammar
19379      */
19380     
19381     inline.gfm = merge({}, inline.normal, {
19382       escape: replace(inline.escape)('])', '~|])')(),
19383       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19384       del: /^~~(?=\S)([\s\S]*?\S)~~/,
19385       text: replace(inline.text)
19386         (']|', '~]|')
19387         ('|', '|https?://|')
19388         ()
19389     });
19390     
19391     /**
19392      * GFM + Line Breaks Inline Grammar
19393      */
19394     
19395     inline.breaks = merge({}, inline.gfm, {
19396       br: replace(inline.br)('{2,}', '*')(),
19397       text: replace(inline.gfm.text)('{2,}', '*')()
19398     });
19399     
19400     /**
19401      * Inline Lexer & Compiler
19402      */
19403     
19404     var InlineLexer  = function (links, options) {
19405       this.options = options || marked.defaults;
19406       this.links = links;
19407       this.rules = inline.normal;
19408       this.renderer = this.options.renderer || new Renderer;
19409       this.renderer.options = this.options;
19410     
19411       if (!this.links) {
19412         throw new
19413           Error('Tokens array requires a `links` property.');
19414       }
19415     
19416       if (this.options.gfm) {
19417         if (this.options.breaks) {
19418           this.rules = inline.breaks;
19419         } else {
19420           this.rules = inline.gfm;
19421         }
19422       } else if (this.options.pedantic) {
19423         this.rules = inline.pedantic;
19424       }
19425     }
19426     
19427     /**
19428      * Expose Inline Rules
19429      */
19430     
19431     InlineLexer.rules = inline;
19432     
19433     /**
19434      * Static Lexing/Compiling Method
19435      */
19436     
19437     InlineLexer.output = function(src, links, options) {
19438       var inline = new InlineLexer(links, options);
19439       return inline.output(src);
19440     };
19441     
19442     /**
19443      * Lexing/Compiling
19444      */
19445     
19446     InlineLexer.prototype.output = function(src) {
19447       var out = ''
19448         , link
19449         , text
19450         , href
19451         , cap;
19452     
19453       while (src) {
19454         // escape
19455         if (cap = this.rules.escape.exec(src)) {
19456           src = src.substring(cap[0].length);
19457           out += cap[1];
19458           continue;
19459         }
19460     
19461         // autolink
19462         if (cap = this.rules.autolink.exec(src)) {
19463           src = src.substring(cap[0].length);
19464           if (cap[2] === '@') {
19465             text = cap[1].charAt(6) === ':'
19466               ? this.mangle(cap[1].substring(7))
19467               : this.mangle(cap[1]);
19468             href = this.mangle('mailto:') + text;
19469           } else {
19470             text = escape(cap[1]);
19471             href = text;
19472           }
19473           out += this.renderer.link(href, null, text);
19474           continue;
19475         }
19476     
19477         // url (gfm)
19478         if (!this.inLink && (cap = this.rules.url.exec(src))) {
19479           src = src.substring(cap[0].length);
19480           text = escape(cap[1]);
19481           href = text;
19482           out += this.renderer.link(href, null, text);
19483           continue;
19484         }
19485     
19486         // tag
19487         if (cap = this.rules.tag.exec(src)) {
19488           if (!this.inLink && /^<a /i.test(cap[0])) {
19489             this.inLink = true;
19490           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19491             this.inLink = false;
19492           }
19493           src = src.substring(cap[0].length);
19494           out += this.options.sanitize
19495             ? this.options.sanitizer
19496               ? this.options.sanitizer(cap[0])
19497               : escape(cap[0])
19498             : cap[0];
19499           continue;
19500         }
19501     
19502         // link
19503         if (cap = this.rules.link.exec(src)) {
19504           src = src.substring(cap[0].length);
19505           this.inLink = true;
19506           out += this.outputLink(cap, {
19507             href: cap[2],
19508             title: cap[3]
19509           });
19510           this.inLink = false;
19511           continue;
19512         }
19513     
19514         // reflink, nolink
19515         if ((cap = this.rules.reflink.exec(src))
19516             || (cap = this.rules.nolink.exec(src))) {
19517           src = src.substring(cap[0].length);
19518           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19519           link = this.links[link.toLowerCase()];
19520           if (!link || !link.href) {
19521             out += cap[0].charAt(0);
19522             src = cap[0].substring(1) + src;
19523             continue;
19524           }
19525           this.inLink = true;
19526           out += this.outputLink(cap, link);
19527           this.inLink = false;
19528           continue;
19529         }
19530     
19531         // strong
19532         if (cap = this.rules.strong.exec(src)) {
19533           src = src.substring(cap[0].length);
19534           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19535           continue;
19536         }
19537     
19538         // em
19539         if (cap = this.rules.em.exec(src)) {
19540           src = src.substring(cap[0].length);
19541           out += this.renderer.em(this.output(cap[2] || cap[1]));
19542           continue;
19543         }
19544     
19545         // code
19546         if (cap = this.rules.code.exec(src)) {
19547           src = src.substring(cap[0].length);
19548           out += this.renderer.codespan(escape(cap[2], true));
19549           continue;
19550         }
19551     
19552         // br
19553         if (cap = this.rules.br.exec(src)) {
19554           src = src.substring(cap[0].length);
19555           out += this.renderer.br();
19556           continue;
19557         }
19558     
19559         // del (gfm)
19560         if (cap = this.rules.del.exec(src)) {
19561           src = src.substring(cap[0].length);
19562           out += this.renderer.del(this.output(cap[1]));
19563           continue;
19564         }
19565     
19566         // text
19567         if (cap = this.rules.text.exec(src)) {
19568           src = src.substring(cap[0].length);
19569           out += this.renderer.text(escape(this.smartypants(cap[0])));
19570           continue;
19571         }
19572     
19573         if (src) {
19574           throw new
19575             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19576         }
19577       }
19578     
19579       return out;
19580     };
19581     
19582     /**
19583      * Compile Link
19584      */
19585     
19586     InlineLexer.prototype.outputLink = function(cap, link) {
19587       var href = escape(link.href)
19588         , title = link.title ? escape(link.title) : null;
19589     
19590       return cap[0].charAt(0) !== '!'
19591         ? this.renderer.link(href, title, this.output(cap[1]))
19592         : this.renderer.image(href, title, escape(cap[1]));
19593     };
19594     
19595     /**
19596      * Smartypants Transformations
19597      */
19598     
19599     InlineLexer.prototype.smartypants = function(text) {
19600       if (!this.options.smartypants)  { return text; }
19601       return text
19602         // em-dashes
19603         .replace(/---/g, '\u2014')
19604         // en-dashes
19605         .replace(/--/g, '\u2013')
19606         // opening singles
19607         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19608         // closing singles & apostrophes
19609         .replace(/'/g, '\u2019')
19610         // opening doubles
19611         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19612         // closing doubles
19613         .replace(/"/g, '\u201d')
19614         // ellipses
19615         .replace(/\.{3}/g, '\u2026');
19616     };
19617     
19618     /**
19619      * Mangle Links
19620      */
19621     
19622     InlineLexer.prototype.mangle = function(text) {
19623       if (!this.options.mangle) { return text; }
19624       var out = ''
19625         , l = text.length
19626         , i = 0
19627         , ch;
19628     
19629       for (; i < l; i++) {
19630         ch = text.charCodeAt(i);
19631         if (Math.random() > 0.5) {
19632           ch = 'x' + ch.toString(16);
19633         }
19634         out += '&#' + ch + ';';
19635       }
19636     
19637       return out;
19638     };
19639     
19640     /**
19641      * Renderer
19642      */
19643     
19644      /**
19645          * eval:var:Renderer
19646     */
19647     
19648     var Renderer   = function (options) {
19649       this.options = options || {};
19650     }
19651     
19652     Renderer.prototype.code = function(code, lang, escaped) {
19653       if (this.options.highlight) {
19654         var out = this.options.highlight(code, lang);
19655         if (out != null && out !== code) {
19656           escaped = true;
19657           code = out;
19658         }
19659       } else {
19660             // hack!!! - it's already escapeD?
19661             escaped = true;
19662       }
19663     
19664       if (!lang) {
19665         return '<pre><code>'
19666           + (escaped ? code : escape(code, true))
19667           + '\n</code></pre>';
19668       }
19669     
19670       return '<pre><code class="'
19671         + this.options.langPrefix
19672         + escape(lang, true)
19673         + '">'
19674         + (escaped ? code : escape(code, true))
19675         + '\n</code></pre>\n';
19676     };
19677     
19678     Renderer.prototype.blockquote = function(quote) {
19679       return '<blockquote>\n' + quote + '</blockquote>\n';
19680     };
19681     
19682     Renderer.prototype.html = function(html) {
19683       return html;
19684     };
19685     
19686     Renderer.prototype.heading = function(text, level, raw) {
19687       return '<h'
19688         + level
19689         + ' id="'
19690         + this.options.headerPrefix
19691         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19692         + '">'
19693         + text
19694         + '</h'
19695         + level
19696         + '>\n';
19697     };
19698     
19699     Renderer.prototype.hr = function() {
19700       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19701     };
19702     
19703     Renderer.prototype.list = function(body, ordered) {
19704       var type = ordered ? 'ol' : 'ul';
19705       return '<' + type + '>\n' + body + '</' + type + '>\n';
19706     };
19707     
19708     Renderer.prototype.listitem = function(text) {
19709       return '<li>' + text + '</li>\n';
19710     };
19711     
19712     Renderer.prototype.paragraph = function(text) {
19713       return '<p>' + text + '</p>\n';
19714     };
19715     
19716     Renderer.prototype.table = function(header, body) {
19717       return '<table class="table table-striped">\n'
19718         + '<thead>\n'
19719         + header
19720         + '</thead>\n'
19721         + '<tbody>\n'
19722         + body
19723         + '</tbody>\n'
19724         + '</table>\n';
19725     };
19726     
19727     Renderer.prototype.tablerow = function(content) {
19728       return '<tr>\n' + content + '</tr>\n';
19729     };
19730     
19731     Renderer.prototype.tablecell = function(content, flags) {
19732       var type = flags.header ? 'th' : 'td';
19733       var tag = flags.align
19734         ? '<' + type + ' style="text-align:' + flags.align + '">'
19735         : '<' + type + '>';
19736       return tag + content + '</' + type + '>\n';
19737     };
19738     
19739     // span level renderer
19740     Renderer.prototype.strong = function(text) {
19741       return '<strong>' + text + '</strong>';
19742     };
19743     
19744     Renderer.prototype.em = function(text) {
19745       return '<em>' + text + '</em>';
19746     };
19747     
19748     Renderer.prototype.codespan = function(text) {
19749       return '<code>' + text + '</code>';
19750     };
19751     
19752     Renderer.prototype.br = function() {
19753       return this.options.xhtml ? '<br/>' : '<br>';
19754     };
19755     
19756     Renderer.prototype.del = function(text) {
19757       return '<del>' + text + '</del>';
19758     };
19759     
19760     Renderer.prototype.link = function(href, title, text) {
19761       if (this.options.sanitize) {
19762         try {
19763           var prot = decodeURIComponent(unescape(href))
19764             .replace(/[^\w:]/g, '')
19765             .toLowerCase();
19766         } catch (e) {
19767           return '';
19768         }
19769         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19770           return '';
19771         }
19772       }
19773       var out = '<a href="' + href + '"';
19774       if (title) {
19775         out += ' title="' + title + '"';
19776       }
19777       out += '>' + text + '</a>';
19778       return out;
19779     };
19780     
19781     Renderer.prototype.image = function(href, title, text) {
19782       var out = '<img src="' + href + '" alt="' + text + '"';
19783       if (title) {
19784         out += ' title="' + title + '"';
19785       }
19786       out += this.options.xhtml ? '/>' : '>';
19787       return out;
19788     };
19789     
19790     Renderer.prototype.text = function(text) {
19791       return text;
19792     };
19793     
19794     /**
19795      * Parsing & Compiling
19796      */
19797          /**
19798          * eval:var:Parser
19799     */
19800     
19801     var Parser= function (options) {
19802       this.tokens = [];
19803       this.token = null;
19804       this.options = options || marked.defaults;
19805       this.options.renderer = this.options.renderer || new Renderer;
19806       this.renderer = this.options.renderer;
19807       this.renderer.options = this.options;
19808     }
19809     
19810     /**
19811      * Static Parse Method
19812      */
19813     
19814     Parser.parse = function(src, options, renderer) {
19815       var parser = new Parser(options, renderer);
19816       return parser.parse(src);
19817     };
19818     
19819     /**
19820      * Parse Loop
19821      */
19822     
19823     Parser.prototype.parse = function(src) {
19824       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19825       this.tokens = src.reverse();
19826     
19827       var out = '';
19828       while (this.next()) {
19829         out += this.tok();
19830       }
19831     
19832       return out;
19833     };
19834     
19835     /**
19836      * Next Token
19837      */
19838     
19839     Parser.prototype.next = function() {
19840       return this.token = this.tokens.pop();
19841     };
19842     
19843     /**
19844      * Preview Next Token
19845      */
19846     
19847     Parser.prototype.peek = function() {
19848       return this.tokens[this.tokens.length - 1] || 0;
19849     };
19850     
19851     /**
19852      * Parse Text Tokens
19853      */
19854     
19855     Parser.prototype.parseText = function() {
19856       var body = this.token.text;
19857     
19858       while (this.peek().type === 'text') {
19859         body += '\n' + this.next().text;
19860       }
19861     
19862       return this.inline.output(body);
19863     };
19864     
19865     /**
19866      * Parse Current Token
19867      */
19868     
19869     Parser.prototype.tok = function() {
19870       switch (this.token.type) {
19871         case 'space': {
19872           return '';
19873         }
19874         case 'hr': {
19875           return this.renderer.hr();
19876         }
19877         case 'heading': {
19878           return this.renderer.heading(
19879             this.inline.output(this.token.text),
19880             this.token.depth,
19881             this.token.text);
19882         }
19883         case 'code': {
19884           return this.renderer.code(this.token.text,
19885             this.token.lang,
19886             this.token.escaped);
19887         }
19888         case 'table': {
19889           var header = ''
19890             , body = ''
19891             , i
19892             , row
19893             , cell
19894             , flags
19895             , j;
19896     
19897           // header
19898           cell = '';
19899           for (i = 0; i < this.token.header.length; i++) {
19900             flags = { header: true, align: this.token.align[i] };
19901             cell += this.renderer.tablecell(
19902               this.inline.output(this.token.header[i]),
19903               { header: true, align: this.token.align[i] }
19904             );
19905           }
19906           header += this.renderer.tablerow(cell);
19907     
19908           for (i = 0; i < this.token.cells.length; i++) {
19909             row = this.token.cells[i];
19910     
19911             cell = '';
19912             for (j = 0; j < row.length; j++) {
19913               cell += this.renderer.tablecell(
19914                 this.inline.output(row[j]),
19915                 { header: false, align: this.token.align[j] }
19916               );
19917             }
19918     
19919             body += this.renderer.tablerow(cell);
19920           }
19921           return this.renderer.table(header, body);
19922         }
19923         case 'blockquote_start': {
19924           var body = '';
19925     
19926           while (this.next().type !== 'blockquote_end') {
19927             body += this.tok();
19928           }
19929     
19930           return this.renderer.blockquote(body);
19931         }
19932         case 'list_start': {
19933           var body = ''
19934             , ordered = this.token.ordered;
19935     
19936           while (this.next().type !== 'list_end') {
19937             body += this.tok();
19938           }
19939     
19940           return this.renderer.list(body, ordered);
19941         }
19942         case 'list_item_start': {
19943           var body = '';
19944     
19945           while (this.next().type !== 'list_item_end') {
19946             body += this.token.type === 'text'
19947               ? this.parseText()
19948               : this.tok();
19949           }
19950     
19951           return this.renderer.listitem(body);
19952         }
19953         case 'loose_item_start': {
19954           var body = '';
19955     
19956           while (this.next().type !== 'list_item_end') {
19957             body += this.tok();
19958           }
19959     
19960           return this.renderer.listitem(body);
19961         }
19962         case 'html': {
19963           var html = !this.token.pre && !this.options.pedantic
19964             ? this.inline.output(this.token.text)
19965             : this.token.text;
19966           return this.renderer.html(html);
19967         }
19968         case 'paragraph': {
19969           return this.renderer.paragraph(this.inline.output(this.token.text));
19970         }
19971         case 'text': {
19972           return this.renderer.paragraph(this.parseText());
19973         }
19974       }
19975     };
19976   
19977     
19978     /**
19979      * Marked
19980      */
19981          /**
19982          * eval:var:marked
19983     */
19984     var marked = function (src, opt, callback) {
19985       if (callback || typeof opt === 'function') {
19986         if (!callback) {
19987           callback = opt;
19988           opt = null;
19989         }
19990     
19991         opt = merge({}, marked.defaults, opt || {});
19992     
19993         var highlight = opt.highlight
19994           , tokens
19995           , pending
19996           , i = 0;
19997     
19998         try {
19999           tokens = Lexer.lex(src, opt)
20000         } catch (e) {
20001           return callback(e);
20002         }
20003     
20004         pending = tokens.length;
20005          /**
20006          * eval:var:done
20007     */
20008         var done = function(err) {
20009           if (err) {
20010             opt.highlight = highlight;
20011             return callback(err);
20012           }
20013     
20014           var out;
20015     
20016           try {
20017             out = Parser.parse(tokens, opt);
20018           } catch (e) {
20019             err = e;
20020           }
20021     
20022           opt.highlight = highlight;
20023     
20024           return err
20025             ? callback(err)
20026             : callback(null, out);
20027         };
20028     
20029         if (!highlight || highlight.length < 3) {
20030           return done();
20031         }
20032     
20033         delete opt.highlight;
20034     
20035         if (!pending) { return done(); }
20036     
20037         for (; i < tokens.length; i++) {
20038           (function(token) {
20039             if (token.type !== 'code') {
20040               return --pending || done();
20041             }
20042             return highlight(token.text, token.lang, function(err, code) {
20043               if (err) { return done(err); }
20044               if (code == null || code === token.text) {
20045                 return --pending || done();
20046               }
20047               token.text = code;
20048               token.escaped = true;
20049               --pending || done();
20050             });
20051           })(tokens[i]);
20052         }
20053     
20054         return;
20055       }
20056       try {
20057         if (opt) { opt = merge({}, marked.defaults, opt); }
20058         return Parser.parse(Lexer.lex(src, opt), opt);
20059       } catch (e) {
20060         e.message += '\nPlease report this to https://github.com/chjj/marked.';
20061         if ((opt || marked.defaults).silent) {
20062           return '<p>An error occured:</p><pre>'
20063             + escape(e.message + '', true)
20064             + '</pre>';
20065         }
20066         throw e;
20067       }
20068     }
20069     
20070     /**
20071      * Options
20072      */
20073     
20074     marked.options =
20075     marked.setOptions = function(opt) {
20076       merge(marked.defaults, opt);
20077       return marked;
20078     };
20079     
20080     marked.defaults = {
20081       gfm: true,
20082       tables: true,
20083       breaks: false,
20084       pedantic: false,
20085       sanitize: false,
20086       sanitizer: null,
20087       mangle: true,
20088       smartLists: false,
20089       silent: false,
20090       highlight: null,
20091       langPrefix: 'lang-',
20092       smartypants: false,
20093       headerPrefix: '',
20094       renderer: new Renderer,
20095       xhtml: false
20096     };
20097     
20098     /**
20099      * Expose
20100      */
20101     
20102     marked.Parser = Parser;
20103     marked.parser = Parser.parse;
20104     
20105     marked.Renderer = Renderer;
20106     
20107     marked.Lexer = Lexer;
20108     marked.lexer = Lexer.lex;
20109     
20110     marked.InlineLexer = InlineLexer;
20111     marked.inlineLexer = InlineLexer.output;
20112     
20113     marked.parse = marked;
20114     
20115     Roo.Markdown.marked = marked;
20116
20117 })();/*
20118  * Based on:
20119  * Ext JS Library 1.1.1
20120  * Copyright(c) 2006-2007, Ext JS, LLC.
20121  *
20122  * Originally Released Under LGPL - original licence link has changed is not relivant.
20123  *
20124  * Fork - LGPL
20125  * <script type="text/javascript">
20126  */
20127
20128
20129
20130 /*
20131  * These classes are derivatives of the similarly named classes in the YUI Library.
20132  * The original license:
20133  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
20134  * Code licensed under the BSD License:
20135  * http://developer.yahoo.net/yui/license.txt
20136  */
20137
20138 (function() {
20139
20140 var Event=Roo.EventManager;
20141 var Dom=Roo.lib.Dom;
20142
20143 /**
20144  * @class Roo.dd.DragDrop
20145  * @extends Roo.util.Observable
20146  * Defines the interface and base operation of items that that can be
20147  * dragged or can be drop targets.  It was designed to be extended, overriding
20148  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
20149  * Up to three html elements can be associated with a DragDrop instance:
20150  * <ul>
20151  * <li>linked element: the element that is passed into the constructor.
20152  * This is the element which defines the boundaries for interaction with
20153  * other DragDrop objects.</li>
20154  * <li>handle element(s): The drag operation only occurs if the element that
20155  * was clicked matches a handle element.  By default this is the linked
20156  * element, but there are times that you will want only a portion of the
20157  * linked element to initiate the drag operation, and the setHandleElId()
20158  * method provides a way to define this.</li>
20159  * <li>drag element: this represents the element that would be moved along
20160  * with the cursor during a drag operation.  By default, this is the linked
20161  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
20162  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
20163  * </li>
20164  * </ul>
20165  * This class should not be instantiated until the onload event to ensure that
20166  * the associated elements are available.
20167  * The following would define a DragDrop obj that would interact with any
20168  * other DragDrop obj in the "group1" group:
20169  * <pre>
20170  *  dd = new Roo.dd.DragDrop("div1", "group1");
20171  * </pre>
20172  * Since none of the event handlers have been implemented, nothing would
20173  * actually happen if you were to run the code above.  Normally you would
20174  * override this class or one of the default implementations, but you can
20175  * also override the methods you want on an instance of the class...
20176  * <pre>
20177  *  dd.onDragDrop = function(e, id) {
20178  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
20179  *  }
20180  * </pre>
20181  * @constructor
20182  * @param {String} id of the element that is linked to this instance
20183  * @param {String} sGroup the group of related DragDrop objects
20184  * @param {object} config an object containing configurable attributes
20185  *                Valid properties for DragDrop:
20186  *                    padding, isTarget, maintainOffset, primaryButtonOnly
20187  */
20188 Roo.dd.DragDrop = function(id, sGroup, config) {
20189     if (id) {
20190         this.init(id, sGroup, config);
20191     }
20192     
20193 };
20194
20195 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
20196
20197     /**
20198      * The id of the element associated with this object.  This is what we
20199      * refer to as the "linked element" because the size and position of
20200      * this element is used to determine when the drag and drop objects have
20201      * interacted.
20202      * @property id
20203      * @type String
20204      */
20205     id: null,
20206
20207     /**
20208      * Configuration attributes passed into the constructor
20209      * @property config
20210      * @type object
20211      */
20212     config: null,
20213
20214     /**
20215      * The id of the element that will be dragged.  By default this is same
20216      * as the linked element , but could be changed to another element. Ex:
20217      * Roo.dd.DDProxy
20218      * @property dragElId
20219      * @type String
20220      * @private
20221      */
20222     dragElId: null,
20223
20224     /**
20225      * the id of the element that initiates the drag operation.  By default
20226      * this is the linked element, but could be changed to be a child of this
20227      * element.  This lets us do things like only starting the drag when the
20228      * header element within the linked html element is clicked.
20229      * @property handleElId
20230      * @type String
20231      * @private
20232      */
20233     handleElId: null,
20234
20235     /**
20236      * An associative array of HTML tags that will be ignored if clicked.
20237      * @property invalidHandleTypes
20238      * @type {string: string}
20239      */
20240     invalidHandleTypes: null,
20241
20242     /**
20243      * An associative array of ids for elements that will be ignored if clicked
20244      * @property invalidHandleIds
20245      * @type {string: string}
20246      */
20247     invalidHandleIds: null,
20248
20249     /**
20250      * An indexted array of css class names for elements that will be ignored
20251      * if clicked.
20252      * @property invalidHandleClasses
20253      * @type string[]
20254      */
20255     invalidHandleClasses: null,
20256
20257     /**
20258      * The linked element's absolute X position at the time the drag was
20259      * started
20260      * @property startPageX
20261      * @type int
20262      * @private
20263      */
20264     startPageX: 0,
20265
20266     /**
20267      * The linked element's absolute X position at the time the drag was
20268      * started
20269      * @property startPageY
20270      * @type int
20271      * @private
20272      */
20273     startPageY: 0,
20274
20275     /**
20276      * The group defines a logical collection of DragDrop objects that are
20277      * related.  Instances only get events when interacting with other
20278      * DragDrop object in the same group.  This lets us define multiple
20279      * groups using a single DragDrop subclass if we want.
20280      * @property groups
20281      * @type {string: string}
20282      */
20283     groups: null,
20284
20285     /**
20286      * Individual drag/drop instances can be locked.  This will prevent
20287      * onmousedown start drag.
20288      * @property locked
20289      * @type boolean
20290      * @private
20291      */
20292     locked: false,
20293
20294     /**
20295      * Lock this instance
20296      * @method lock
20297      */
20298     lock: function() { this.locked = true; },
20299
20300     /**
20301      * Unlock this instace
20302      * @method unlock
20303      */
20304     unlock: function() { this.locked = false; },
20305
20306     /**
20307      * By default, all insances can be a drop target.  This can be disabled by
20308      * setting isTarget to false.
20309      * @method isTarget
20310      * @type boolean
20311      */
20312     isTarget: true,
20313
20314     /**
20315      * The padding configured for this drag and drop object for calculating
20316      * the drop zone intersection with this object.
20317      * @method padding
20318      * @type int[]
20319      */
20320     padding: null,
20321
20322     /**
20323      * Cached reference to the linked element
20324      * @property _domRef
20325      * @private
20326      */
20327     _domRef: null,
20328
20329     /**
20330      * Internal typeof flag
20331      * @property __ygDragDrop
20332      * @private
20333      */
20334     __ygDragDrop: true,
20335
20336     /**
20337      * Set to true when horizontal contraints are applied
20338      * @property constrainX
20339      * @type boolean
20340      * @private
20341      */
20342     constrainX: false,
20343
20344     /**
20345      * Set to true when vertical contraints are applied
20346      * @property constrainY
20347      * @type boolean
20348      * @private
20349      */
20350     constrainY: false,
20351
20352     /**
20353      * The left constraint
20354      * @property minX
20355      * @type int
20356      * @private
20357      */
20358     minX: 0,
20359
20360     /**
20361      * The right constraint
20362      * @property maxX
20363      * @type int
20364      * @private
20365      */
20366     maxX: 0,
20367
20368     /**
20369      * The up constraint
20370      * @property minY
20371      * @type int
20372      * @type int
20373      * @private
20374      */
20375     minY: 0,
20376
20377     /**
20378      * The down constraint
20379      * @property maxY
20380      * @type int
20381      * @private
20382      */
20383     maxY: 0,
20384
20385     /**
20386      * Maintain offsets when we resetconstraints.  Set to true when you want
20387      * the position of the element relative to its parent to stay the same
20388      * when the page changes
20389      *
20390      * @property maintainOffset
20391      * @type boolean
20392      */
20393     maintainOffset: false,
20394
20395     /**
20396      * Array of pixel locations the element will snap to if we specified a
20397      * horizontal graduation/interval.  This array is generated automatically
20398      * when you define a tick interval.
20399      * @property xTicks
20400      * @type int[]
20401      */
20402     xTicks: null,
20403
20404     /**
20405      * Array of pixel locations the element will snap to if we specified a
20406      * vertical graduation/interval.  This array is generated automatically
20407      * when you define a tick interval.
20408      * @property yTicks
20409      * @type int[]
20410      */
20411     yTicks: null,
20412
20413     /**
20414      * By default the drag and drop instance will only respond to the primary
20415      * button click (left button for a right-handed mouse).  Set to true to
20416      * allow drag and drop to start with any mouse click that is propogated
20417      * by the browser
20418      * @property primaryButtonOnly
20419      * @type boolean
20420      */
20421     primaryButtonOnly: true,
20422
20423     /**
20424      * The availabe property is false until the linked dom element is accessible.
20425      * @property available
20426      * @type boolean
20427      */
20428     available: false,
20429
20430     /**
20431      * By default, drags can only be initiated if the mousedown occurs in the
20432      * region the linked element is.  This is done in part to work around a
20433      * bug in some browsers that mis-report the mousedown if the previous
20434      * mouseup happened outside of the window.  This property is set to true
20435      * if outer handles are defined.
20436      *
20437      * @property hasOuterHandles
20438      * @type boolean
20439      * @default false
20440      */
20441     hasOuterHandles: false,
20442
20443     /**
20444      * Code that executes immediately before the startDrag event
20445      * @method b4StartDrag
20446      * @private
20447      */
20448     b4StartDrag: function(x, y) { },
20449
20450     /**
20451      * Abstract method called after a drag/drop object is clicked
20452      * and the drag or mousedown time thresholds have beeen met.
20453      * @method startDrag
20454      * @param {int} X click location
20455      * @param {int} Y click location
20456      */
20457     startDrag: function(x, y) { /* override this */ },
20458
20459     /**
20460      * Code that executes immediately before the onDrag event
20461      * @method b4Drag
20462      * @private
20463      */
20464     b4Drag: function(e) { },
20465
20466     /**
20467      * Abstract method called during the onMouseMove event while dragging an
20468      * object.
20469      * @method onDrag
20470      * @param {Event} e the mousemove event
20471      */
20472     onDrag: function(e) { /* override this */ },
20473
20474     /**
20475      * Abstract method called when this element fist begins hovering over
20476      * another DragDrop obj
20477      * @method onDragEnter
20478      * @param {Event} e the mousemove event
20479      * @param {String|DragDrop[]} id In POINT mode, the element
20480      * id this is hovering over.  In INTERSECT mode, an array of one or more
20481      * dragdrop items being hovered over.
20482      */
20483     onDragEnter: function(e, id) { /* override this */ },
20484
20485     /**
20486      * Code that executes immediately before the onDragOver event
20487      * @method b4DragOver
20488      * @private
20489      */
20490     b4DragOver: function(e) { },
20491
20492     /**
20493      * Abstract method called when this element is hovering over another
20494      * DragDrop obj
20495      * @method onDragOver
20496      * @param {Event} e the mousemove event
20497      * @param {String|DragDrop[]} id In POINT mode, the element
20498      * id this is hovering over.  In INTERSECT mode, an array of dd items
20499      * being hovered over.
20500      */
20501     onDragOver: function(e, id) { /* override this */ },
20502
20503     /**
20504      * Code that executes immediately before the onDragOut event
20505      * @method b4DragOut
20506      * @private
20507      */
20508     b4DragOut: function(e) { },
20509
20510     /**
20511      * Abstract method called when we are no longer hovering over an element
20512      * @method onDragOut
20513      * @param {Event} e the mousemove event
20514      * @param {String|DragDrop[]} id In POINT mode, the element
20515      * id this was hovering over.  In INTERSECT mode, an array of dd items
20516      * that the mouse is no longer over.
20517      */
20518     onDragOut: function(e, id) { /* override this */ },
20519
20520     /**
20521      * Code that executes immediately before the onDragDrop event
20522      * @method b4DragDrop
20523      * @private
20524      */
20525     b4DragDrop: function(e) { },
20526
20527     /**
20528      * Abstract method called when this item is dropped on another DragDrop
20529      * obj
20530      * @method onDragDrop
20531      * @param {Event} e the mouseup event
20532      * @param {String|DragDrop[]} id In POINT mode, the element
20533      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20534      * was dropped on.
20535      */
20536     onDragDrop: function(e, id) { /* override this */ },
20537
20538     /**
20539      * Abstract method called when this item is dropped on an area with no
20540      * drop target
20541      * @method onInvalidDrop
20542      * @param {Event} e the mouseup event
20543      */
20544     onInvalidDrop: function(e) { /* override this */ },
20545
20546     /**
20547      * Code that executes immediately before the endDrag event
20548      * @method b4EndDrag
20549      * @private
20550      */
20551     b4EndDrag: function(e) { },
20552
20553     /**
20554      * Fired when we are done dragging the object
20555      * @method endDrag
20556      * @param {Event} e the mouseup event
20557      */
20558     endDrag: function(e) { /* override this */ },
20559
20560     /**
20561      * Code executed immediately before the onMouseDown event
20562      * @method b4MouseDown
20563      * @param {Event} e the mousedown event
20564      * @private
20565      */
20566     b4MouseDown: function(e) {  },
20567
20568     /**
20569      * Event handler that fires when a drag/drop obj gets a mousedown
20570      * @method onMouseDown
20571      * @param {Event} e the mousedown event
20572      */
20573     onMouseDown: function(e) { /* override this */ },
20574
20575     /**
20576      * Event handler that fires when a drag/drop obj gets a mouseup
20577      * @method onMouseUp
20578      * @param {Event} e the mouseup event
20579      */
20580     onMouseUp: function(e) { /* override this */ },
20581
20582     /**
20583      * Override the onAvailable method to do what is needed after the initial
20584      * position was determined.
20585      * @method onAvailable
20586      */
20587     onAvailable: function () {
20588     },
20589
20590     /*
20591      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20592      * @type Object
20593      */
20594     defaultPadding : {left:0, right:0, top:0, bottom:0},
20595
20596     /*
20597      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20598  *
20599  * Usage:
20600  <pre><code>
20601  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20602                 { dragElId: "existingProxyDiv" });
20603  dd.startDrag = function(){
20604      this.constrainTo("parent-id");
20605  };
20606  </code></pre>
20607  * Or you can initalize it using the {@link Roo.Element} object:
20608  <pre><code>
20609  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20610      startDrag : function(){
20611          this.constrainTo("parent-id");
20612      }
20613  });
20614  </code></pre>
20615      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20616      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20617      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20618      * an object containing the sides to pad. For example: {right:10, bottom:10}
20619      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20620      */
20621     constrainTo : function(constrainTo, pad, inContent){
20622         if(typeof pad == "number"){
20623             pad = {left: pad, right:pad, top:pad, bottom:pad};
20624         }
20625         pad = pad || this.defaultPadding;
20626         var b = Roo.get(this.getEl()).getBox();
20627         var ce = Roo.get(constrainTo);
20628         var s = ce.getScroll();
20629         var c, cd = ce.dom;
20630         if(cd == document.body){
20631             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20632         }else{
20633             xy = ce.getXY();
20634             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20635         }
20636
20637
20638         var topSpace = b.y - c.y;
20639         var leftSpace = b.x - c.x;
20640
20641         this.resetConstraints();
20642         this.setXConstraint(leftSpace - (pad.left||0), // left
20643                 c.width - leftSpace - b.width - (pad.right||0) //right
20644         );
20645         this.setYConstraint(topSpace - (pad.top||0), //top
20646                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20647         );
20648     },
20649
20650     /**
20651      * Returns a reference to the linked element
20652      * @method getEl
20653      * @return {HTMLElement} the html element
20654      */
20655     getEl: function() {
20656         if (!this._domRef) {
20657             this._domRef = Roo.getDom(this.id);
20658         }
20659
20660         return this._domRef;
20661     },
20662
20663     /**
20664      * Returns a reference to the actual element to drag.  By default this is
20665      * the same as the html element, but it can be assigned to another
20666      * element. An example of this can be found in Roo.dd.DDProxy
20667      * @method getDragEl
20668      * @return {HTMLElement} the html element
20669      */
20670     getDragEl: function() {
20671         return Roo.getDom(this.dragElId);
20672     },
20673
20674     /**
20675      * Sets up the DragDrop object.  Must be called in the constructor of any
20676      * Roo.dd.DragDrop subclass
20677      * @method init
20678      * @param id the id of the linked element
20679      * @param {String} sGroup the group of related items
20680      * @param {object} config configuration attributes
20681      */
20682     init: function(id, sGroup, config) {
20683         this.initTarget(id, sGroup, config);
20684         if (!Roo.isTouch) {
20685             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20686         }
20687         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20688         // Event.on(this.id, "selectstart", Event.preventDefault);
20689     },
20690
20691     /**
20692      * Initializes Targeting functionality only... the object does not
20693      * get a mousedown handler.
20694      * @method initTarget
20695      * @param id the id of the linked element
20696      * @param {String} sGroup the group of related items
20697      * @param {object} config configuration attributes
20698      */
20699     initTarget: function(id, sGroup, config) {
20700
20701         // configuration attributes
20702         this.config = config || {};
20703
20704         // create a local reference to the drag and drop manager
20705         this.DDM = Roo.dd.DDM;
20706         // initialize the groups array
20707         this.groups = {};
20708
20709         // assume that we have an element reference instead of an id if the
20710         // parameter is not a string
20711         if (typeof id !== "string") {
20712             id = Roo.id(id);
20713         }
20714
20715         // set the id
20716         this.id = id;
20717
20718         // add to an interaction group
20719         this.addToGroup((sGroup) ? sGroup : "default");
20720
20721         // We don't want to register this as the handle with the manager
20722         // so we just set the id rather than calling the setter.
20723         this.handleElId = id;
20724
20725         // the linked element is the element that gets dragged by default
20726         this.setDragElId(id);
20727
20728         // by default, clicked anchors will not start drag operations.
20729         this.invalidHandleTypes = { A: "A" };
20730         this.invalidHandleIds = {};
20731         this.invalidHandleClasses = [];
20732
20733         this.applyConfig();
20734
20735         this.handleOnAvailable();
20736     },
20737
20738     /**
20739      * Applies the configuration parameters that were passed into the constructor.
20740      * This is supposed to happen at each level through the inheritance chain.  So
20741      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20742      * DragDrop in order to get all of the parameters that are available in
20743      * each object.
20744      * @method applyConfig
20745      */
20746     applyConfig: function() {
20747
20748         // configurable properties:
20749         //    padding, isTarget, maintainOffset, primaryButtonOnly
20750         this.padding           = this.config.padding || [0, 0, 0, 0];
20751         this.isTarget          = (this.config.isTarget !== false);
20752         this.maintainOffset    = (this.config.maintainOffset);
20753         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20754
20755     },
20756
20757     /**
20758      * Executed when the linked element is available
20759      * @method handleOnAvailable
20760      * @private
20761      */
20762     handleOnAvailable: function() {
20763         this.available = true;
20764         this.resetConstraints();
20765         this.onAvailable();
20766     },
20767
20768      /**
20769      * Configures the padding for the target zone in px.  Effectively expands
20770      * (or reduces) the virtual object size for targeting calculations.
20771      * Supports css-style shorthand; if only one parameter is passed, all sides
20772      * will have that padding, and if only two are passed, the top and bottom
20773      * will have the first param, the left and right the second.
20774      * @method setPadding
20775      * @param {int} iTop    Top pad
20776      * @param {int} iRight  Right pad
20777      * @param {int} iBot    Bot pad
20778      * @param {int} iLeft   Left pad
20779      */
20780     setPadding: function(iTop, iRight, iBot, iLeft) {
20781         // this.padding = [iLeft, iRight, iTop, iBot];
20782         if (!iRight && 0 !== iRight) {
20783             this.padding = [iTop, iTop, iTop, iTop];
20784         } else if (!iBot && 0 !== iBot) {
20785             this.padding = [iTop, iRight, iTop, iRight];
20786         } else {
20787             this.padding = [iTop, iRight, iBot, iLeft];
20788         }
20789     },
20790
20791     /**
20792      * Stores the initial placement of the linked element.
20793      * @method setInitialPosition
20794      * @param {int} diffX   the X offset, default 0
20795      * @param {int} diffY   the Y offset, default 0
20796      */
20797     setInitPosition: function(diffX, diffY) {
20798         var el = this.getEl();
20799
20800         if (!this.DDM.verifyEl(el)) {
20801             return;
20802         }
20803
20804         var dx = diffX || 0;
20805         var dy = diffY || 0;
20806
20807         var p = Dom.getXY( el );
20808
20809         this.initPageX = p[0] - dx;
20810         this.initPageY = p[1] - dy;
20811
20812         this.lastPageX = p[0];
20813         this.lastPageY = p[1];
20814
20815
20816         this.setStartPosition(p);
20817     },
20818
20819     /**
20820      * Sets the start position of the element.  This is set when the obj
20821      * is initialized, the reset when a drag is started.
20822      * @method setStartPosition
20823      * @param pos current position (from previous lookup)
20824      * @private
20825      */
20826     setStartPosition: function(pos) {
20827         var p = pos || Dom.getXY( this.getEl() );
20828         this.deltaSetXY = null;
20829
20830         this.startPageX = p[0];
20831         this.startPageY = p[1];
20832     },
20833
20834     /**
20835      * Add this instance to a group of related drag/drop objects.  All
20836      * instances belong to at least one group, and can belong to as many
20837      * groups as needed.
20838      * @method addToGroup
20839      * @param sGroup {string} the name of the group
20840      */
20841     addToGroup: function(sGroup) {
20842         this.groups[sGroup] = true;
20843         this.DDM.regDragDrop(this, sGroup);
20844     },
20845
20846     /**
20847      * Remove's this instance from the supplied interaction group
20848      * @method removeFromGroup
20849      * @param {string}  sGroup  The group to drop
20850      */
20851     removeFromGroup: function(sGroup) {
20852         if (this.groups[sGroup]) {
20853             delete this.groups[sGroup];
20854         }
20855
20856         this.DDM.removeDDFromGroup(this, sGroup);
20857     },
20858
20859     /**
20860      * Allows you to specify that an element other than the linked element
20861      * will be moved with the cursor during a drag
20862      * @method setDragElId
20863      * @param id {string} the id of the element that will be used to initiate the drag
20864      */
20865     setDragElId: function(id) {
20866         this.dragElId = id;
20867     },
20868
20869     /**
20870      * Allows you to specify a child of the linked element that should be
20871      * used to initiate the drag operation.  An example of this would be if
20872      * you have a content div with text and links.  Clicking anywhere in the
20873      * content area would normally start the drag operation.  Use this method
20874      * to specify that an element inside of the content div is the element
20875      * that starts the drag operation.
20876      * @method setHandleElId
20877      * @param id {string} the id of the element that will be used to
20878      * initiate the drag.
20879      */
20880     setHandleElId: function(id) {
20881         if (typeof id !== "string") {
20882             id = Roo.id(id);
20883         }
20884         this.handleElId = id;
20885         this.DDM.regHandle(this.id, id);
20886     },
20887
20888     /**
20889      * Allows you to set an element outside of the linked element as a drag
20890      * handle
20891      * @method setOuterHandleElId
20892      * @param id the id of the element that will be used to initiate the drag
20893      */
20894     setOuterHandleElId: function(id) {
20895         if (typeof id !== "string") {
20896             id = Roo.id(id);
20897         }
20898         Event.on(id, "mousedown",
20899                 this.handleMouseDown, this);
20900         this.setHandleElId(id);
20901
20902         this.hasOuterHandles = true;
20903     },
20904
20905     /**
20906      * Remove all drag and drop hooks for this element
20907      * @method unreg
20908      */
20909     unreg: function() {
20910         Event.un(this.id, "mousedown",
20911                 this.handleMouseDown);
20912         Event.un(this.id, "touchstart",
20913                 this.handleMouseDown);
20914         this._domRef = null;
20915         this.DDM._remove(this);
20916     },
20917
20918     destroy : function(){
20919         this.unreg();
20920     },
20921
20922     /**
20923      * Returns true if this instance is locked, or the drag drop mgr is locked
20924      * (meaning that all drag/drop is disabled on the page.)
20925      * @method isLocked
20926      * @return {boolean} true if this obj or all drag/drop is locked, else
20927      * false
20928      */
20929     isLocked: function() {
20930         return (this.DDM.isLocked() || this.locked);
20931     },
20932
20933     /**
20934      * Fired when this object is clicked
20935      * @method handleMouseDown
20936      * @param {Event} e
20937      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20938      * @private
20939      */
20940     handleMouseDown: function(e, oDD){
20941      
20942         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20943             //Roo.log('not touch/ button !=0');
20944             return;
20945         }
20946         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20947             return; // double touch..
20948         }
20949         
20950
20951         if (this.isLocked()) {
20952             //Roo.log('locked');
20953             return;
20954         }
20955
20956         this.DDM.refreshCache(this.groups);
20957 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20958         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20959         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20960             //Roo.log('no outer handes or not over target');
20961                 // do nothing.
20962         } else {
20963 //            Roo.log('check validator');
20964             if (this.clickValidator(e)) {
20965 //                Roo.log('validate success');
20966                 // set the initial element position
20967                 this.setStartPosition();
20968
20969
20970                 this.b4MouseDown(e);
20971                 this.onMouseDown(e);
20972
20973                 this.DDM.handleMouseDown(e, this);
20974
20975                 this.DDM.stopEvent(e);
20976             } else {
20977
20978
20979             }
20980         }
20981     },
20982
20983     clickValidator: function(e) {
20984         var target = e.getTarget();
20985         return ( this.isValidHandleChild(target) &&
20986                     (this.id == this.handleElId ||
20987                         this.DDM.handleWasClicked(target, this.id)) );
20988     },
20989
20990     /**
20991      * Allows you to specify a tag name that should not start a drag operation
20992      * when clicked.  This is designed to facilitate embedding links within a
20993      * drag handle that do something other than start the drag.
20994      * @method addInvalidHandleType
20995      * @param {string} tagName the type of element to exclude
20996      */
20997     addInvalidHandleType: function(tagName) {
20998         var type = tagName.toUpperCase();
20999         this.invalidHandleTypes[type] = type;
21000     },
21001
21002     /**
21003      * Lets you to specify an element id for a child of a drag handle
21004      * that should not initiate a drag
21005      * @method addInvalidHandleId
21006      * @param {string} id the element id of the element you wish to ignore
21007      */
21008     addInvalidHandleId: function(id) {
21009         if (typeof id !== "string") {
21010             id = Roo.id(id);
21011         }
21012         this.invalidHandleIds[id] = id;
21013     },
21014
21015     /**
21016      * Lets you specify a css class of elements that will not initiate a drag
21017      * @method addInvalidHandleClass
21018      * @param {string} cssClass the class of the elements you wish to ignore
21019      */
21020     addInvalidHandleClass: function(cssClass) {
21021         this.invalidHandleClasses.push(cssClass);
21022     },
21023
21024     /**
21025      * Unsets an excluded tag name set by addInvalidHandleType
21026      * @method removeInvalidHandleType
21027      * @param {string} tagName the type of element to unexclude
21028      */
21029     removeInvalidHandleType: function(tagName) {
21030         var type = tagName.toUpperCase();
21031         // this.invalidHandleTypes[type] = null;
21032         delete this.invalidHandleTypes[type];
21033     },
21034
21035     /**
21036      * Unsets an invalid handle id
21037      * @method removeInvalidHandleId
21038      * @param {string} id the id of the element to re-enable
21039      */
21040     removeInvalidHandleId: function(id) {
21041         if (typeof id !== "string") {
21042             id = Roo.id(id);
21043         }
21044         delete this.invalidHandleIds[id];
21045     },
21046
21047     /**
21048      * Unsets an invalid css class
21049      * @method removeInvalidHandleClass
21050      * @param {string} cssClass the class of the element(s) you wish to
21051      * re-enable
21052      */
21053     removeInvalidHandleClass: function(cssClass) {
21054         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
21055             if (this.invalidHandleClasses[i] == cssClass) {
21056                 delete this.invalidHandleClasses[i];
21057             }
21058         }
21059     },
21060
21061     /**
21062      * Checks the tag exclusion list to see if this click should be ignored
21063      * @method isValidHandleChild
21064      * @param {HTMLElement} node the HTMLElement to evaluate
21065      * @return {boolean} true if this is a valid tag type, false if not
21066      */
21067     isValidHandleChild: function(node) {
21068
21069         var valid = true;
21070         // var n = (node.nodeName == "#text") ? node.parentNode : node;
21071         var nodeName;
21072         try {
21073             nodeName = node.nodeName.toUpperCase();
21074         } catch(e) {
21075             nodeName = node.nodeName;
21076         }
21077         valid = valid && !this.invalidHandleTypes[nodeName];
21078         valid = valid && !this.invalidHandleIds[node.id];
21079
21080         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
21081             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
21082         }
21083
21084
21085         return valid;
21086
21087     },
21088
21089     /**
21090      * Create the array of horizontal tick marks if an interval was specified
21091      * in setXConstraint().
21092      * @method setXTicks
21093      * @private
21094      */
21095     setXTicks: function(iStartX, iTickSize) {
21096         this.xTicks = [];
21097         this.xTickSize = iTickSize;
21098
21099         var tickMap = {};
21100
21101         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
21102             if (!tickMap[i]) {
21103                 this.xTicks[this.xTicks.length] = i;
21104                 tickMap[i] = true;
21105             }
21106         }
21107
21108         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
21109             if (!tickMap[i]) {
21110                 this.xTicks[this.xTicks.length] = i;
21111                 tickMap[i] = true;
21112             }
21113         }
21114
21115         this.xTicks.sort(this.DDM.numericSort) ;
21116     },
21117
21118     /**
21119      * Create the array of vertical tick marks if an interval was specified in
21120      * setYConstraint().
21121      * @method setYTicks
21122      * @private
21123      */
21124     setYTicks: function(iStartY, iTickSize) {
21125         this.yTicks = [];
21126         this.yTickSize = iTickSize;
21127
21128         var tickMap = {};
21129
21130         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
21131             if (!tickMap[i]) {
21132                 this.yTicks[this.yTicks.length] = i;
21133                 tickMap[i] = true;
21134             }
21135         }
21136
21137         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
21138             if (!tickMap[i]) {
21139                 this.yTicks[this.yTicks.length] = i;
21140                 tickMap[i] = true;
21141             }
21142         }
21143
21144         this.yTicks.sort(this.DDM.numericSort) ;
21145     },
21146
21147     /**
21148      * By default, the element can be dragged any place on the screen.  Use
21149      * this method to limit the horizontal travel of the element.  Pass in
21150      * 0,0 for the parameters if you want to lock the drag to the y axis.
21151      * @method setXConstraint
21152      * @param {int} iLeft the number of pixels the element can move to the left
21153      * @param {int} iRight the number of pixels the element can move to the
21154      * right
21155      * @param {int} iTickSize optional parameter for specifying that the
21156      * element
21157      * should move iTickSize pixels at a time.
21158      */
21159     setXConstraint: function(iLeft, iRight, iTickSize) {
21160         this.leftConstraint = iLeft;
21161         this.rightConstraint = iRight;
21162
21163         this.minX = this.initPageX - iLeft;
21164         this.maxX = this.initPageX + iRight;
21165         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
21166
21167         this.constrainX = true;
21168     },
21169
21170     /**
21171      * Clears any constraints applied to this instance.  Also clears ticks
21172      * since they can't exist independent of a constraint at this time.
21173      * @method clearConstraints
21174      */
21175     clearConstraints: function() {
21176         this.constrainX = false;
21177         this.constrainY = false;
21178         this.clearTicks();
21179     },
21180
21181     /**
21182      * Clears any tick interval defined for this instance
21183      * @method clearTicks
21184      */
21185     clearTicks: function() {
21186         this.xTicks = null;
21187         this.yTicks = null;
21188         this.xTickSize = 0;
21189         this.yTickSize = 0;
21190     },
21191
21192     /**
21193      * By default, the element can be dragged any place on the screen.  Set
21194      * this to limit the vertical travel of the element.  Pass in 0,0 for the
21195      * parameters if you want to lock the drag to the x axis.
21196      * @method setYConstraint
21197      * @param {int} iUp the number of pixels the element can move up
21198      * @param {int} iDown the number of pixels the element can move down
21199      * @param {int} iTickSize optional parameter for specifying that the
21200      * element should move iTickSize pixels at a time.
21201      */
21202     setYConstraint: function(iUp, iDown, iTickSize) {
21203         this.topConstraint = iUp;
21204         this.bottomConstraint = iDown;
21205
21206         this.minY = this.initPageY - iUp;
21207         this.maxY = this.initPageY + iDown;
21208         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21209
21210         this.constrainY = true;
21211
21212     },
21213
21214     /**
21215      * resetConstraints must be called if you manually reposition a dd element.
21216      * @method resetConstraints
21217      * @param {boolean} maintainOffset
21218      */
21219     resetConstraints: function() {
21220
21221
21222         // Maintain offsets if necessary
21223         if (this.initPageX || this.initPageX === 0) {
21224             // figure out how much this thing has moved
21225             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21226             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21227
21228             this.setInitPosition(dx, dy);
21229
21230         // This is the first time we have detected the element's position
21231         } else {
21232             this.setInitPosition();
21233         }
21234
21235         if (this.constrainX) {
21236             this.setXConstraint( this.leftConstraint,
21237                                  this.rightConstraint,
21238                                  this.xTickSize        );
21239         }
21240
21241         if (this.constrainY) {
21242             this.setYConstraint( this.topConstraint,
21243                                  this.bottomConstraint,
21244                                  this.yTickSize         );
21245         }
21246     },
21247
21248     /**
21249      * Normally the drag element is moved pixel by pixel, but we can specify
21250      * that it move a number of pixels at a time.  This method resolves the
21251      * location when we have it set up like this.
21252      * @method getTick
21253      * @param {int} val where we want to place the object
21254      * @param {int[]} tickArray sorted array of valid points
21255      * @return {int} the closest tick
21256      * @private
21257      */
21258     getTick: function(val, tickArray) {
21259
21260         if (!tickArray) {
21261             // If tick interval is not defined, it is effectively 1 pixel,
21262             // so we return the value passed to us.
21263             return val;
21264         } else if (tickArray[0] >= val) {
21265             // The value is lower than the first tick, so we return the first
21266             // tick.
21267             return tickArray[0];
21268         } else {
21269             for (var i=0, len=tickArray.length; i<len; ++i) {
21270                 var next = i + 1;
21271                 if (tickArray[next] && tickArray[next] >= val) {
21272                     var diff1 = val - tickArray[i];
21273                     var diff2 = tickArray[next] - val;
21274                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21275                 }
21276             }
21277
21278             // The value is larger than the last tick, so we return the last
21279             // tick.
21280             return tickArray[tickArray.length - 1];
21281         }
21282     },
21283
21284     /**
21285      * toString method
21286      * @method toString
21287      * @return {string} string representation of the dd obj
21288      */
21289     toString: function() {
21290         return ("DragDrop " + this.id);
21291     }
21292
21293 });
21294
21295 })();
21296 /*
21297  * Based on:
21298  * Ext JS Library 1.1.1
21299  * Copyright(c) 2006-2007, Ext JS, LLC.
21300  *
21301  * Originally Released Under LGPL - original licence link has changed is not relivant.
21302  *
21303  * Fork - LGPL
21304  * <script type="text/javascript">
21305  */
21306
21307
21308 /**
21309  * The drag and drop utility provides a framework for building drag and drop
21310  * applications.  In addition to enabling drag and drop for specific elements,
21311  * the drag and drop elements are tracked by the manager class, and the
21312  * interactions between the various elements are tracked during the drag and
21313  * the implementing code is notified about these important moments.
21314  */
21315
21316 // Only load the library once.  Rewriting the manager class would orphan
21317 // existing drag and drop instances.
21318 if (!Roo.dd.DragDropMgr) {
21319
21320 /**
21321  * @class Roo.dd.DragDropMgr
21322  * DragDropMgr is a singleton that tracks the element interaction for
21323  * all DragDrop items in the window.  Generally, you will not call
21324  * this class directly, but it does have helper methods that could
21325  * be useful in your DragDrop implementations.
21326  * @static
21327  */
21328 Roo.dd.DragDropMgr = function() {
21329
21330     var Event = Roo.EventManager;
21331
21332     return {
21333
21334         /**
21335          * Two dimensional Array of registered DragDrop objects.  The first
21336          * dimension is the DragDrop item group, the second the DragDrop
21337          * object.
21338          * @property ids
21339          * @type {string: string}
21340          * @private
21341          * @static
21342          */
21343         ids: {},
21344
21345         /**
21346          * Array of element ids defined as drag handles.  Used to determine
21347          * if the element that generated the mousedown event is actually the
21348          * handle and not the html element itself.
21349          * @property handleIds
21350          * @type {string: string}
21351          * @private
21352          * @static
21353          */
21354         handleIds: {},
21355
21356         /**
21357          * the DragDrop object that is currently being dragged
21358          * @property dragCurrent
21359          * @type DragDrop
21360          * @private
21361          * @static
21362          **/
21363         dragCurrent: null,
21364
21365         /**
21366          * the DragDrop object(s) that are being hovered over
21367          * @property dragOvers
21368          * @type Array
21369          * @private
21370          * @static
21371          */
21372         dragOvers: {},
21373
21374         /**
21375          * the X distance between the cursor and the object being dragged
21376          * @property deltaX
21377          * @type int
21378          * @private
21379          * @static
21380          */
21381         deltaX: 0,
21382
21383         /**
21384          * the Y distance between the cursor and the object being dragged
21385          * @property deltaY
21386          * @type int
21387          * @private
21388          * @static
21389          */
21390         deltaY: 0,
21391
21392         /**
21393          * Flag to determine if we should prevent the default behavior of the
21394          * events we define. By default this is true, but this can be set to
21395          * false if you need the default behavior (not recommended)
21396          * @property preventDefault
21397          * @type boolean
21398          * @static
21399          */
21400         preventDefault: true,
21401
21402         /**
21403          * Flag to determine if we should stop the propagation of the events
21404          * we generate. This is true by default but you may want to set it to
21405          * false if the html element contains other features that require the
21406          * mouse click.
21407          * @property stopPropagation
21408          * @type boolean
21409          * @static
21410          */
21411         stopPropagation: true,
21412
21413         /**
21414          * Internal flag that is set to true when drag and drop has been
21415          * intialized
21416          * @property initialized
21417          * @private
21418          * @static
21419          */
21420         initalized: false,
21421
21422         /**
21423          * All drag and drop can be disabled.
21424          * @property locked
21425          * @private
21426          * @static
21427          */
21428         locked: false,
21429
21430         /**
21431          * Called the first time an element is registered.
21432          * @method init
21433          * @private
21434          * @static
21435          */
21436         init: function() {
21437             this.initialized = true;
21438         },
21439
21440         /**
21441          * In point mode, drag and drop interaction is defined by the
21442          * location of the cursor during the drag/drop
21443          * @property POINT
21444          * @type int
21445          * @static
21446          */
21447         POINT: 0,
21448
21449         /**
21450          * In intersect mode, drag and drop interactio nis defined by the
21451          * overlap of two or more drag and drop objects.
21452          * @property INTERSECT
21453          * @type int
21454          * @static
21455          */
21456         INTERSECT: 1,
21457
21458         /**
21459          * The current drag and drop mode.  Default: POINT
21460          * @property mode
21461          * @type int
21462          * @static
21463          */
21464         mode: 0,
21465
21466         /**
21467          * Runs method on all drag and drop objects
21468          * @method _execOnAll
21469          * @private
21470          * @static
21471          */
21472         _execOnAll: function(sMethod, args) {
21473             for (var i in this.ids) {
21474                 for (var j in this.ids[i]) {
21475                     var oDD = this.ids[i][j];
21476                     if (! this.isTypeOfDD(oDD)) {
21477                         continue;
21478                     }
21479                     oDD[sMethod].apply(oDD, args);
21480                 }
21481             }
21482         },
21483
21484         /**
21485          * Drag and drop initialization.  Sets up the global event handlers
21486          * @method _onLoad
21487          * @private
21488          * @static
21489          */
21490         _onLoad: function() {
21491
21492             this.init();
21493
21494             if (!Roo.isTouch) {
21495                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21496                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21497             }
21498             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21499             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21500             
21501             Event.on(window,   "unload",    this._onUnload, this, true);
21502             Event.on(window,   "resize",    this._onResize, this, true);
21503             // Event.on(window,   "mouseout",    this._test);
21504
21505         },
21506
21507         /**
21508          * Reset constraints on all drag and drop objs
21509          * @method _onResize
21510          * @private
21511          * @static
21512          */
21513         _onResize: function(e) {
21514             this._execOnAll("resetConstraints", []);
21515         },
21516
21517         /**
21518          * Lock all drag and drop functionality
21519          * @method lock
21520          * @static
21521          */
21522         lock: function() { this.locked = true; },
21523
21524         /**
21525          * Unlock all drag and drop functionality
21526          * @method unlock
21527          * @static
21528          */
21529         unlock: function() { this.locked = false; },
21530
21531         /**
21532          * Is drag and drop locked?
21533          * @method isLocked
21534          * @return {boolean} True if drag and drop is locked, false otherwise.
21535          * @static
21536          */
21537         isLocked: function() { return this.locked; },
21538
21539         /**
21540          * Location cache that is set for all drag drop objects when a drag is
21541          * initiated, cleared when the drag is finished.
21542          * @property locationCache
21543          * @private
21544          * @static
21545          */
21546         locationCache: {},
21547
21548         /**
21549          * Set useCache to false if you want to force object the lookup of each
21550          * drag and drop linked element constantly during a drag.
21551          * @property useCache
21552          * @type boolean
21553          * @static
21554          */
21555         useCache: true,
21556
21557         /**
21558          * The number of pixels that the mouse needs to move after the
21559          * mousedown before the drag is initiated.  Default=3;
21560          * @property clickPixelThresh
21561          * @type int
21562          * @static
21563          */
21564         clickPixelThresh: 3,
21565
21566         /**
21567          * The number of milliseconds after the mousedown event to initiate the
21568          * drag if we don't get a mouseup event. Default=1000
21569          * @property clickTimeThresh
21570          * @type int
21571          * @static
21572          */
21573         clickTimeThresh: 350,
21574
21575         /**
21576          * Flag that indicates that either the drag pixel threshold or the
21577          * mousdown time threshold has been met
21578          * @property dragThreshMet
21579          * @type boolean
21580          * @private
21581          * @static
21582          */
21583         dragThreshMet: false,
21584
21585         /**
21586          * Timeout used for the click time threshold
21587          * @property clickTimeout
21588          * @type Object
21589          * @private
21590          * @static
21591          */
21592         clickTimeout: null,
21593
21594         /**
21595          * The X position of the mousedown event stored for later use when a
21596          * drag threshold is met.
21597          * @property startX
21598          * @type int
21599          * @private
21600          * @static
21601          */
21602         startX: 0,
21603
21604         /**
21605          * The Y position of the mousedown event stored for later use when a
21606          * drag threshold is met.
21607          * @property startY
21608          * @type int
21609          * @private
21610          * @static
21611          */
21612         startY: 0,
21613
21614         /**
21615          * Each DragDrop instance must be registered with the DragDropMgr.
21616          * This is executed in DragDrop.init()
21617          * @method regDragDrop
21618          * @param {DragDrop} oDD the DragDrop object to register
21619          * @param {String} sGroup the name of the group this element belongs to
21620          * @static
21621          */
21622         regDragDrop: function(oDD, sGroup) {
21623             if (!this.initialized) { this.init(); }
21624
21625             if (!this.ids[sGroup]) {
21626                 this.ids[sGroup] = {};
21627             }
21628             this.ids[sGroup][oDD.id] = oDD;
21629         },
21630
21631         /**
21632          * Removes the supplied dd instance from the supplied group. Executed
21633          * by DragDrop.removeFromGroup, so don't call this function directly.
21634          * @method removeDDFromGroup
21635          * @private
21636          * @static
21637          */
21638         removeDDFromGroup: function(oDD, sGroup) {
21639             if (!this.ids[sGroup]) {
21640                 this.ids[sGroup] = {};
21641             }
21642
21643             var obj = this.ids[sGroup];
21644             if (obj && obj[oDD.id]) {
21645                 delete obj[oDD.id];
21646             }
21647         },
21648
21649         /**
21650          * Unregisters a drag and drop item.  This is executed in
21651          * DragDrop.unreg, use that method instead of calling this directly.
21652          * @method _remove
21653          * @private
21654          * @static
21655          */
21656         _remove: function(oDD) {
21657             for (var g in oDD.groups) {
21658                 if (g && this.ids[g][oDD.id]) {
21659                     delete this.ids[g][oDD.id];
21660                 }
21661             }
21662             delete this.handleIds[oDD.id];
21663         },
21664
21665         /**
21666          * Each DragDrop handle element must be registered.  This is done
21667          * automatically when executing DragDrop.setHandleElId()
21668          * @method regHandle
21669          * @param {String} sDDId the DragDrop id this element is a handle for
21670          * @param {String} sHandleId the id of the element that is the drag
21671          * handle
21672          * @static
21673          */
21674         regHandle: function(sDDId, sHandleId) {
21675             if (!this.handleIds[sDDId]) {
21676                 this.handleIds[sDDId] = {};
21677             }
21678             this.handleIds[sDDId][sHandleId] = sHandleId;
21679         },
21680
21681         /**
21682          * Utility function to determine if a given element has been
21683          * registered as a drag drop item.
21684          * @method isDragDrop
21685          * @param {String} id the element id to check
21686          * @return {boolean} true if this element is a DragDrop item,
21687          * false otherwise
21688          * @static
21689          */
21690         isDragDrop: function(id) {
21691             return ( this.getDDById(id) ) ? true : false;
21692         },
21693
21694         /**
21695          * Returns the drag and drop instances that are in all groups the
21696          * passed in instance belongs to.
21697          * @method getRelated
21698          * @param {DragDrop} p_oDD the obj to get related data for
21699          * @param {boolean} bTargetsOnly if true, only return targetable objs
21700          * @return {DragDrop[]} the related instances
21701          * @static
21702          */
21703         getRelated: function(p_oDD, bTargetsOnly) {
21704             var oDDs = [];
21705             for (var i in p_oDD.groups) {
21706                 for (j in this.ids[i]) {
21707                     var dd = this.ids[i][j];
21708                     if (! this.isTypeOfDD(dd)) {
21709                         continue;
21710                     }
21711                     if (!bTargetsOnly || dd.isTarget) {
21712                         oDDs[oDDs.length] = dd;
21713                     }
21714                 }
21715             }
21716
21717             return oDDs;
21718         },
21719
21720         /**
21721          * Returns true if the specified dd target is a legal target for
21722          * the specifice drag obj
21723          * @method isLegalTarget
21724          * @param {DragDrop} the drag obj
21725          * @param {DragDrop} the target
21726          * @return {boolean} true if the target is a legal target for the
21727          * dd obj
21728          * @static
21729          */
21730         isLegalTarget: function (oDD, oTargetDD) {
21731             var targets = this.getRelated(oDD, true);
21732             for (var i=0, len=targets.length;i<len;++i) {
21733                 if (targets[i].id == oTargetDD.id) {
21734                     return true;
21735                 }
21736             }
21737
21738             return false;
21739         },
21740
21741         /**
21742          * My goal is to be able to transparently determine if an object is
21743          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21744          * returns "object", oDD.constructor.toString() always returns
21745          * "DragDrop" and not the name of the subclass.  So for now it just
21746          * evaluates a well-known variable in DragDrop.
21747          * @method isTypeOfDD
21748          * @param {Object} the object to evaluate
21749          * @return {boolean} true if typeof oDD = DragDrop
21750          * @static
21751          */
21752         isTypeOfDD: function (oDD) {
21753             return (oDD && oDD.__ygDragDrop);
21754         },
21755
21756         /**
21757          * Utility function to determine if a given element has been
21758          * registered as a drag drop handle for the given Drag Drop object.
21759          * @method isHandle
21760          * @param {String} id the element id to check
21761          * @return {boolean} true if this element is a DragDrop handle, false
21762          * otherwise
21763          * @static
21764          */
21765         isHandle: function(sDDId, sHandleId) {
21766             return ( this.handleIds[sDDId] &&
21767                             this.handleIds[sDDId][sHandleId] );
21768         },
21769
21770         /**
21771          * Returns the DragDrop instance for a given id
21772          * @method getDDById
21773          * @param {String} id the id of the DragDrop object
21774          * @return {DragDrop} the drag drop object, null if it is not found
21775          * @static
21776          */
21777         getDDById: function(id) {
21778             for (var i in this.ids) {
21779                 if (this.ids[i][id]) {
21780                     return this.ids[i][id];
21781                 }
21782             }
21783             return null;
21784         },
21785
21786         /**
21787          * Fired after a registered DragDrop object gets the mousedown event.
21788          * Sets up the events required to track the object being dragged
21789          * @method handleMouseDown
21790          * @param {Event} e the event
21791          * @param oDD the DragDrop object being dragged
21792          * @private
21793          * @static
21794          */
21795         handleMouseDown: function(e, oDD) {
21796             if(Roo.QuickTips){
21797                 Roo.QuickTips.disable();
21798             }
21799             this.currentTarget = e.getTarget();
21800
21801             this.dragCurrent = oDD;
21802
21803             var el = oDD.getEl();
21804
21805             // track start position
21806             this.startX = e.getPageX();
21807             this.startY = e.getPageY();
21808
21809             this.deltaX = this.startX - el.offsetLeft;
21810             this.deltaY = this.startY - el.offsetTop;
21811
21812             this.dragThreshMet = false;
21813
21814             this.clickTimeout = setTimeout(
21815                     function() {
21816                         var DDM = Roo.dd.DDM;
21817                         DDM.startDrag(DDM.startX, DDM.startY);
21818                     },
21819                     this.clickTimeThresh );
21820         },
21821
21822         /**
21823          * Fired when either the drag pixel threshol or the mousedown hold
21824          * time threshold has been met.
21825          * @method startDrag
21826          * @param x {int} the X position of the original mousedown
21827          * @param y {int} the Y position of the original mousedown
21828          * @static
21829          */
21830         startDrag: function(x, y) {
21831             clearTimeout(this.clickTimeout);
21832             if (this.dragCurrent) {
21833                 this.dragCurrent.b4StartDrag(x, y);
21834                 this.dragCurrent.startDrag(x, y);
21835             }
21836             this.dragThreshMet = true;
21837         },
21838
21839         /**
21840          * Internal function to handle the mouseup event.  Will be invoked
21841          * from the context of the document.
21842          * @method handleMouseUp
21843          * @param {Event} e the event
21844          * @private
21845          * @static
21846          */
21847         handleMouseUp: function(e) {
21848
21849             if(Roo.QuickTips){
21850                 Roo.QuickTips.enable();
21851             }
21852             if (! this.dragCurrent) {
21853                 return;
21854             }
21855
21856             clearTimeout(this.clickTimeout);
21857
21858             if (this.dragThreshMet) {
21859                 this.fireEvents(e, true);
21860             } else {
21861             }
21862
21863             this.stopDrag(e);
21864
21865             this.stopEvent(e);
21866         },
21867
21868         /**
21869          * Utility to stop event propagation and event default, if these
21870          * features are turned on.
21871          * @method stopEvent
21872          * @param {Event} e the event as returned by this.getEvent()
21873          * @static
21874          */
21875         stopEvent: function(e){
21876             if(this.stopPropagation) {
21877                 e.stopPropagation();
21878             }
21879
21880             if (this.preventDefault) {
21881                 e.preventDefault();
21882             }
21883         },
21884
21885         /**
21886          * Internal function to clean up event handlers after the drag
21887          * operation is complete
21888          * @method stopDrag
21889          * @param {Event} e the event
21890          * @private
21891          * @static
21892          */
21893         stopDrag: function(e) {
21894             // Fire the drag end event for the item that was dragged
21895             if (this.dragCurrent) {
21896                 if (this.dragThreshMet) {
21897                     this.dragCurrent.b4EndDrag(e);
21898                     this.dragCurrent.endDrag(e);
21899                 }
21900
21901                 this.dragCurrent.onMouseUp(e);
21902             }
21903
21904             this.dragCurrent = null;
21905             this.dragOvers = {};
21906         },
21907
21908         /**
21909          * Internal function to handle the mousemove event.  Will be invoked
21910          * from the context of the html element.
21911          *
21912          * @TODO figure out what we can do about mouse events lost when the
21913          * user drags objects beyond the window boundary.  Currently we can
21914          * detect this in internet explorer by verifying that the mouse is
21915          * down during the mousemove event.  Firefox doesn't give us the
21916          * button state on the mousemove event.
21917          * @method handleMouseMove
21918          * @param {Event} e the event
21919          * @private
21920          * @static
21921          */
21922         handleMouseMove: function(e) {
21923             if (! this.dragCurrent) {
21924                 return true;
21925             }
21926
21927             // var button = e.which || e.button;
21928
21929             // check for IE mouseup outside of page boundary
21930             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21931                 this.stopEvent(e);
21932                 return this.handleMouseUp(e);
21933             }
21934
21935             if (!this.dragThreshMet) {
21936                 var diffX = Math.abs(this.startX - e.getPageX());
21937                 var diffY = Math.abs(this.startY - e.getPageY());
21938                 if (diffX > this.clickPixelThresh ||
21939                             diffY > this.clickPixelThresh) {
21940                     this.startDrag(this.startX, this.startY);
21941                 }
21942             }
21943
21944             if (this.dragThreshMet) {
21945                 this.dragCurrent.b4Drag(e);
21946                 this.dragCurrent.onDrag(e);
21947                 if(!this.dragCurrent.moveOnly){
21948                     this.fireEvents(e, false);
21949                 }
21950             }
21951
21952             this.stopEvent(e);
21953
21954             return true;
21955         },
21956
21957         /**
21958          * Iterates over all of the DragDrop elements to find ones we are
21959          * hovering over or dropping on
21960          * @method fireEvents
21961          * @param {Event} e the event
21962          * @param {boolean} isDrop is this a drop op or a mouseover op?
21963          * @private
21964          * @static
21965          */
21966         fireEvents: function(e, isDrop) {
21967             var dc = this.dragCurrent;
21968
21969             // If the user did the mouse up outside of the window, we could
21970             // get here even though we have ended the drag.
21971             if (!dc || dc.isLocked()) {
21972                 return;
21973             }
21974
21975             var pt = e.getPoint();
21976
21977             // cache the previous dragOver array
21978             var oldOvers = [];
21979
21980             var outEvts   = [];
21981             var overEvts  = [];
21982             var dropEvts  = [];
21983             var enterEvts = [];
21984
21985             // Check to see if the object(s) we were hovering over is no longer
21986             // being hovered over so we can fire the onDragOut event
21987             for (var i in this.dragOvers) {
21988
21989                 var ddo = this.dragOvers[i];
21990
21991                 if (! this.isTypeOfDD(ddo)) {
21992                     continue;
21993                 }
21994
21995                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21996                     outEvts.push( ddo );
21997                 }
21998
21999                 oldOvers[i] = true;
22000                 delete this.dragOvers[i];
22001             }
22002
22003             for (var sGroup in dc.groups) {
22004
22005                 if ("string" != typeof sGroup) {
22006                     continue;
22007                 }
22008
22009                 for (i in this.ids[sGroup]) {
22010                     var oDD = this.ids[sGroup][i];
22011                     if (! this.isTypeOfDD(oDD)) {
22012                         continue;
22013                     }
22014
22015                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
22016                         if (this.isOverTarget(pt, oDD, this.mode)) {
22017                             // look for drop interactions
22018                             if (isDrop) {
22019                                 dropEvts.push( oDD );
22020                             // look for drag enter and drag over interactions
22021                             } else {
22022
22023                                 // initial drag over: dragEnter fires
22024                                 if (!oldOvers[oDD.id]) {
22025                                     enterEvts.push( oDD );
22026                                 // subsequent drag overs: dragOver fires
22027                                 } else {
22028                                     overEvts.push( oDD );
22029                                 }
22030
22031                                 this.dragOvers[oDD.id] = oDD;
22032                             }
22033                         }
22034                     }
22035                 }
22036             }
22037
22038             if (this.mode) {
22039                 if (outEvts.length) {
22040                     dc.b4DragOut(e, outEvts);
22041                     dc.onDragOut(e, outEvts);
22042                 }
22043
22044                 if (enterEvts.length) {
22045                     dc.onDragEnter(e, enterEvts);
22046                 }
22047
22048                 if (overEvts.length) {
22049                     dc.b4DragOver(e, overEvts);
22050                     dc.onDragOver(e, overEvts);
22051                 }
22052
22053                 if (dropEvts.length) {
22054                     dc.b4DragDrop(e, dropEvts);
22055                     dc.onDragDrop(e, dropEvts);
22056                 }
22057
22058             } else {
22059                 // fire dragout events
22060                 var len = 0;
22061                 for (i=0, len=outEvts.length; i<len; ++i) {
22062                     dc.b4DragOut(e, outEvts[i].id);
22063                     dc.onDragOut(e, outEvts[i].id);
22064                 }
22065
22066                 // fire enter events
22067                 for (i=0,len=enterEvts.length; i<len; ++i) {
22068                     // dc.b4DragEnter(e, oDD.id);
22069                     dc.onDragEnter(e, enterEvts[i].id);
22070                 }
22071
22072                 // fire over events
22073                 for (i=0,len=overEvts.length; i<len; ++i) {
22074                     dc.b4DragOver(e, overEvts[i].id);
22075                     dc.onDragOver(e, overEvts[i].id);
22076                 }
22077
22078                 // fire drop events
22079                 for (i=0, len=dropEvts.length; i<len; ++i) {
22080                     dc.b4DragDrop(e, dropEvts[i].id);
22081                     dc.onDragDrop(e, dropEvts[i].id);
22082                 }
22083
22084             }
22085
22086             // notify about a drop that did not find a target
22087             if (isDrop && !dropEvts.length) {
22088                 dc.onInvalidDrop(e);
22089             }
22090
22091         },
22092
22093         /**
22094          * Helper function for getting the best match from the list of drag
22095          * and drop objects returned by the drag and drop events when we are
22096          * in INTERSECT mode.  It returns either the first object that the
22097          * cursor is over, or the object that has the greatest overlap with
22098          * the dragged element.
22099          * @method getBestMatch
22100          * @param  {DragDrop[]} dds The array of drag and drop objects
22101          * targeted
22102          * @return {DragDrop}       The best single match
22103          * @static
22104          */
22105         getBestMatch: function(dds) {
22106             var winner = null;
22107             // Return null if the input is not what we expect
22108             //if (!dds || !dds.length || dds.length == 0) {
22109                // winner = null;
22110             // If there is only one item, it wins
22111             //} else if (dds.length == 1) {
22112
22113             var len = dds.length;
22114
22115             if (len == 1) {
22116                 winner = dds[0];
22117             } else {
22118                 // Loop through the targeted items
22119                 for (var i=0; i<len; ++i) {
22120                     var dd = dds[i];
22121                     // If the cursor is over the object, it wins.  If the
22122                     // cursor is over multiple matches, the first one we come
22123                     // to wins.
22124                     if (dd.cursorIsOver) {
22125                         winner = dd;
22126                         break;
22127                     // Otherwise the object with the most overlap wins
22128                     } else {
22129                         if (!winner ||
22130                             winner.overlap.getArea() < dd.overlap.getArea()) {
22131                             winner = dd;
22132                         }
22133                     }
22134                 }
22135             }
22136
22137             return winner;
22138         },
22139
22140         /**
22141          * Refreshes the cache of the top-left and bottom-right points of the
22142          * drag and drop objects in the specified group(s).  This is in the
22143          * format that is stored in the drag and drop instance, so typical
22144          * usage is:
22145          * <code>
22146          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
22147          * </code>
22148          * Alternatively:
22149          * <code>
22150          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
22151          * </code>
22152          * @TODO this really should be an indexed array.  Alternatively this
22153          * method could accept both.
22154          * @method refreshCache
22155          * @param {Object} groups an associative array of groups to refresh
22156          * @static
22157          */
22158         refreshCache: function(groups) {
22159             for (var sGroup in groups) {
22160                 if ("string" != typeof sGroup) {
22161                     continue;
22162                 }
22163                 for (var i in this.ids[sGroup]) {
22164                     var oDD = this.ids[sGroup][i];
22165
22166                     if (this.isTypeOfDD(oDD)) {
22167                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
22168                         var loc = this.getLocation(oDD);
22169                         if (loc) {
22170                             this.locationCache[oDD.id] = loc;
22171                         } else {
22172                             delete this.locationCache[oDD.id];
22173                             // this will unregister the drag and drop object if
22174                             // the element is not in a usable state
22175                             // oDD.unreg();
22176                         }
22177                     }
22178                 }
22179             }
22180         },
22181
22182         /**
22183          * This checks to make sure an element exists and is in the DOM.  The
22184          * main purpose is to handle cases where innerHTML is used to remove
22185          * drag and drop objects from the DOM.  IE provides an 'unspecified
22186          * error' when trying to access the offsetParent of such an element
22187          * @method verifyEl
22188          * @param {HTMLElement} el the element to check
22189          * @return {boolean} true if the element looks usable
22190          * @static
22191          */
22192         verifyEl: function(el) {
22193             if (el) {
22194                 var parent;
22195                 if(Roo.isIE){
22196                     try{
22197                         parent = el.offsetParent;
22198                     }catch(e){}
22199                 }else{
22200                     parent = el.offsetParent;
22201                 }
22202                 if (parent) {
22203                     return true;
22204                 }
22205             }
22206
22207             return false;
22208         },
22209
22210         /**
22211          * Returns a Region object containing the drag and drop element's position
22212          * and size, including the padding configured for it
22213          * @method getLocation
22214          * @param {DragDrop} oDD the drag and drop object to get the
22215          *                       location for
22216          * @return {Roo.lib.Region} a Region object representing the total area
22217          *                             the element occupies, including any padding
22218          *                             the instance is configured for.
22219          * @static
22220          */
22221         getLocation: function(oDD) {
22222             if (! this.isTypeOfDD(oDD)) {
22223                 return null;
22224             }
22225
22226             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22227
22228             try {
22229                 pos= Roo.lib.Dom.getXY(el);
22230             } catch (e) { }
22231
22232             if (!pos) {
22233                 return null;
22234             }
22235
22236             x1 = pos[0];
22237             x2 = x1 + el.offsetWidth;
22238             y1 = pos[1];
22239             y2 = y1 + el.offsetHeight;
22240
22241             t = y1 - oDD.padding[0];
22242             r = x2 + oDD.padding[1];
22243             b = y2 + oDD.padding[2];
22244             l = x1 - oDD.padding[3];
22245
22246             return new Roo.lib.Region( t, r, b, l );
22247         },
22248
22249         /**
22250          * Checks the cursor location to see if it over the target
22251          * @method isOverTarget
22252          * @param {Roo.lib.Point} pt The point to evaluate
22253          * @param {DragDrop} oTarget the DragDrop object we are inspecting
22254          * @return {boolean} true if the mouse is over the target
22255          * @private
22256          * @static
22257          */
22258         isOverTarget: function(pt, oTarget, intersect) {
22259             // use cache if available
22260             var loc = this.locationCache[oTarget.id];
22261             if (!loc || !this.useCache) {
22262                 loc = this.getLocation(oTarget);
22263                 this.locationCache[oTarget.id] = loc;
22264
22265             }
22266
22267             if (!loc) {
22268                 return false;
22269             }
22270
22271             oTarget.cursorIsOver = loc.contains( pt );
22272
22273             // DragDrop is using this as a sanity check for the initial mousedown
22274             // in this case we are done.  In POINT mode, if the drag obj has no
22275             // contraints, we are also done. Otherwise we need to evaluate the
22276             // location of the target as related to the actual location of the
22277             // dragged element.
22278             var dc = this.dragCurrent;
22279             if (!dc || !dc.getTargetCoord ||
22280                     (!intersect && !dc.constrainX && !dc.constrainY)) {
22281                 return oTarget.cursorIsOver;
22282             }
22283
22284             oTarget.overlap = null;
22285
22286             // Get the current location of the drag element, this is the
22287             // location of the mouse event less the delta that represents
22288             // where the original mousedown happened on the element.  We
22289             // need to consider constraints and ticks as well.
22290             var pos = dc.getTargetCoord(pt.x, pt.y);
22291
22292             var el = dc.getDragEl();
22293             var curRegion = new Roo.lib.Region( pos.y,
22294                                                    pos.x + el.offsetWidth,
22295                                                    pos.y + el.offsetHeight,
22296                                                    pos.x );
22297
22298             var overlap = curRegion.intersect(loc);
22299
22300             if (overlap) {
22301                 oTarget.overlap = overlap;
22302                 return (intersect) ? true : oTarget.cursorIsOver;
22303             } else {
22304                 return false;
22305             }
22306         },
22307
22308         /**
22309          * unload event handler
22310          * @method _onUnload
22311          * @private
22312          * @static
22313          */
22314         _onUnload: function(e, me) {
22315             Roo.dd.DragDropMgr.unregAll();
22316         },
22317
22318         /**
22319          * Cleans up the drag and drop events and objects.
22320          * @method unregAll
22321          * @private
22322          * @static
22323          */
22324         unregAll: function() {
22325
22326             if (this.dragCurrent) {
22327                 this.stopDrag();
22328                 this.dragCurrent = null;
22329             }
22330
22331             this._execOnAll("unreg", []);
22332
22333             for (i in this.elementCache) {
22334                 delete this.elementCache[i];
22335             }
22336
22337             this.elementCache = {};
22338             this.ids = {};
22339         },
22340
22341         /**
22342          * A cache of DOM elements
22343          * @property elementCache
22344          * @private
22345          * @static
22346          */
22347         elementCache: {},
22348
22349         /**
22350          * Get the wrapper for the DOM element specified
22351          * @method getElWrapper
22352          * @param {String} id the id of the element to get
22353          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22354          * @private
22355          * @deprecated This wrapper isn't that useful
22356          * @static
22357          */
22358         getElWrapper: function(id) {
22359             var oWrapper = this.elementCache[id];
22360             if (!oWrapper || !oWrapper.el) {
22361                 oWrapper = this.elementCache[id] =
22362                     new this.ElementWrapper(Roo.getDom(id));
22363             }
22364             return oWrapper;
22365         },
22366
22367         /**
22368          * Returns the actual DOM element
22369          * @method getElement
22370          * @param {String} id the id of the elment to get
22371          * @return {Object} The element
22372          * @deprecated use Roo.getDom instead
22373          * @static
22374          */
22375         getElement: function(id) {
22376             return Roo.getDom(id);
22377         },
22378
22379         /**
22380          * Returns the style property for the DOM element (i.e.,
22381          * document.getElById(id).style)
22382          * @method getCss
22383          * @param {String} id the id of the elment to get
22384          * @return {Object} The style property of the element
22385          * @deprecated use Roo.getDom instead
22386          * @static
22387          */
22388         getCss: function(id) {
22389             var el = Roo.getDom(id);
22390             return (el) ? el.style : null;
22391         },
22392
22393         /**
22394          * Inner class for cached elements
22395          * @class DragDropMgr.ElementWrapper
22396          * @for DragDropMgr
22397          * @private
22398          * @deprecated
22399          */
22400         ElementWrapper: function(el) {
22401                 /**
22402                  * The element
22403                  * @property el
22404                  */
22405                 this.el = el || null;
22406                 /**
22407                  * The element id
22408                  * @property id
22409                  */
22410                 this.id = this.el && el.id;
22411                 /**
22412                  * A reference to the style property
22413                  * @property css
22414                  */
22415                 this.css = this.el && el.style;
22416             },
22417
22418         /**
22419          * Returns the X position of an html element
22420          * @method getPosX
22421          * @param el the element for which to get the position
22422          * @return {int} the X coordinate
22423          * @for DragDropMgr
22424          * @deprecated use Roo.lib.Dom.getX instead
22425          * @static
22426          */
22427         getPosX: function(el) {
22428             return Roo.lib.Dom.getX(el);
22429         },
22430
22431         /**
22432          * Returns the Y position of an html element
22433          * @method getPosY
22434          * @param el the element for which to get the position
22435          * @return {int} the Y coordinate
22436          * @deprecated use Roo.lib.Dom.getY instead
22437          * @static
22438          */
22439         getPosY: function(el) {
22440             return Roo.lib.Dom.getY(el);
22441         },
22442
22443         /**
22444          * Swap two nodes.  In IE, we use the native method, for others we
22445          * emulate the IE behavior
22446          * @method swapNode
22447          * @param n1 the first node to swap
22448          * @param n2 the other node to swap
22449          * @static
22450          */
22451         swapNode: function(n1, n2) {
22452             if (n1.swapNode) {
22453                 n1.swapNode(n2);
22454             } else {
22455                 var p = n2.parentNode;
22456                 var s = n2.nextSibling;
22457
22458                 if (s == n1) {
22459                     p.insertBefore(n1, n2);
22460                 } else if (n2 == n1.nextSibling) {
22461                     p.insertBefore(n2, n1);
22462                 } else {
22463                     n1.parentNode.replaceChild(n2, n1);
22464                     p.insertBefore(n1, s);
22465                 }
22466             }
22467         },
22468
22469         /**
22470          * Returns the current scroll position
22471          * @method getScroll
22472          * @private
22473          * @static
22474          */
22475         getScroll: function () {
22476             var t, l, dde=document.documentElement, db=document.body;
22477             if (dde && (dde.scrollTop || dde.scrollLeft)) {
22478                 t = dde.scrollTop;
22479                 l = dde.scrollLeft;
22480             } else if (db) {
22481                 t = db.scrollTop;
22482                 l = db.scrollLeft;
22483             } else {
22484
22485             }
22486             return { top: t, left: l };
22487         },
22488
22489         /**
22490          * Returns the specified element style property
22491          * @method getStyle
22492          * @param {HTMLElement} el          the element
22493          * @param {string}      styleProp   the style property
22494          * @return {string} The value of the style property
22495          * @deprecated use Roo.lib.Dom.getStyle
22496          * @static
22497          */
22498         getStyle: function(el, styleProp) {
22499             return Roo.fly(el).getStyle(styleProp);
22500         },
22501
22502         /**
22503          * Gets the scrollTop
22504          * @method getScrollTop
22505          * @return {int} the document's scrollTop
22506          * @static
22507          */
22508         getScrollTop: function () { return this.getScroll().top; },
22509
22510         /**
22511          * Gets the scrollLeft
22512          * @method getScrollLeft
22513          * @return {int} the document's scrollTop
22514          * @static
22515          */
22516         getScrollLeft: function () { return this.getScroll().left; },
22517
22518         /**
22519          * Sets the x/y position of an element to the location of the
22520          * target element.
22521          * @method moveToEl
22522          * @param {HTMLElement} moveEl      The element to move
22523          * @param {HTMLElement} targetEl    The position reference element
22524          * @static
22525          */
22526         moveToEl: function (moveEl, targetEl) {
22527             var aCoord = Roo.lib.Dom.getXY(targetEl);
22528             Roo.lib.Dom.setXY(moveEl, aCoord);
22529         },
22530
22531         /**
22532          * Numeric array sort function
22533          * @method numericSort
22534          * @static
22535          */
22536         numericSort: function(a, b) { return (a - b); },
22537
22538         /**
22539          * Internal counter
22540          * @property _timeoutCount
22541          * @private
22542          * @static
22543          */
22544         _timeoutCount: 0,
22545
22546         /**
22547          * Trying to make the load order less important.  Without this we get
22548          * an error if this file is loaded before the Event Utility.
22549          * @method _addListeners
22550          * @private
22551          * @static
22552          */
22553         _addListeners: function() {
22554             var DDM = Roo.dd.DDM;
22555             if ( Roo.lib.Event && document ) {
22556                 DDM._onLoad();
22557             } else {
22558                 if (DDM._timeoutCount > 2000) {
22559                 } else {
22560                     setTimeout(DDM._addListeners, 10);
22561                     if (document && document.body) {
22562                         DDM._timeoutCount += 1;
22563                     }
22564                 }
22565             }
22566         },
22567
22568         /**
22569          * Recursively searches the immediate parent and all child nodes for
22570          * the handle element in order to determine wheter or not it was
22571          * clicked.
22572          * @method handleWasClicked
22573          * @param node the html element to inspect
22574          * @static
22575          */
22576         handleWasClicked: function(node, id) {
22577             if (this.isHandle(id, node.id)) {
22578                 return true;
22579             } else {
22580                 // check to see if this is a text node child of the one we want
22581                 var p = node.parentNode;
22582
22583                 while (p) {
22584                     if (this.isHandle(id, p.id)) {
22585                         return true;
22586                     } else {
22587                         p = p.parentNode;
22588                     }
22589                 }
22590             }
22591
22592             return false;
22593         }
22594
22595     };
22596
22597 }();
22598
22599 // shorter alias, save a few bytes
22600 Roo.dd.DDM = Roo.dd.DragDropMgr;
22601 Roo.dd.DDM._addListeners();
22602
22603 }/*
22604  * Based on:
22605  * Ext JS Library 1.1.1
22606  * Copyright(c) 2006-2007, Ext JS, LLC.
22607  *
22608  * Originally Released Under LGPL - original licence link has changed is not relivant.
22609  *
22610  * Fork - LGPL
22611  * <script type="text/javascript">
22612  */
22613
22614 /**
22615  * @class Roo.dd.DD
22616  * A DragDrop implementation where the linked element follows the
22617  * mouse cursor during a drag.
22618  * @extends Roo.dd.DragDrop
22619  * @constructor
22620  * @param {String} id the id of the linked element
22621  * @param {String} sGroup the group of related DragDrop items
22622  * @param {object} config an object containing configurable attributes
22623  *                Valid properties for DD:
22624  *                    scroll
22625  */
22626 Roo.dd.DD = function(id, sGroup, config) {
22627     if (id) {
22628         this.init(id, sGroup, config);
22629     }
22630 };
22631
22632 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22633
22634     /**
22635      * When set to true, the utility automatically tries to scroll the browser
22636      * window wehn a drag and drop element is dragged near the viewport boundary.
22637      * Defaults to true.
22638      * @property scroll
22639      * @type boolean
22640      */
22641     scroll: true,
22642
22643     /**
22644      * Sets the pointer offset to the distance between the linked element's top
22645      * left corner and the location the element was clicked
22646      * @method autoOffset
22647      * @param {int} iPageX the X coordinate of the click
22648      * @param {int} iPageY the Y coordinate of the click
22649      */
22650     autoOffset: function(iPageX, iPageY) {
22651         var x = iPageX - this.startPageX;
22652         var y = iPageY - this.startPageY;
22653         this.setDelta(x, y);
22654     },
22655
22656     /**
22657      * Sets the pointer offset.  You can call this directly to force the
22658      * offset to be in a particular location (e.g., pass in 0,0 to set it
22659      * to the center of the object)
22660      * @method setDelta
22661      * @param {int} iDeltaX the distance from the left
22662      * @param {int} iDeltaY the distance from the top
22663      */
22664     setDelta: function(iDeltaX, iDeltaY) {
22665         this.deltaX = iDeltaX;
22666         this.deltaY = iDeltaY;
22667     },
22668
22669     /**
22670      * Sets the drag element to the location of the mousedown or click event,
22671      * maintaining the cursor location relative to the location on the element
22672      * that was clicked.  Override this if you want to place the element in a
22673      * location other than where the cursor is.
22674      * @method setDragElPos
22675      * @param {int} iPageX the X coordinate of the mousedown or drag event
22676      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22677      */
22678     setDragElPos: function(iPageX, iPageY) {
22679         // the first time we do this, we are going to check to make sure
22680         // the element has css positioning
22681
22682         var el = this.getDragEl();
22683         this.alignElWithMouse(el, iPageX, iPageY);
22684     },
22685
22686     /**
22687      * Sets the element to the location of the mousedown or click event,
22688      * maintaining the cursor location relative to the location on the element
22689      * that was clicked.  Override this if you want to place the element in a
22690      * location other than where the cursor is.
22691      * @method alignElWithMouse
22692      * @param {HTMLElement} el the element to move
22693      * @param {int} iPageX the X coordinate of the mousedown or drag event
22694      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22695      */
22696     alignElWithMouse: function(el, iPageX, iPageY) {
22697         var oCoord = this.getTargetCoord(iPageX, iPageY);
22698         var fly = el.dom ? el : Roo.fly(el);
22699         if (!this.deltaSetXY) {
22700             var aCoord = [oCoord.x, oCoord.y];
22701             fly.setXY(aCoord);
22702             var newLeft = fly.getLeft(true);
22703             var newTop  = fly.getTop(true);
22704             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22705         } else {
22706             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22707         }
22708
22709         this.cachePosition(oCoord.x, oCoord.y);
22710         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22711         return oCoord;
22712     },
22713
22714     /**
22715      * Saves the most recent position so that we can reset the constraints and
22716      * tick marks on-demand.  We need to know this so that we can calculate the
22717      * number of pixels the element is offset from its original position.
22718      * @method cachePosition
22719      * @param iPageX the current x position (optional, this just makes it so we
22720      * don't have to look it up again)
22721      * @param iPageY the current y position (optional, this just makes it so we
22722      * don't have to look it up again)
22723      */
22724     cachePosition: function(iPageX, iPageY) {
22725         if (iPageX) {
22726             this.lastPageX = iPageX;
22727             this.lastPageY = iPageY;
22728         } else {
22729             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22730             this.lastPageX = aCoord[0];
22731             this.lastPageY = aCoord[1];
22732         }
22733     },
22734
22735     /**
22736      * Auto-scroll the window if the dragged object has been moved beyond the
22737      * visible window boundary.
22738      * @method autoScroll
22739      * @param {int} x the drag element's x position
22740      * @param {int} y the drag element's y position
22741      * @param {int} h the height of the drag element
22742      * @param {int} w the width of the drag element
22743      * @private
22744      */
22745     autoScroll: function(x, y, h, w) {
22746
22747         if (this.scroll) {
22748             // The client height
22749             var clientH = Roo.lib.Dom.getViewWidth();
22750
22751             // The client width
22752             var clientW = Roo.lib.Dom.getViewHeight();
22753
22754             // The amt scrolled down
22755             var st = this.DDM.getScrollTop();
22756
22757             // The amt scrolled right
22758             var sl = this.DDM.getScrollLeft();
22759
22760             // Location of the bottom of the element
22761             var bot = h + y;
22762
22763             // Location of the right of the element
22764             var right = w + x;
22765
22766             // The distance from the cursor to the bottom of the visible area,
22767             // adjusted so that we don't scroll if the cursor is beyond the
22768             // element drag constraints
22769             var toBot = (clientH + st - y - this.deltaY);
22770
22771             // The distance from the cursor to the right of the visible area
22772             var toRight = (clientW + sl - x - this.deltaX);
22773
22774
22775             // How close to the edge the cursor must be before we scroll
22776             // var thresh = (document.all) ? 100 : 40;
22777             var thresh = 40;
22778
22779             // How many pixels to scroll per autoscroll op.  This helps to reduce
22780             // clunky scrolling. IE is more sensitive about this ... it needs this
22781             // value to be higher.
22782             var scrAmt = (document.all) ? 80 : 30;
22783
22784             // Scroll down if we are near the bottom of the visible page and the
22785             // obj extends below the crease
22786             if ( bot > clientH && toBot < thresh ) {
22787                 window.scrollTo(sl, st + scrAmt);
22788             }
22789
22790             // Scroll up if the window is scrolled down and the top of the object
22791             // goes above the top border
22792             if ( y < st && st > 0 && y - st < thresh ) {
22793                 window.scrollTo(sl, st - scrAmt);
22794             }
22795
22796             // Scroll right if the obj is beyond the right border and the cursor is
22797             // near the border.
22798             if ( right > clientW && toRight < thresh ) {
22799                 window.scrollTo(sl + scrAmt, st);
22800             }
22801
22802             // Scroll left if the window has been scrolled to the right and the obj
22803             // extends past the left border
22804             if ( x < sl && sl > 0 && x - sl < thresh ) {
22805                 window.scrollTo(sl - scrAmt, st);
22806             }
22807         }
22808     },
22809
22810     /**
22811      * Finds the location the element should be placed if we want to move
22812      * it to where the mouse location less the click offset would place us.
22813      * @method getTargetCoord
22814      * @param {int} iPageX the X coordinate of the click
22815      * @param {int} iPageY the Y coordinate of the click
22816      * @return an object that contains the coordinates (Object.x and Object.y)
22817      * @private
22818      */
22819     getTargetCoord: function(iPageX, iPageY) {
22820
22821
22822         var x = iPageX - this.deltaX;
22823         var y = iPageY - this.deltaY;
22824
22825         if (this.constrainX) {
22826             if (x < this.minX) { x = this.minX; }
22827             if (x > this.maxX) { x = this.maxX; }
22828         }
22829
22830         if (this.constrainY) {
22831             if (y < this.minY) { y = this.minY; }
22832             if (y > this.maxY) { y = this.maxY; }
22833         }
22834
22835         x = this.getTick(x, this.xTicks);
22836         y = this.getTick(y, this.yTicks);
22837
22838
22839         return {x:x, y:y};
22840     },
22841
22842     /*
22843      * Sets up config options specific to this class. Overrides
22844      * Roo.dd.DragDrop, but all versions of this method through the
22845      * inheritance chain are called
22846      */
22847     applyConfig: function() {
22848         Roo.dd.DD.superclass.applyConfig.call(this);
22849         this.scroll = (this.config.scroll !== false);
22850     },
22851
22852     /*
22853      * Event that fires prior to the onMouseDown event.  Overrides
22854      * Roo.dd.DragDrop.
22855      */
22856     b4MouseDown: function(e) {
22857         // this.resetConstraints();
22858         this.autoOffset(e.getPageX(),
22859                             e.getPageY());
22860     },
22861
22862     /*
22863      * Event that fires prior to the onDrag event.  Overrides
22864      * Roo.dd.DragDrop.
22865      */
22866     b4Drag: function(e) {
22867         this.setDragElPos(e.getPageX(),
22868                             e.getPageY());
22869     },
22870
22871     toString: function() {
22872         return ("DD " + this.id);
22873     }
22874
22875     //////////////////////////////////////////////////////////////////////////
22876     // Debugging ygDragDrop events that can be overridden
22877     //////////////////////////////////////////////////////////////////////////
22878     /*
22879     startDrag: function(x, y) {
22880     },
22881
22882     onDrag: function(e) {
22883     },
22884
22885     onDragEnter: function(e, id) {
22886     },
22887
22888     onDragOver: function(e, id) {
22889     },
22890
22891     onDragOut: function(e, id) {
22892     },
22893
22894     onDragDrop: function(e, id) {
22895     },
22896
22897     endDrag: function(e) {
22898     }
22899
22900     */
22901
22902 });/*
22903  * Based on:
22904  * Ext JS Library 1.1.1
22905  * Copyright(c) 2006-2007, Ext JS, LLC.
22906  *
22907  * Originally Released Under LGPL - original licence link has changed is not relivant.
22908  *
22909  * Fork - LGPL
22910  * <script type="text/javascript">
22911  */
22912
22913 /**
22914  * @class Roo.dd.DDProxy
22915  * A DragDrop implementation that inserts an empty, bordered div into
22916  * the document that follows the cursor during drag operations.  At the time of
22917  * the click, the frame div is resized to the dimensions of the linked html
22918  * element, and moved to the exact location of the linked element.
22919  *
22920  * References to the "frame" element refer to the single proxy element that
22921  * was created to be dragged in place of all DDProxy elements on the
22922  * page.
22923  *
22924  * @extends Roo.dd.DD
22925  * @constructor
22926  * @param {String} id the id of the linked html element
22927  * @param {String} sGroup the group of related DragDrop objects
22928  * @param {object} config an object containing configurable attributes
22929  *                Valid properties for DDProxy in addition to those in DragDrop:
22930  *                   resizeFrame, centerFrame, dragElId
22931  */
22932 Roo.dd.DDProxy = function(id, sGroup, config) {
22933     if (id) {
22934         this.init(id, sGroup, config);
22935         this.initFrame();
22936     }
22937 };
22938
22939 /**
22940  * The default drag frame div id
22941  * @property Roo.dd.DDProxy.dragElId
22942  * @type String
22943  * @static
22944  */
22945 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22946
22947 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22948
22949     /**
22950      * By default we resize the drag frame to be the same size as the element
22951      * we want to drag (this is to get the frame effect).  We can turn it off
22952      * if we want a different behavior.
22953      * @property resizeFrame
22954      * @type boolean
22955      */
22956     resizeFrame: true,
22957
22958     /**
22959      * By default the frame is positioned exactly where the drag element is, so
22960      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22961      * you do not have constraints on the obj is to have the drag frame centered
22962      * around the cursor.  Set centerFrame to true for this effect.
22963      * @property centerFrame
22964      * @type boolean
22965      */
22966     centerFrame: false,
22967
22968     /**
22969      * Creates the proxy element if it does not yet exist
22970      * @method createFrame
22971      */
22972     createFrame: function() {
22973         var self = this;
22974         var body = document.body;
22975
22976         if (!body || !body.firstChild) {
22977             setTimeout( function() { self.createFrame(); }, 50 );
22978             return;
22979         }
22980
22981         var div = this.getDragEl();
22982
22983         if (!div) {
22984             div    = document.createElement("div");
22985             div.id = this.dragElId;
22986             var s  = div.style;
22987
22988             s.position   = "absolute";
22989             s.visibility = "hidden";
22990             s.cursor     = "move";
22991             s.border     = "2px solid #aaa";
22992             s.zIndex     = 999;
22993
22994             // appendChild can blow up IE if invoked prior to the window load event
22995             // while rendering a table.  It is possible there are other scenarios
22996             // that would cause this to happen as well.
22997             body.insertBefore(div, body.firstChild);
22998         }
22999     },
23000
23001     /**
23002      * Initialization for the drag frame element.  Must be called in the
23003      * constructor of all subclasses
23004      * @method initFrame
23005      */
23006     initFrame: function() {
23007         this.createFrame();
23008     },
23009
23010     applyConfig: function() {
23011         Roo.dd.DDProxy.superclass.applyConfig.call(this);
23012
23013         this.resizeFrame = (this.config.resizeFrame !== false);
23014         this.centerFrame = (this.config.centerFrame);
23015         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
23016     },
23017
23018     /**
23019      * Resizes the drag frame to the dimensions of the clicked object, positions
23020      * it over the object, and finally displays it
23021      * @method showFrame
23022      * @param {int} iPageX X click position
23023      * @param {int} iPageY Y click position
23024      * @private
23025      */
23026     showFrame: function(iPageX, iPageY) {
23027         var el = this.getEl();
23028         var dragEl = this.getDragEl();
23029         var s = dragEl.style;
23030
23031         this._resizeProxy();
23032
23033         if (this.centerFrame) {
23034             this.setDelta( Math.round(parseInt(s.width,  10)/2),
23035                            Math.round(parseInt(s.height, 10)/2) );
23036         }
23037
23038         this.setDragElPos(iPageX, iPageY);
23039
23040         Roo.fly(dragEl).show();
23041     },
23042
23043     /**
23044      * The proxy is automatically resized to the dimensions of the linked
23045      * element when a drag is initiated, unless resizeFrame is set to false
23046      * @method _resizeProxy
23047      * @private
23048      */
23049     _resizeProxy: function() {
23050         if (this.resizeFrame) {
23051             var el = this.getEl();
23052             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
23053         }
23054     },
23055
23056     // overrides Roo.dd.DragDrop
23057     b4MouseDown: function(e) {
23058         var x = e.getPageX();
23059         var y = e.getPageY();
23060         this.autoOffset(x, y);
23061         this.setDragElPos(x, y);
23062     },
23063
23064     // overrides Roo.dd.DragDrop
23065     b4StartDrag: function(x, y) {
23066         // show the drag frame
23067         this.showFrame(x, y);
23068     },
23069
23070     // overrides Roo.dd.DragDrop
23071     b4EndDrag: function(e) {
23072         Roo.fly(this.getDragEl()).hide();
23073     },
23074
23075     // overrides Roo.dd.DragDrop
23076     // By default we try to move the element to the last location of the frame.
23077     // This is so that the default behavior mirrors that of Roo.dd.DD.
23078     endDrag: function(e) {
23079
23080         var lel = this.getEl();
23081         var del = this.getDragEl();
23082
23083         // Show the drag frame briefly so we can get its position
23084         del.style.visibility = "";
23085
23086         this.beforeMove();
23087         // Hide the linked element before the move to get around a Safari
23088         // rendering bug.
23089         lel.style.visibility = "hidden";
23090         Roo.dd.DDM.moveToEl(lel, del);
23091         del.style.visibility = "hidden";
23092         lel.style.visibility = "";
23093
23094         this.afterDrag();
23095     },
23096
23097     beforeMove : function(){
23098
23099     },
23100
23101     afterDrag : function(){
23102
23103     },
23104
23105     toString: function() {
23106         return ("DDProxy " + this.id);
23107     }
23108
23109 });
23110 /*
23111  * Based on:
23112  * Ext JS Library 1.1.1
23113  * Copyright(c) 2006-2007, Ext JS, LLC.
23114  *
23115  * Originally Released Under LGPL - original licence link has changed is not relivant.
23116  *
23117  * Fork - LGPL
23118  * <script type="text/javascript">
23119  */
23120
23121  /**
23122  * @class Roo.dd.DDTarget
23123  * A DragDrop implementation that does not move, but can be a drop
23124  * target.  You would get the same result by simply omitting implementation
23125  * for the event callbacks, but this way we reduce the processing cost of the
23126  * event listener and the callbacks.
23127  * @extends Roo.dd.DragDrop
23128  * @constructor
23129  * @param {String} id the id of the element that is a drop target
23130  * @param {String} sGroup the group of related DragDrop objects
23131  * @param {object} config an object containing configurable attributes
23132  *                 Valid properties for DDTarget in addition to those in
23133  *                 DragDrop:
23134  *                    none
23135  */
23136 Roo.dd.DDTarget = function(id, sGroup, config) {
23137     if (id) {
23138         this.initTarget(id, sGroup, config);
23139     }
23140     if (config && (config.listeners || config.events)) { 
23141         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
23142             listeners : config.listeners || {}, 
23143             events : config.events || {} 
23144         });    
23145     }
23146 };
23147
23148 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
23149 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
23150     toString: function() {
23151         return ("DDTarget " + this.id);
23152     }
23153 });
23154 /*
23155  * Based on:
23156  * Ext JS Library 1.1.1
23157  * Copyright(c) 2006-2007, Ext JS, LLC.
23158  *
23159  * Originally Released Under LGPL - original licence link has changed is not relivant.
23160  *
23161  * Fork - LGPL
23162  * <script type="text/javascript">
23163  */
23164  
23165
23166 /**
23167  * @class Roo.dd.ScrollManager
23168  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
23169  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
23170  * @static
23171  */
23172 Roo.dd.ScrollManager = function(){
23173     var ddm = Roo.dd.DragDropMgr;
23174     var els = {};
23175     var dragEl = null;
23176     var proc = {};
23177     
23178     
23179     
23180     var onStop = function(e){
23181         dragEl = null;
23182         clearProc();
23183     };
23184     
23185     var triggerRefresh = function(){
23186         if(ddm.dragCurrent){
23187              ddm.refreshCache(ddm.dragCurrent.groups);
23188         }
23189     };
23190     
23191     var doScroll = function(){
23192         if(ddm.dragCurrent){
23193             var dds = Roo.dd.ScrollManager;
23194             if(!dds.animate){
23195                 if(proc.el.scroll(proc.dir, dds.increment)){
23196                     triggerRefresh();
23197                 }
23198             }else{
23199                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23200             }
23201         }
23202     };
23203     
23204     var clearProc = function(){
23205         if(proc.id){
23206             clearInterval(proc.id);
23207         }
23208         proc.id = 0;
23209         proc.el = null;
23210         proc.dir = "";
23211     };
23212     
23213     var startProc = function(el, dir){
23214          Roo.log('scroll startproc');
23215         clearProc();
23216         proc.el = el;
23217         proc.dir = dir;
23218         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23219     };
23220     
23221     var onFire = function(e, isDrop){
23222        
23223         if(isDrop || !ddm.dragCurrent){ return; }
23224         var dds = Roo.dd.ScrollManager;
23225         if(!dragEl || dragEl != ddm.dragCurrent){
23226             dragEl = ddm.dragCurrent;
23227             // refresh regions on drag start
23228             dds.refreshCache();
23229         }
23230         
23231         var xy = Roo.lib.Event.getXY(e);
23232         var pt = new Roo.lib.Point(xy[0], xy[1]);
23233         for(var id in els){
23234             var el = els[id], r = el._region;
23235             if(r && r.contains(pt) && el.isScrollable()){
23236                 if(r.bottom - pt.y <= dds.thresh){
23237                     if(proc.el != el){
23238                         startProc(el, "down");
23239                     }
23240                     return;
23241                 }else if(r.right - pt.x <= dds.thresh){
23242                     if(proc.el != el){
23243                         startProc(el, "left");
23244                     }
23245                     return;
23246                 }else if(pt.y - r.top <= dds.thresh){
23247                     if(proc.el != el){
23248                         startProc(el, "up");
23249                     }
23250                     return;
23251                 }else if(pt.x - r.left <= dds.thresh){
23252                     if(proc.el != el){
23253                         startProc(el, "right");
23254                     }
23255                     return;
23256                 }
23257             }
23258         }
23259         clearProc();
23260     };
23261     
23262     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23263     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23264     
23265     return {
23266         /**
23267          * Registers new overflow element(s) to auto scroll
23268          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23269          */
23270         register : function(el){
23271             if(el instanceof Array){
23272                 for(var i = 0, len = el.length; i < len; i++) {
23273                         this.register(el[i]);
23274                 }
23275             }else{
23276                 el = Roo.get(el);
23277                 els[el.id] = el;
23278             }
23279             Roo.dd.ScrollManager.els = els;
23280         },
23281         
23282         /**
23283          * Unregisters overflow element(s) so they are no longer scrolled
23284          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23285          */
23286         unregister : function(el){
23287             if(el instanceof Array){
23288                 for(var i = 0, len = el.length; i < len; i++) {
23289                         this.unregister(el[i]);
23290                 }
23291             }else{
23292                 el = Roo.get(el);
23293                 delete els[el.id];
23294             }
23295         },
23296         
23297         /**
23298          * The number of pixels from the edge of a container the pointer needs to be to 
23299          * trigger scrolling (defaults to 25)
23300          * @type Number
23301          */
23302         thresh : 25,
23303         
23304         /**
23305          * The number of pixels to scroll in each scroll increment (defaults to 50)
23306          * @type Number
23307          */
23308         increment : 100,
23309         
23310         /**
23311          * The frequency of scrolls in milliseconds (defaults to 500)
23312          * @type Number
23313          */
23314         frequency : 500,
23315         
23316         /**
23317          * True to animate the scroll (defaults to true)
23318          * @type Boolean
23319          */
23320         animate: true,
23321         
23322         /**
23323          * The animation duration in seconds - 
23324          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23325          * @type Number
23326          */
23327         animDuration: .4,
23328         
23329         /**
23330          * Manually trigger a cache refresh.
23331          */
23332         refreshCache : function(){
23333             for(var id in els){
23334                 if(typeof els[id] == 'object'){ // for people extending the object prototype
23335                     els[id]._region = els[id].getRegion();
23336                 }
23337             }
23338         }
23339     };
23340 }();/*
23341  * Based on:
23342  * Ext JS Library 1.1.1
23343  * Copyright(c) 2006-2007, Ext JS, LLC.
23344  *
23345  * Originally Released Under LGPL - original licence link has changed is not relivant.
23346  *
23347  * Fork - LGPL
23348  * <script type="text/javascript">
23349  */
23350  
23351
23352 /**
23353  * @class Roo.dd.Registry
23354  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
23355  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23356  * @static
23357  */
23358 Roo.dd.Registry = function(){
23359     var elements = {}; 
23360     var handles = {}; 
23361     var autoIdSeed = 0;
23362
23363     var getId = function(el, autogen){
23364         if(typeof el == "string"){
23365             return el;
23366         }
23367         var id = el.id;
23368         if(!id && autogen !== false){
23369             id = "roodd-" + (++autoIdSeed);
23370             el.id = id;
23371         }
23372         return id;
23373     };
23374     
23375     return {
23376     /**
23377      * Register a drag drop element
23378      * @param {String|HTMLElement} element The id or DOM node to register
23379      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23380      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
23381      * knows how to interpret, plus there are some specific properties known to the Registry that should be
23382      * populated in the data object (if applicable):
23383      * <pre>
23384 Value      Description<br />
23385 ---------  ------------------------------------------<br />
23386 handles    Array of DOM nodes that trigger dragging<br />
23387            for the element being registered<br />
23388 isHandle   True if the element passed in triggers<br />
23389            dragging itself, else false
23390 </pre>
23391      */
23392         register : function(el, data){
23393             data = data || {};
23394             if(typeof el == "string"){
23395                 el = document.getElementById(el);
23396             }
23397             data.ddel = el;
23398             elements[getId(el)] = data;
23399             if(data.isHandle !== false){
23400                 handles[data.ddel.id] = data;
23401             }
23402             if(data.handles){
23403                 var hs = data.handles;
23404                 for(var i = 0, len = hs.length; i < len; i++){
23405                         handles[getId(hs[i])] = data;
23406                 }
23407             }
23408         },
23409
23410     /**
23411      * Unregister a drag drop element
23412      * @param {String|HTMLElement}  element The id or DOM node to unregister
23413      */
23414         unregister : function(el){
23415             var id = getId(el, false);
23416             var data = elements[id];
23417             if(data){
23418                 delete elements[id];
23419                 if(data.handles){
23420                     var hs = data.handles;
23421                     for(var i = 0, len = hs.length; i < len; i++){
23422                         delete handles[getId(hs[i], false)];
23423                     }
23424                 }
23425             }
23426         },
23427
23428     /**
23429      * Returns the handle registered for a DOM Node by id
23430      * @param {String|HTMLElement} id The DOM node or id to look up
23431      * @return {Object} handle The custom handle data
23432      */
23433         getHandle : function(id){
23434             if(typeof id != "string"){ // must be element?
23435                 id = id.id;
23436             }
23437             return handles[id];
23438         },
23439
23440     /**
23441      * Returns the handle that is registered for the DOM node that is the target of the event
23442      * @param {Event} e The event
23443      * @return {Object} handle The custom handle data
23444      */
23445         getHandleFromEvent : function(e){
23446             var t = Roo.lib.Event.getTarget(e);
23447             return t ? handles[t.id] : null;
23448         },
23449
23450     /**
23451      * Returns a custom data object that is registered for a DOM node by id
23452      * @param {String|HTMLElement} id The DOM node or id to look up
23453      * @return {Object} data The custom data
23454      */
23455         getTarget : function(id){
23456             if(typeof id != "string"){ // must be element?
23457                 id = id.id;
23458             }
23459             return elements[id];
23460         },
23461
23462     /**
23463      * Returns a custom data object that is registered for the DOM node that is the target of the event
23464      * @param {Event} e The event
23465      * @return {Object} data The custom data
23466      */
23467         getTargetFromEvent : function(e){
23468             var t = Roo.lib.Event.getTarget(e);
23469             return t ? elements[t.id] || handles[t.id] : null;
23470         }
23471     };
23472 }();/*
23473  * Based on:
23474  * Ext JS Library 1.1.1
23475  * Copyright(c) 2006-2007, Ext JS, LLC.
23476  *
23477  * Originally Released Under LGPL - original licence link has changed is not relivant.
23478  *
23479  * Fork - LGPL
23480  * <script type="text/javascript">
23481  */
23482  
23483
23484 /**
23485  * @class Roo.dd.StatusProxy
23486  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23487  * default drag proxy used by all Roo.dd components.
23488  * @constructor
23489  * @param {Object} config
23490  */
23491 Roo.dd.StatusProxy = function(config){
23492     Roo.apply(this, config);
23493     this.id = this.id || Roo.id();
23494     this.el = new Roo.Layer({
23495         dh: {
23496             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23497                 {tag: "div", cls: "x-dd-drop-icon"},
23498                 {tag: "div", cls: "x-dd-drag-ghost"}
23499             ]
23500         }, 
23501         shadow: !config || config.shadow !== false
23502     });
23503     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23504     this.dropStatus = this.dropNotAllowed;
23505 };
23506
23507 Roo.dd.StatusProxy.prototype = {
23508     /**
23509      * @cfg {String} dropAllowed
23510      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23511      */
23512     dropAllowed : "x-dd-drop-ok",
23513     /**
23514      * @cfg {String} dropNotAllowed
23515      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23516      */
23517     dropNotAllowed : "x-dd-drop-nodrop",
23518
23519     /**
23520      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23521      * over the current target element.
23522      * @param {String} cssClass The css class for the new drop status indicator image
23523      */
23524     setStatus : function(cssClass){
23525         cssClass = cssClass || this.dropNotAllowed;
23526         if(this.dropStatus != cssClass){
23527             this.el.replaceClass(this.dropStatus, cssClass);
23528             this.dropStatus = cssClass;
23529         }
23530     },
23531
23532     /**
23533      * Resets the status indicator to the default dropNotAllowed value
23534      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23535      */
23536     reset : function(clearGhost){
23537         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23538         this.dropStatus = this.dropNotAllowed;
23539         if(clearGhost){
23540             this.ghost.update("");
23541         }
23542     },
23543
23544     /**
23545      * Updates the contents of the ghost element
23546      * @param {String} html The html that will replace the current innerHTML of the ghost element
23547      */
23548     update : function(html){
23549         if(typeof html == "string"){
23550             this.ghost.update(html);
23551         }else{
23552             this.ghost.update("");
23553             html.style.margin = "0";
23554             this.ghost.dom.appendChild(html);
23555         }
23556         // ensure float = none set?? cant remember why though.
23557         var el = this.ghost.dom.firstChild;
23558                 if(el){
23559                         Roo.fly(el).setStyle('float', 'none');
23560                 }
23561     },
23562     
23563     /**
23564      * Returns the underlying proxy {@link Roo.Layer}
23565      * @return {Roo.Layer} el
23566     */
23567     getEl : function(){
23568         return this.el;
23569     },
23570
23571     /**
23572      * Returns the ghost element
23573      * @return {Roo.Element} el
23574      */
23575     getGhost : function(){
23576         return this.ghost;
23577     },
23578
23579     /**
23580      * Hides the proxy
23581      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23582      */
23583     hide : function(clear){
23584         this.el.hide();
23585         if(clear){
23586             this.reset(true);
23587         }
23588     },
23589
23590     /**
23591      * Stops the repair animation if it's currently running
23592      */
23593     stop : function(){
23594         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23595             this.anim.stop();
23596         }
23597     },
23598
23599     /**
23600      * Displays this proxy
23601      */
23602     show : function(){
23603         this.el.show();
23604     },
23605
23606     /**
23607      * Force the Layer to sync its shadow and shim positions to the element
23608      */
23609     sync : function(){
23610         this.el.sync();
23611     },
23612
23613     /**
23614      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23615      * invalid drop operation by the item being dragged.
23616      * @param {Array} xy The XY position of the element ([x, y])
23617      * @param {Function} callback The function to call after the repair is complete
23618      * @param {Object} scope The scope in which to execute the callback
23619      */
23620     repair : function(xy, callback, scope){
23621         this.callback = callback;
23622         this.scope = scope;
23623         if(xy && this.animRepair !== false){
23624             this.el.addClass("x-dd-drag-repair");
23625             this.el.hideUnders(true);
23626             this.anim = this.el.shift({
23627                 duration: this.repairDuration || .5,
23628                 easing: 'easeOut',
23629                 xy: xy,
23630                 stopFx: true,
23631                 callback: this.afterRepair,
23632                 scope: this
23633             });
23634         }else{
23635             this.afterRepair();
23636         }
23637     },
23638
23639     // private
23640     afterRepair : function(){
23641         this.hide(true);
23642         if(typeof this.callback == "function"){
23643             this.callback.call(this.scope || this);
23644         }
23645         this.callback = null;
23646         this.scope = null;
23647     }
23648 };/*
23649  * Based on:
23650  * Ext JS Library 1.1.1
23651  * Copyright(c) 2006-2007, Ext JS, LLC.
23652  *
23653  * Originally Released Under LGPL - original licence link has changed is not relivant.
23654  *
23655  * Fork - LGPL
23656  * <script type="text/javascript">
23657  */
23658
23659 /**
23660  * @class Roo.dd.DragSource
23661  * @extends Roo.dd.DDProxy
23662  * A simple class that provides the basic implementation needed to make any element draggable.
23663  * @constructor
23664  * @param {String/HTMLElement/Element} el The container element
23665  * @param {Object} config
23666  */
23667 Roo.dd.DragSource = function(el, config){
23668     this.el = Roo.get(el);
23669     this.dragData = {};
23670     
23671     Roo.apply(this, config);
23672     
23673     if(!this.proxy){
23674         this.proxy = new Roo.dd.StatusProxy();
23675     }
23676
23677     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23678           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23679     
23680     this.dragging = false;
23681 };
23682
23683 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23684     /**
23685      * @cfg {String} dropAllowed
23686      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23687      */
23688     dropAllowed : "x-dd-drop-ok",
23689     /**
23690      * @cfg {String} dropNotAllowed
23691      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23692      */
23693     dropNotAllowed : "x-dd-drop-nodrop",
23694
23695     /**
23696      * Returns the data object associated with this drag source
23697      * @return {Object} data An object containing arbitrary data
23698      */
23699     getDragData : function(e){
23700         return this.dragData;
23701     },
23702
23703     // private
23704     onDragEnter : function(e, id){
23705         var target = Roo.dd.DragDropMgr.getDDById(id);
23706         this.cachedTarget = target;
23707         if(this.beforeDragEnter(target, e, id) !== false){
23708             if(target.isNotifyTarget){
23709                 var status = target.notifyEnter(this, e, this.dragData);
23710                 this.proxy.setStatus(status);
23711             }else{
23712                 this.proxy.setStatus(this.dropAllowed);
23713             }
23714             
23715             if(this.afterDragEnter){
23716                 /**
23717                  * An empty function by default, but provided so that you can perform a custom action
23718                  * when the dragged item enters the drop target by providing an implementation.
23719                  * @param {Roo.dd.DragDrop} target The drop target
23720                  * @param {Event} e The event object
23721                  * @param {String} id The id of the dragged element
23722                  * @method afterDragEnter
23723                  */
23724                 this.afterDragEnter(target, e, id);
23725             }
23726         }
23727     },
23728
23729     /**
23730      * An empty function by default, but provided so that you can perform a custom action
23731      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23732      * @param {Roo.dd.DragDrop} target The drop target
23733      * @param {Event} e The event object
23734      * @param {String} id The id of the dragged element
23735      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23736      */
23737     beforeDragEnter : function(target, e, id){
23738         return true;
23739     },
23740
23741     // private
23742     alignElWithMouse: function() {
23743         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23744         this.proxy.sync();
23745     },
23746
23747     // private
23748     onDragOver : function(e, id){
23749         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23750         if(this.beforeDragOver(target, e, id) !== false){
23751             if(target.isNotifyTarget){
23752                 var status = target.notifyOver(this, e, this.dragData);
23753                 this.proxy.setStatus(status);
23754             }
23755
23756             if(this.afterDragOver){
23757                 /**
23758                  * An empty function by default, but provided so that you can perform a custom action
23759                  * while the dragged item is over the drop target by providing an implementation.
23760                  * @param {Roo.dd.DragDrop} target The drop target
23761                  * @param {Event} e The event object
23762                  * @param {String} id The id of the dragged element
23763                  * @method afterDragOver
23764                  */
23765                 this.afterDragOver(target, e, id);
23766             }
23767         }
23768     },
23769
23770     /**
23771      * An empty function by default, but provided so that you can perform a custom action
23772      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23773      * @param {Roo.dd.DragDrop} target The drop target
23774      * @param {Event} e The event object
23775      * @param {String} id The id of the dragged element
23776      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23777      */
23778     beforeDragOver : function(target, e, id){
23779         return true;
23780     },
23781
23782     // private
23783     onDragOut : function(e, id){
23784         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23785         if(this.beforeDragOut(target, e, id) !== false){
23786             if(target.isNotifyTarget){
23787                 target.notifyOut(this, e, this.dragData);
23788             }
23789             this.proxy.reset();
23790             if(this.afterDragOut){
23791                 /**
23792                  * An empty function by default, but provided so that you can perform a custom action
23793                  * after the dragged item is dragged out of the target without dropping.
23794                  * @param {Roo.dd.DragDrop} target The drop target
23795                  * @param {Event} e The event object
23796                  * @param {String} id The id of the dragged element
23797                  * @method afterDragOut
23798                  */
23799                 this.afterDragOut(target, e, id);
23800             }
23801         }
23802         this.cachedTarget = null;
23803     },
23804
23805     /**
23806      * An empty function by default, but provided so that you can perform a custom action before the dragged
23807      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23808      * @param {Roo.dd.DragDrop} target The drop target
23809      * @param {Event} e The event object
23810      * @param {String} id The id of the dragged element
23811      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23812      */
23813     beforeDragOut : function(target, e, id){
23814         return true;
23815     },
23816     
23817     // private
23818     onDragDrop : function(e, id){
23819         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23820         if(this.beforeDragDrop(target, e, id) !== false){
23821             if(target.isNotifyTarget){
23822                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23823                     this.onValidDrop(target, e, id);
23824                 }else{
23825                     this.onInvalidDrop(target, e, id);
23826                 }
23827             }else{
23828                 this.onValidDrop(target, e, id);
23829             }
23830             
23831             if(this.afterDragDrop){
23832                 /**
23833                  * An empty function by default, but provided so that you can perform a custom action
23834                  * after a valid drag drop has occurred by providing an implementation.
23835                  * @param {Roo.dd.DragDrop} target The drop target
23836                  * @param {Event} e The event object
23837                  * @param {String} id The id of the dropped element
23838                  * @method afterDragDrop
23839                  */
23840                 this.afterDragDrop(target, e, id);
23841             }
23842         }
23843         delete this.cachedTarget;
23844     },
23845
23846     /**
23847      * An empty function by default, but provided so that you can perform a custom action before the dragged
23848      * item is dropped onto the target and optionally cancel the onDragDrop.
23849      * @param {Roo.dd.DragDrop} target The drop target
23850      * @param {Event} e The event object
23851      * @param {String} id The id of the dragged element
23852      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23853      */
23854     beforeDragDrop : function(target, e, id){
23855         return true;
23856     },
23857
23858     // private
23859     onValidDrop : function(target, e, id){
23860         this.hideProxy();
23861         if(this.afterValidDrop){
23862             /**
23863              * An empty function by default, but provided so that you can perform a custom action
23864              * after a valid drop has occurred by providing an implementation.
23865              * @param {Object} target The target DD 
23866              * @param {Event} e The event object
23867              * @param {String} id The id of the dropped element
23868              * @method afterInvalidDrop
23869              */
23870             this.afterValidDrop(target, e, id);
23871         }
23872     },
23873
23874     // private
23875     getRepairXY : function(e, data){
23876         return this.el.getXY();  
23877     },
23878
23879     // private
23880     onInvalidDrop : function(target, e, id){
23881         this.beforeInvalidDrop(target, e, id);
23882         if(this.cachedTarget){
23883             if(this.cachedTarget.isNotifyTarget){
23884                 this.cachedTarget.notifyOut(this, e, this.dragData);
23885             }
23886             this.cacheTarget = null;
23887         }
23888         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23889
23890         if(this.afterInvalidDrop){
23891             /**
23892              * An empty function by default, but provided so that you can perform a custom action
23893              * after an invalid drop has occurred by providing an implementation.
23894              * @param {Event} e The event object
23895              * @param {String} id The id of the dropped element
23896              * @method afterInvalidDrop
23897              */
23898             this.afterInvalidDrop(e, id);
23899         }
23900     },
23901
23902     // private
23903     afterRepair : function(){
23904         if(Roo.enableFx){
23905             this.el.highlight(this.hlColor || "c3daf9");
23906         }
23907         this.dragging = false;
23908     },
23909
23910     /**
23911      * An empty function by default, but provided so that you can perform a custom action after an invalid
23912      * drop has occurred.
23913      * @param {Roo.dd.DragDrop} target The drop target
23914      * @param {Event} e The event object
23915      * @param {String} id The id of the dragged element
23916      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23917      */
23918     beforeInvalidDrop : function(target, e, id){
23919         return true;
23920     },
23921
23922     // private
23923     handleMouseDown : function(e){
23924         if(this.dragging) {
23925             return;
23926         }
23927         var data = this.getDragData(e);
23928         if(data && this.onBeforeDrag(data, e) !== false){
23929             this.dragData = data;
23930             this.proxy.stop();
23931             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23932         } 
23933     },
23934
23935     /**
23936      * An empty function by default, but provided so that you can perform a custom action before the initial
23937      * drag event begins and optionally cancel it.
23938      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23939      * @param {Event} e The event object
23940      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23941      */
23942     onBeforeDrag : function(data, e){
23943         return true;
23944     },
23945
23946     /**
23947      * An empty function by default, but provided so that you can perform a custom action once the initial
23948      * drag event has begun.  The drag cannot be canceled from this function.
23949      * @param {Number} x The x position of the click on the dragged object
23950      * @param {Number} y The y position of the click on the dragged object
23951      */
23952     onStartDrag : Roo.emptyFn,
23953
23954     // private - YUI override
23955     startDrag : function(x, y){
23956         this.proxy.reset();
23957         this.dragging = true;
23958         this.proxy.update("");
23959         this.onInitDrag(x, y);
23960         this.proxy.show();
23961     },
23962
23963     // private
23964     onInitDrag : function(x, y){
23965         var clone = this.el.dom.cloneNode(true);
23966         clone.id = Roo.id(); // prevent duplicate ids
23967         this.proxy.update(clone);
23968         this.onStartDrag(x, y);
23969         return true;
23970     },
23971
23972     /**
23973      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23974      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23975      */
23976     getProxy : function(){
23977         return this.proxy;  
23978     },
23979
23980     /**
23981      * Hides the drag source's {@link Roo.dd.StatusProxy}
23982      */
23983     hideProxy : function(){
23984         this.proxy.hide();  
23985         this.proxy.reset(true);
23986         this.dragging = false;
23987     },
23988
23989     // private
23990     triggerCacheRefresh : function(){
23991         Roo.dd.DDM.refreshCache(this.groups);
23992     },
23993
23994     // private - override to prevent hiding
23995     b4EndDrag: function(e) {
23996     },
23997
23998     // private - override to prevent moving
23999     endDrag : function(e){
24000         this.onEndDrag(this.dragData, e);
24001     },
24002
24003     // private
24004     onEndDrag : function(data, e){
24005     },
24006     
24007     // private - pin to cursor
24008     autoOffset : function(x, y) {
24009         this.setDelta(-12, -20);
24010     }    
24011 });/*
24012  * Based on:
24013  * Ext JS Library 1.1.1
24014  * Copyright(c) 2006-2007, Ext JS, LLC.
24015  *
24016  * Originally Released Under LGPL - original licence link has changed is not relivant.
24017  *
24018  * Fork - LGPL
24019  * <script type="text/javascript">
24020  */
24021
24022
24023 /**
24024  * @class Roo.dd.DropTarget
24025  * @extends Roo.dd.DDTarget
24026  * A simple class that provides the basic implementation needed to make any element a drop target that can have
24027  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
24028  * @constructor
24029  * @param {String/HTMLElement/Element} el The container element
24030  * @param {Object} config
24031  */
24032 Roo.dd.DropTarget = function(el, config){
24033     this.el = Roo.get(el);
24034     
24035     var listeners = false; ;
24036     if (config && config.listeners) {
24037         listeners= config.listeners;
24038         delete config.listeners;
24039     }
24040     Roo.apply(this, config);
24041     
24042     if(this.containerScroll){
24043         Roo.dd.ScrollManager.register(this.el);
24044     }
24045     this.addEvents( {
24046          /**
24047          * @scope Roo.dd.DropTarget
24048          */
24049          
24050          /**
24051          * @event enter
24052          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
24053          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
24054          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
24055          * 
24056          * IMPORTANT : it should set  this.valid to true|false
24057          * 
24058          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24059          * @param {Event} e The event
24060          * @param {Object} data An object containing arbitrary data supplied by the drag source
24061          */
24062         "enter" : true,
24063         
24064          /**
24065          * @event over
24066          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
24067          * This method will be called on every mouse movement while the drag source is over the drop target.
24068          * This default implementation simply returns the dropAllowed config value.
24069          * 
24070          * IMPORTANT : it should set  this.valid to true|false
24071          * 
24072          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24073          * @param {Event} e The event
24074          * @param {Object} data An object containing arbitrary data supplied by the drag source
24075          
24076          */
24077         "over" : true,
24078         /**
24079          * @event out
24080          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
24081          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
24082          * overClass (if any) from the drop element.
24083          * 
24084          * 
24085          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24086          * @param {Event} e The event
24087          * @param {Object} data An object containing arbitrary data supplied by the drag source
24088          */
24089          "out" : true,
24090          
24091         /**
24092          * @event drop
24093          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
24094          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
24095          * implementation that does something to process the drop event and returns true so that the drag source's
24096          * repair action does not run.
24097          * 
24098          * IMPORTANT : it should set this.success
24099          * 
24100          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24101          * @param {Event} e The event
24102          * @param {Object} data An object containing arbitrary data supplied by the drag source
24103         */
24104          "drop" : true
24105     });
24106             
24107      
24108     Roo.dd.DropTarget.superclass.constructor.call(  this, 
24109         this.el.dom, 
24110         this.ddGroup || this.group,
24111         {
24112             isTarget: true,
24113             listeners : listeners || {} 
24114            
24115         
24116         }
24117     );
24118
24119 };
24120
24121 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
24122     /**
24123      * @cfg {String} overClass
24124      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
24125      */
24126      /**
24127      * @cfg {String} ddGroup
24128      * The drag drop group to handle drop events for
24129      */
24130      
24131     /**
24132      * @cfg {String} dropAllowed
24133      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
24134      */
24135     dropAllowed : "x-dd-drop-ok",
24136     /**
24137      * @cfg {String} dropNotAllowed
24138      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
24139      */
24140     dropNotAllowed : "x-dd-drop-nodrop",
24141     /**
24142      * @cfg {boolean} success
24143      * set this after drop listener.. 
24144      */
24145     success : false,
24146     /**
24147      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
24148      * if the drop point is valid for over/enter..
24149      */
24150     valid : false,
24151     // private
24152     isTarget : true,
24153
24154     // private
24155     isNotifyTarget : true,
24156     
24157     /**
24158      * @hide
24159      */
24160     notifyEnter : function(dd, e, data)
24161     {
24162         this.valid = true;
24163         this.fireEvent('enter', dd, e, data);
24164         if(this.overClass){
24165             this.el.addClass(this.overClass);
24166         }
24167         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24168             this.valid ? this.dropAllowed : this.dropNotAllowed
24169         );
24170     },
24171
24172     /**
24173      * @hide
24174      */
24175     notifyOver : function(dd, e, data)
24176     {
24177         this.valid = true;
24178         this.fireEvent('over', dd, e, data);
24179         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24180             this.valid ? this.dropAllowed : this.dropNotAllowed
24181         );
24182     },
24183
24184     /**
24185      * @hide
24186      */
24187     notifyOut : function(dd, e, data)
24188     {
24189         this.fireEvent('out', dd, e, data);
24190         if(this.overClass){
24191             this.el.removeClass(this.overClass);
24192         }
24193     },
24194
24195     /**
24196      * @hide
24197      */
24198     notifyDrop : function(dd, e, data)
24199     {
24200         this.success = false;
24201         this.fireEvent('drop', dd, e, data);
24202         return this.success;
24203     }
24204 });/*
24205  * Based on:
24206  * Ext JS Library 1.1.1
24207  * Copyright(c) 2006-2007, Ext JS, LLC.
24208  *
24209  * Originally Released Under LGPL - original licence link has changed is not relivant.
24210  *
24211  * Fork - LGPL
24212  * <script type="text/javascript">
24213  */
24214
24215
24216 /**
24217  * @class Roo.dd.DragZone
24218  * @extends Roo.dd.DragSource
24219  * This class provides a container DD instance that proxies for multiple child node sources.<br />
24220  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24221  * @constructor
24222  * @param {String/HTMLElement/Element} el The container element
24223  * @param {Object} config
24224  */
24225 Roo.dd.DragZone = function(el, config){
24226     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24227     if(this.containerScroll){
24228         Roo.dd.ScrollManager.register(this.el);
24229     }
24230 };
24231
24232 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24233     /**
24234      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24235      * for auto scrolling during drag operations.
24236      */
24237     /**
24238      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24239      * method after a failed drop (defaults to "c3daf9" - light blue)
24240      */
24241
24242     /**
24243      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24244      * for a valid target to drag based on the mouse down. Override this method
24245      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24246      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24247      * @param {EventObject} e The mouse down event
24248      * @return {Object} The dragData
24249      */
24250     getDragData : function(e){
24251         return Roo.dd.Registry.getHandleFromEvent(e);
24252     },
24253     
24254     /**
24255      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24256      * this.dragData.ddel
24257      * @param {Number} x The x position of the click on the dragged object
24258      * @param {Number} y The y position of the click on the dragged object
24259      * @return {Boolean} true to continue the drag, false to cancel
24260      */
24261     onInitDrag : function(x, y){
24262         this.proxy.update(this.dragData.ddel.cloneNode(true));
24263         this.onStartDrag(x, y);
24264         return true;
24265     },
24266     
24267     /**
24268      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
24269      */
24270     afterRepair : function(){
24271         if(Roo.enableFx){
24272             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24273         }
24274         this.dragging = false;
24275     },
24276
24277     /**
24278      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24279      * the XY of this.dragData.ddel
24280      * @param {EventObject} e The mouse up event
24281      * @return {Array} The xy location (e.g. [100, 200])
24282      */
24283     getRepairXY : function(e){
24284         return Roo.Element.fly(this.dragData.ddel).getXY();  
24285     }
24286 });/*
24287  * Based on:
24288  * Ext JS Library 1.1.1
24289  * Copyright(c) 2006-2007, Ext JS, LLC.
24290  *
24291  * Originally Released Under LGPL - original licence link has changed is not relivant.
24292  *
24293  * Fork - LGPL
24294  * <script type="text/javascript">
24295  */
24296 /**
24297  * @class Roo.dd.DropZone
24298  * @extends Roo.dd.DropTarget
24299  * This class provides a container DD instance that proxies for multiple child node targets.<br />
24300  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24301  * @constructor
24302  * @param {String/HTMLElement/Element} el The container element
24303  * @param {Object} config
24304  */
24305 Roo.dd.DropZone = function(el, config){
24306     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24307 };
24308
24309 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24310     /**
24311      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
24312      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24313      * provide your own custom lookup.
24314      * @param {Event} e The event
24315      * @return {Object} data The custom data
24316      */
24317     getTargetFromEvent : function(e){
24318         return Roo.dd.Registry.getTargetFromEvent(e);
24319     },
24320
24321     /**
24322      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24323      * that it has registered.  This method has no default implementation and should be overridden to provide
24324      * node-specific processing if necessary.
24325      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
24326      * {@link #getTargetFromEvent} for this node)
24327      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24328      * @param {Event} e The event
24329      * @param {Object} data An object containing arbitrary data supplied by the drag source
24330      */
24331     onNodeEnter : function(n, dd, e, data){
24332         
24333     },
24334
24335     /**
24336      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24337      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
24338      * overridden to provide the proper feedback.
24339      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24340      * {@link #getTargetFromEvent} for this node)
24341      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24342      * @param {Event} e The event
24343      * @param {Object} data An object containing arbitrary data supplied by the drag source
24344      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24345      * underlying {@link Roo.dd.StatusProxy} can be updated
24346      */
24347     onNodeOver : function(n, dd, e, data){
24348         return this.dropAllowed;
24349     },
24350
24351     /**
24352      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24353      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
24354      * node-specific processing if necessary.
24355      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24356      * {@link #getTargetFromEvent} for this node)
24357      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24358      * @param {Event} e The event
24359      * @param {Object} data An object containing arbitrary data supplied by the drag source
24360      */
24361     onNodeOut : function(n, dd, e, data){
24362         
24363     },
24364
24365     /**
24366      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24367      * the drop node.  The default implementation returns false, so it should be overridden to provide the
24368      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24369      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24370      * {@link #getTargetFromEvent} for this node)
24371      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24372      * @param {Event} e The event
24373      * @param {Object} data An object containing arbitrary data supplied by the drag source
24374      * @return {Boolean} True if the drop was valid, else false
24375      */
24376     onNodeDrop : function(n, dd, e, data){
24377         return false;
24378     },
24379
24380     /**
24381      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24382      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
24383      * it should be overridden to provide the proper feedback if necessary.
24384      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24385      * @param {Event} e The event
24386      * @param {Object} data An object containing arbitrary data supplied by the drag source
24387      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24388      * underlying {@link Roo.dd.StatusProxy} can be updated
24389      */
24390     onContainerOver : function(dd, e, data){
24391         return this.dropNotAllowed;
24392     },
24393
24394     /**
24395      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24396      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
24397      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24398      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
24399      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24400      * @param {Event} e The event
24401      * @param {Object} data An object containing arbitrary data supplied by the drag source
24402      * @return {Boolean} True if the drop was valid, else false
24403      */
24404     onContainerDrop : function(dd, e, data){
24405         return false;
24406     },
24407
24408     /**
24409      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24410      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
24411      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24412      * you should override this method and provide a custom implementation.
24413      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24414      * @param {Event} e The event
24415      * @param {Object} data An object containing arbitrary data supplied by the drag source
24416      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24417      * underlying {@link Roo.dd.StatusProxy} can be updated
24418      */
24419     notifyEnter : function(dd, e, data){
24420         return this.dropNotAllowed;
24421     },
24422
24423     /**
24424      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24425      * This method will be called on every mouse movement while the drag source is over the drop zone.
24426      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24427      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24428      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24429      * registered node, it will call {@link #onContainerOver}.
24430      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24431      * @param {Event} e The event
24432      * @param {Object} data An object containing arbitrary data supplied by the drag source
24433      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24434      * underlying {@link Roo.dd.StatusProxy} can be updated
24435      */
24436     notifyOver : function(dd, e, data){
24437         var n = this.getTargetFromEvent(e);
24438         if(!n){ // not over valid drop target
24439             if(this.lastOverNode){
24440                 this.onNodeOut(this.lastOverNode, dd, e, data);
24441                 this.lastOverNode = null;
24442             }
24443             return this.onContainerOver(dd, e, data);
24444         }
24445         if(this.lastOverNode != n){
24446             if(this.lastOverNode){
24447                 this.onNodeOut(this.lastOverNode, dd, e, data);
24448             }
24449             this.onNodeEnter(n, dd, e, data);
24450             this.lastOverNode = n;
24451         }
24452         return this.onNodeOver(n, dd, e, data);
24453     },
24454
24455     /**
24456      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24457      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
24458      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24459      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24460      * @param {Event} e The event
24461      * @param {Object} data An object containing arbitrary data supplied by the drag zone
24462      */
24463     notifyOut : function(dd, e, data){
24464         if(this.lastOverNode){
24465             this.onNodeOut(this.lastOverNode, dd, e, data);
24466             this.lastOverNode = null;
24467         }
24468     },
24469
24470     /**
24471      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24472      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
24473      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24474      * otherwise it will call {@link #onContainerDrop}.
24475      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24476      * @param {Event} e The event
24477      * @param {Object} data An object containing arbitrary data supplied by the drag source
24478      * @return {Boolean} True if the drop was valid, else false
24479      */
24480     notifyDrop : function(dd, e, data){
24481         if(this.lastOverNode){
24482             this.onNodeOut(this.lastOverNode, dd, e, data);
24483             this.lastOverNode = null;
24484         }
24485         var n = this.getTargetFromEvent(e);
24486         return n ?
24487             this.onNodeDrop(n, dd, e, data) :
24488             this.onContainerDrop(dd, e, data);
24489     },
24490
24491     // private
24492     triggerCacheRefresh : function(){
24493         Roo.dd.DDM.refreshCache(this.groups);
24494     }  
24495 });