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         console.log("THIS EL");
17057         console.log(this.el);
17058         if(this.el){
17059             this.el = Roo.get(this.el);
17060             if(this.allowDomMove !== false){
17061                 ct.dom.insertBefore(this.el.dom, position);
17062             }
17063         }
17064     },
17065
17066     /** @private */
17067     getAutoCreate : function(){
17068         var cfg = typeof this.autoCreate == "object" ?
17069                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
17070         if(this.id && !cfg.id){
17071             cfg.id = this.id;
17072         }
17073         return cfg;
17074     },
17075
17076     /** @private */
17077     afterRender : Roo.emptyFn,
17078
17079     /**
17080      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
17081      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
17082      */
17083     destroy : function(){
17084         if(this.fireEvent("beforedestroy", this) !== false){
17085             this.purgeListeners();
17086             this.beforeDestroy();
17087             if(this.rendered){
17088                 this.el.removeAllListeners();
17089                 this.el.remove();
17090                 if(this.actionMode == "container"){
17091                     this.container.remove();
17092                 }
17093             }
17094             this.onDestroy();
17095             Roo.ComponentMgr.unregister(this);
17096             this.fireEvent("destroy", this);
17097         }
17098     },
17099
17100         /** @private */
17101     beforeDestroy : function(){
17102
17103     },
17104
17105         /** @private */
17106         onDestroy : function(){
17107
17108     },
17109
17110     /**
17111      * Returns the underlying {@link Roo.Element}.
17112      * @return {Roo.Element} The element
17113      */
17114     getEl : function(){
17115         return this.el;
17116     },
17117
17118     /**
17119      * Returns the id of this component.
17120      * @return {String}
17121      */
17122     getId : function(){
17123         return this.id;
17124     },
17125
17126     /**
17127      * Try to focus this component.
17128      * @param {Boolean} selectText True to also select the text in this component (if applicable)
17129      * @return {Roo.Component} this
17130      */
17131     focus : function(selectText){
17132         if(this.rendered){
17133             this.el.focus();
17134             if(selectText === true){
17135                 this.el.dom.select();
17136             }
17137         }
17138         return this;
17139     },
17140
17141     /** @private */
17142     blur : function(){
17143         if(this.rendered){
17144             this.el.blur();
17145         }
17146         return this;
17147     },
17148
17149     /**
17150      * Disable this component.
17151      * @return {Roo.Component} this
17152      */
17153     disable : function(){
17154         if(this.rendered){
17155             this.onDisable();
17156         }
17157         this.disabled = true;
17158         this.fireEvent("disable", this);
17159         return this;
17160     },
17161
17162         // private
17163     onDisable : function(){
17164         this.getActionEl().addClass(this.disabledClass);
17165         this.el.dom.disabled = true;
17166     },
17167
17168     /**
17169      * Enable this component.
17170      * @return {Roo.Component} this
17171      */
17172     enable : function(){
17173         if(this.rendered){
17174             this.onEnable();
17175         }
17176         this.disabled = false;
17177         this.fireEvent("enable", this);
17178         return this;
17179     },
17180
17181         // private
17182     onEnable : function(){
17183         this.getActionEl().removeClass(this.disabledClass);
17184         this.el.dom.disabled = false;
17185     },
17186
17187     /**
17188      * Convenience function for setting disabled/enabled by boolean.
17189      * @param {Boolean} disabled
17190      */
17191     setDisabled : function(disabled){
17192         this[disabled ? "disable" : "enable"]();
17193     },
17194
17195     /**
17196      * Show this component.
17197      * @return {Roo.Component} this
17198      */
17199     show: function(){
17200         if(this.fireEvent("beforeshow", this) !== false){
17201             this.hidden = false;
17202             if(this.rendered){
17203                 this.onShow();
17204             }
17205             this.fireEvent("show", this);
17206         }
17207         return this;
17208     },
17209
17210     // private
17211     onShow : function(){
17212         var ae = this.getActionEl();
17213         if(this.hideMode == 'visibility'){
17214             ae.dom.style.visibility = "visible";
17215         }else if(this.hideMode == 'offsets'){
17216             ae.removeClass('x-hidden');
17217         }else{
17218             ae.dom.style.display = "";
17219         }
17220     },
17221
17222     /**
17223      * Hide this component.
17224      * @return {Roo.Component} this
17225      */
17226     hide: function(){
17227         if(this.fireEvent("beforehide", this) !== false){
17228             this.hidden = true;
17229             if(this.rendered){
17230                 this.onHide();
17231             }
17232             this.fireEvent("hide", this);
17233         }
17234         return this;
17235     },
17236
17237     // private
17238     onHide : function(){
17239         var ae = this.getActionEl();
17240         if(this.hideMode == 'visibility'){
17241             ae.dom.style.visibility = "hidden";
17242         }else if(this.hideMode == 'offsets'){
17243             ae.addClass('x-hidden');
17244         }else{
17245             ae.dom.style.display = "none";
17246         }
17247     },
17248
17249     /**
17250      * Convenience function to hide or show this component by boolean.
17251      * @param {Boolean} visible True to show, false to hide
17252      * @return {Roo.Component} this
17253      */
17254     setVisible: function(visible){
17255         if(visible) {
17256             this.show();
17257         }else{
17258             this.hide();
17259         }
17260         return this;
17261     },
17262
17263     /**
17264      * Returns true if this component is visible.
17265      */
17266     isVisible : function(){
17267         return this.getActionEl().isVisible();
17268     },
17269
17270     cloneConfig : function(overrides){
17271         overrides = overrides || {};
17272         var id = overrides.id || Roo.id();
17273         var cfg = Roo.applyIf(overrides, this.initialConfig);
17274         cfg.id = id; // prevent dup id
17275         return new this.constructor(cfg);
17276     }
17277 });/*
17278  * Based on:
17279  * Ext JS Library 1.1.1
17280  * Copyright(c) 2006-2007, Ext JS, LLC.
17281  *
17282  * Originally Released Under LGPL - original licence link has changed is not relivant.
17283  *
17284  * Fork - LGPL
17285  * <script type="text/javascript">
17286  */
17287
17288 /**
17289  * @class Roo.BoxComponent
17290  * @extends Roo.Component
17291  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
17292  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
17293  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17294  * layout containers.
17295  * @constructor
17296  * @param {Roo.Element/String/Object} config The configuration options.
17297  */
17298 Roo.BoxComponent = function(config){
17299     Roo.Component.call(this, config);
17300     this.addEvents({
17301         /**
17302          * @event resize
17303          * Fires after the component is resized.
17304              * @param {Roo.Component} this
17305              * @param {Number} adjWidth The box-adjusted width that was set
17306              * @param {Number} adjHeight The box-adjusted height that was set
17307              * @param {Number} rawWidth The width that was originally specified
17308              * @param {Number} rawHeight The height that was originally specified
17309              */
17310         resize : true,
17311         /**
17312          * @event move
17313          * Fires after the component is moved.
17314              * @param {Roo.Component} this
17315              * @param {Number} x The new x position
17316              * @param {Number} y The new y position
17317              */
17318         move : true
17319     });
17320 };
17321
17322 Roo.extend(Roo.BoxComponent, Roo.Component, {
17323     // private, set in afterRender to signify that the component has been rendered
17324     boxReady : false,
17325     // private, used to defer height settings to subclasses
17326     deferHeight: false,
17327     /** @cfg {Number} width
17328      * width (optional) size of component
17329      */
17330      /** @cfg {Number} height
17331      * height (optional) size of component
17332      */
17333      
17334     /**
17335      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
17336      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17337      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17338      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17339      * @return {Roo.BoxComponent} this
17340      */
17341     setSize : function(w, h){
17342         // support for standard size objects
17343         if(typeof w == 'object'){
17344             h = w.height;
17345             w = w.width;
17346         }
17347         // not rendered
17348         if(!this.boxReady){
17349             this.width = w;
17350             this.height = h;
17351             return this;
17352         }
17353
17354         // prevent recalcs when not needed
17355         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17356             return this;
17357         }
17358         this.lastSize = {width: w, height: h};
17359
17360         var adj = this.adjustSize(w, h);
17361         var aw = adj.width, ah = adj.height;
17362         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17363             var rz = this.getResizeEl();
17364             if(!this.deferHeight && aw !== undefined && ah !== undefined){
17365                 rz.setSize(aw, ah);
17366             }else if(!this.deferHeight && ah !== undefined){
17367                 rz.setHeight(ah);
17368             }else if(aw !== undefined){
17369                 rz.setWidth(aw);
17370             }
17371             this.onResize(aw, ah, w, h);
17372             this.fireEvent('resize', this, aw, ah, w, h);
17373         }
17374         return this;
17375     },
17376
17377     /**
17378      * Gets the current size of the component's underlying element.
17379      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17380      */
17381     getSize : function(){
17382         return this.el.getSize();
17383     },
17384
17385     /**
17386      * Gets the current XY position of the component's underlying element.
17387      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17388      * @return {Array} The XY position of the element (e.g., [100, 200])
17389      */
17390     getPosition : function(local){
17391         if(local === true){
17392             return [this.el.getLeft(true), this.el.getTop(true)];
17393         }
17394         return this.xy || this.el.getXY();
17395     },
17396
17397     /**
17398      * Gets the current box measurements of the component's underlying element.
17399      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17400      * @returns {Object} box An object in the format {x, y, width, height}
17401      */
17402     getBox : function(local){
17403         var s = this.el.getSize();
17404         if(local){
17405             s.x = this.el.getLeft(true);
17406             s.y = this.el.getTop(true);
17407         }else{
17408             var xy = this.xy || this.el.getXY();
17409             s.x = xy[0];
17410             s.y = xy[1];
17411         }
17412         return s;
17413     },
17414
17415     /**
17416      * Sets the current box measurements of the component's underlying element.
17417      * @param {Object} box An object in the format {x, y, width, height}
17418      * @returns {Roo.BoxComponent} this
17419      */
17420     updateBox : function(box){
17421         this.setSize(box.width, box.height);
17422         this.setPagePosition(box.x, box.y);
17423         return this;
17424     },
17425
17426     // protected
17427     getResizeEl : function(){
17428         return this.resizeEl || this.el;
17429     },
17430
17431     // protected
17432     getPositionEl : function(){
17433         return this.positionEl || this.el;
17434     },
17435
17436     /**
17437      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
17438      * This method fires the move event.
17439      * @param {Number} left The new left
17440      * @param {Number} top The new top
17441      * @returns {Roo.BoxComponent} this
17442      */
17443     setPosition : function(x, y){
17444         this.x = x;
17445         this.y = y;
17446         if(!this.boxReady){
17447             return this;
17448         }
17449         var adj = this.adjustPosition(x, y);
17450         var ax = adj.x, ay = adj.y;
17451
17452         var el = this.getPositionEl();
17453         if(ax !== undefined || ay !== undefined){
17454             if(ax !== undefined && ay !== undefined){
17455                 el.setLeftTop(ax, ay);
17456             }else if(ax !== undefined){
17457                 el.setLeft(ax);
17458             }else if(ay !== undefined){
17459                 el.setTop(ay);
17460             }
17461             this.onPosition(ax, ay);
17462             this.fireEvent('move', this, ax, ay);
17463         }
17464         return this;
17465     },
17466
17467     /**
17468      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
17469      * This method fires the move event.
17470      * @param {Number} x The new x position
17471      * @param {Number} y The new y position
17472      * @returns {Roo.BoxComponent} this
17473      */
17474     setPagePosition : function(x, y){
17475         this.pageX = x;
17476         this.pageY = y;
17477         if(!this.boxReady){
17478             return;
17479         }
17480         if(x === undefined || y === undefined){ // cannot translate undefined points
17481             return;
17482         }
17483         var p = this.el.translatePoints(x, y);
17484         this.setPosition(p.left, p.top);
17485         return this;
17486     },
17487
17488     // private
17489     onRender : function(ct, position){
17490         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17491         if(this.resizeEl){
17492             this.resizeEl = Roo.get(this.resizeEl);
17493         }
17494         if(this.positionEl){
17495             this.positionEl = Roo.get(this.positionEl);
17496         }
17497     },
17498
17499     // private
17500     afterRender : function(){
17501         Roo.BoxComponent.superclass.afterRender.call(this);
17502         this.boxReady = true;
17503         this.setSize(this.width, this.height);
17504         if(this.x || this.y){
17505             this.setPosition(this.x, this.y);
17506         }
17507         if(this.pageX || this.pageY){
17508             this.setPagePosition(this.pageX, this.pageY);
17509         }
17510     },
17511
17512     /**
17513      * Force the component's size to recalculate based on the underlying element's current height and width.
17514      * @returns {Roo.BoxComponent} this
17515      */
17516     syncSize : function(){
17517         delete this.lastSize;
17518         this.setSize(this.el.getWidth(), this.el.getHeight());
17519         return this;
17520     },
17521
17522     /**
17523      * Called after the component is resized, this method is empty by default but can be implemented by any
17524      * subclass that needs to perform custom logic after a resize occurs.
17525      * @param {Number} adjWidth The box-adjusted width that was set
17526      * @param {Number} adjHeight The box-adjusted height that was set
17527      * @param {Number} rawWidth The width that was originally specified
17528      * @param {Number} rawHeight The height that was originally specified
17529      */
17530     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17531
17532     },
17533
17534     /**
17535      * Called after the component is moved, this method is empty by default but can be implemented by any
17536      * subclass that needs to perform custom logic after a move occurs.
17537      * @param {Number} x The new x position
17538      * @param {Number} y The new y position
17539      */
17540     onPosition : function(x, y){
17541
17542     },
17543
17544     // private
17545     adjustSize : function(w, h){
17546         if(this.autoWidth){
17547             w = 'auto';
17548         }
17549         if(this.autoHeight){
17550             h = 'auto';
17551         }
17552         return {width : w, height: h};
17553     },
17554
17555     // private
17556     adjustPosition : function(x, y){
17557         return {x : x, y: y};
17558     }
17559 });/*
17560  * Based on:
17561  * Ext JS Library 1.1.1
17562  * Copyright(c) 2006-2007, Ext JS, LLC.
17563  *
17564  * Originally Released Under LGPL - original licence link has changed is not relivant.
17565  *
17566  * Fork - LGPL
17567  * <script type="text/javascript">
17568  */
17569  (function(){ 
17570 /**
17571  * @class Roo.Layer
17572  * @extends Roo.Element
17573  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17574  * automatic maintaining of shadow/shim positions.
17575  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17576  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17577  * you can pass a string with a CSS class name. False turns off the shadow.
17578  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17579  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17580  * @cfg {String} cls CSS class to add to the element
17581  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17582  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17583  * @constructor
17584  * @param {Object} config An object with config options.
17585  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17586  */
17587
17588 Roo.Layer = function(config, existingEl){
17589     config = config || {};
17590     var dh = Roo.DomHelper;
17591     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17592     if(existingEl){
17593         this.dom = Roo.getDom(existingEl);
17594     }
17595     if(!this.dom){
17596         var o = config.dh || {tag: "div", cls: "x-layer"};
17597         this.dom = dh.append(pel, o);
17598     }
17599     if(config.cls){
17600         this.addClass(config.cls);
17601     }
17602     this.constrain = config.constrain !== false;
17603     this.visibilityMode = Roo.Element.VISIBILITY;
17604     if(config.id){
17605         this.id = this.dom.id = config.id;
17606     }else{
17607         this.id = Roo.id(this.dom);
17608     }
17609     this.zindex = config.zindex || this.getZIndex();
17610     this.position("absolute", this.zindex);
17611     if(config.shadow){
17612         this.shadowOffset = config.shadowOffset || 4;
17613         this.shadow = new Roo.Shadow({
17614             offset : this.shadowOffset,
17615             mode : config.shadow
17616         });
17617     }else{
17618         this.shadowOffset = 0;
17619     }
17620     this.useShim = config.shim !== false && Roo.useShims;
17621     this.useDisplay = config.useDisplay;
17622     this.hide();
17623 };
17624
17625 var supr = Roo.Element.prototype;
17626
17627 // shims are shared among layer to keep from having 100 iframes
17628 var shims = [];
17629
17630 Roo.extend(Roo.Layer, Roo.Element, {
17631
17632     getZIndex : function(){
17633         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17634     },
17635
17636     getShim : function(){
17637         if(!this.useShim){
17638             return null;
17639         }
17640         if(this.shim){
17641             return this.shim;
17642         }
17643         var shim = shims.shift();
17644         if(!shim){
17645             shim = this.createShim();
17646             shim.enableDisplayMode('block');
17647             shim.dom.style.display = 'none';
17648             shim.dom.style.visibility = 'visible';
17649         }
17650         var pn = this.dom.parentNode;
17651         if(shim.dom.parentNode != pn){
17652             pn.insertBefore(shim.dom, this.dom);
17653         }
17654         shim.setStyle('z-index', this.getZIndex()-2);
17655         this.shim = shim;
17656         return shim;
17657     },
17658
17659     hideShim : function(){
17660         if(this.shim){
17661             this.shim.setDisplayed(false);
17662             shims.push(this.shim);
17663             delete this.shim;
17664         }
17665     },
17666
17667     disableShadow : function(){
17668         if(this.shadow){
17669             this.shadowDisabled = true;
17670             this.shadow.hide();
17671             this.lastShadowOffset = this.shadowOffset;
17672             this.shadowOffset = 0;
17673         }
17674     },
17675
17676     enableShadow : function(show){
17677         if(this.shadow){
17678             this.shadowDisabled = false;
17679             this.shadowOffset = this.lastShadowOffset;
17680             delete this.lastShadowOffset;
17681             if(show){
17682                 this.sync(true);
17683             }
17684         }
17685     },
17686
17687     // private
17688     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17689     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17690     sync : function(doShow){
17691         var sw = this.shadow;
17692         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17693             var sh = this.getShim();
17694
17695             var w = this.getWidth(),
17696                 h = this.getHeight();
17697
17698             var l = this.getLeft(true),
17699                 t = this.getTop(true);
17700
17701             if(sw && !this.shadowDisabled){
17702                 if(doShow && !sw.isVisible()){
17703                     sw.show(this);
17704                 }else{
17705                     sw.realign(l, t, w, h);
17706                 }
17707                 if(sh){
17708                     if(doShow){
17709                        sh.show();
17710                     }
17711                     // fit the shim behind the shadow, so it is shimmed too
17712                     var a = sw.adjusts, s = sh.dom.style;
17713                     s.left = (Math.min(l, l+a.l))+"px";
17714                     s.top = (Math.min(t, t+a.t))+"px";
17715                     s.width = (w+a.w)+"px";
17716                     s.height = (h+a.h)+"px";
17717                 }
17718             }else if(sh){
17719                 if(doShow){
17720                    sh.show();
17721                 }
17722                 sh.setSize(w, h);
17723                 sh.setLeftTop(l, t);
17724             }
17725             
17726         }
17727     },
17728
17729     // private
17730     destroy : function(){
17731         this.hideShim();
17732         if(this.shadow){
17733             this.shadow.hide();
17734         }
17735         this.removeAllListeners();
17736         var pn = this.dom.parentNode;
17737         if(pn){
17738             pn.removeChild(this.dom);
17739         }
17740         Roo.Element.uncache(this.id);
17741     },
17742
17743     remove : function(){
17744         this.destroy();
17745     },
17746
17747     // private
17748     beginUpdate : function(){
17749         this.updating = true;
17750     },
17751
17752     // private
17753     endUpdate : function(){
17754         this.updating = false;
17755         this.sync(true);
17756     },
17757
17758     // private
17759     hideUnders : function(negOffset){
17760         if(this.shadow){
17761             this.shadow.hide();
17762         }
17763         this.hideShim();
17764     },
17765
17766     // private
17767     constrainXY : function(){
17768         if(this.constrain){
17769             var vw = Roo.lib.Dom.getViewWidth(),
17770                 vh = Roo.lib.Dom.getViewHeight();
17771             var s = Roo.get(document).getScroll();
17772
17773             var xy = this.getXY();
17774             var x = xy[0], y = xy[1];   
17775             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17776             // only move it if it needs it
17777             var moved = false;
17778             // first validate right/bottom
17779             if((x + w) > vw+s.left){
17780                 x = vw - w - this.shadowOffset;
17781                 moved = true;
17782             }
17783             if((y + h) > vh+s.top){
17784                 y = vh - h - this.shadowOffset;
17785                 moved = true;
17786             }
17787             // then make sure top/left isn't negative
17788             if(x < s.left){
17789                 x = s.left;
17790                 moved = true;
17791             }
17792             if(y < s.top){
17793                 y = s.top;
17794                 moved = true;
17795             }
17796             if(moved){
17797                 if(this.avoidY){
17798                     var ay = this.avoidY;
17799                     if(y <= ay && (y+h) >= ay){
17800                         y = ay-h-5;   
17801                     }
17802                 }
17803                 xy = [x, y];
17804                 this.storeXY(xy);
17805                 supr.setXY.call(this, xy);
17806                 this.sync();
17807             }
17808         }
17809     },
17810
17811     isVisible : function(){
17812         return this.visible;    
17813     },
17814
17815     // private
17816     showAction : function(){
17817         this.visible = true; // track visibility to prevent getStyle calls
17818         if(this.useDisplay === true){
17819             this.setDisplayed("");
17820         }else if(this.lastXY){
17821             supr.setXY.call(this, this.lastXY);
17822         }else if(this.lastLT){
17823             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17824         }
17825     },
17826
17827     // private
17828     hideAction : function(){
17829         this.visible = false;
17830         if(this.useDisplay === true){
17831             this.setDisplayed(false);
17832         }else{
17833             this.setLeftTop(-10000,-10000);
17834         }
17835     },
17836
17837     // overridden Element method
17838     setVisible : function(v, a, d, c, e){
17839         if(v){
17840             this.showAction();
17841         }
17842         if(a && v){
17843             var cb = function(){
17844                 this.sync(true);
17845                 if(c){
17846                     c();
17847                 }
17848             }.createDelegate(this);
17849             supr.setVisible.call(this, true, true, d, cb, e);
17850         }else{
17851             if(!v){
17852                 this.hideUnders(true);
17853             }
17854             var cb = c;
17855             if(a){
17856                 cb = function(){
17857                     this.hideAction();
17858                     if(c){
17859                         c();
17860                     }
17861                 }.createDelegate(this);
17862             }
17863             supr.setVisible.call(this, v, a, d, cb, e);
17864             if(v){
17865                 this.sync(true);
17866             }else if(!a){
17867                 this.hideAction();
17868             }
17869         }
17870     },
17871
17872     storeXY : function(xy){
17873         delete this.lastLT;
17874         this.lastXY = xy;
17875     },
17876
17877     storeLeftTop : function(left, top){
17878         delete this.lastXY;
17879         this.lastLT = [left, top];
17880     },
17881
17882     // private
17883     beforeFx : function(){
17884         this.beforeAction();
17885         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17886     },
17887
17888     // private
17889     afterFx : function(){
17890         Roo.Layer.superclass.afterFx.apply(this, arguments);
17891         this.sync(this.isVisible());
17892     },
17893
17894     // private
17895     beforeAction : function(){
17896         if(!this.updating && this.shadow){
17897             this.shadow.hide();
17898         }
17899     },
17900
17901     // overridden Element method
17902     setLeft : function(left){
17903         this.storeLeftTop(left, this.getTop(true));
17904         supr.setLeft.apply(this, arguments);
17905         this.sync();
17906     },
17907
17908     setTop : function(top){
17909         this.storeLeftTop(this.getLeft(true), top);
17910         supr.setTop.apply(this, arguments);
17911         this.sync();
17912     },
17913
17914     setLeftTop : function(left, top){
17915         this.storeLeftTop(left, top);
17916         supr.setLeftTop.apply(this, arguments);
17917         this.sync();
17918     },
17919
17920     setXY : function(xy, a, d, c, e){
17921         this.fixDisplay();
17922         this.beforeAction();
17923         this.storeXY(xy);
17924         var cb = this.createCB(c);
17925         supr.setXY.call(this, xy, a, d, cb, e);
17926         if(!a){
17927             cb();
17928         }
17929     },
17930
17931     // private
17932     createCB : function(c){
17933         var el = this;
17934         return function(){
17935             el.constrainXY();
17936             el.sync(true);
17937             if(c){
17938                 c();
17939             }
17940         };
17941     },
17942
17943     // overridden Element method
17944     setX : function(x, a, d, c, e){
17945         this.setXY([x, this.getY()], a, d, c, e);
17946     },
17947
17948     // overridden Element method
17949     setY : function(y, a, d, c, e){
17950         this.setXY([this.getX(), y], a, d, c, e);
17951     },
17952
17953     // overridden Element method
17954     setSize : function(w, h, a, d, c, e){
17955         this.beforeAction();
17956         var cb = this.createCB(c);
17957         supr.setSize.call(this, w, h, a, d, cb, e);
17958         if(!a){
17959             cb();
17960         }
17961     },
17962
17963     // overridden Element method
17964     setWidth : function(w, a, d, c, e){
17965         this.beforeAction();
17966         var cb = this.createCB(c);
17967         supr.setWidth.call(this, w, a, d, cb, e);
17968         if(!a){
17969             cb();
17970         }
17971     },
17972
17973     // overridden Element method
17974     setHeight : function(h, a, d, c, e){
17975         this.beforeAction();
17976         var cb = this.createCB(c);
17977         supr.setHeight.call(this, h, a, d, cb, e);
17978         if(!a){
17979             cb();
17980         }
17981     },
17982
17983     // overridden Element method
17984     setBounds : function(x, y, w, h, a, d, c, e){
17985         this.beforeAction();
17986         var cb = this.createCB(c);
17987         if(!a){
17988             this.storeXY([x, y]);
17989             supr.setXY.call(this, [x, y]);
17990             supr.setSize.call(this, w, h, a, d, cb, e);
17991             cb();
17992         }else{
17993             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17994         }
17995         return this;
17996     },
17997     
17998     /**
17999      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
18000      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
18001      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
18002      * @param {Number} zindex The new z-index to set
18003      * @return {this} The Layer
18004      */
18005     setZIndex : function(zindex){
18006         this.zindex = zindex;
18007         this.setStyle("z-index", zindex + 2);
18008         if(this.shadow){
18009             this.shadow.setZIndex(zindex + 1);
18010         }
18011         if(this.shim){
18012             this.shim.setStyle("z-index", zindex);
18013         }
18014     }
18015 });
18016 })();/*
18017  * Original code for Roojs - LGPL
18018  * <script type="text/javascript">
18019  */
18020  
18021 /**
18022  * @class Roo.XComponent
18023  * A delayed Element creator...
18024  * Or a way to group chunks of interface together.
18025  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
18026  *  used in conjunction with XComponent.build() it will create an instance of each element,
18027  *  then call addxtype() to build the User interface.
18028  * 
18029  * Mypart.xyx = new Roo.XComponent({
18030
18031     parent : 'Mypart.xyz', // empty == document.element.!!
18032     order : '001',
18033     name : 'xxxx'
18034     region : 'xxxx'
18035     disabled : function() {} 
18036      
18037     tree : function() { // return an tree of xtype declared components
18038         var MODULE = this;
18039         return 
18040         {
18041             xtype : 'NestedLayoutPanel',
18042             // technicall
18043         }
18044      ]
18045  *})
18046  *
18047  *
18048  * It can be used to build a big heiracy, with parent etc.
18049  * or you can just use this to render a single compoent to a dom element
18050  * MYPART.render(Roo.Element | String(id) | dom_element )
18051  *
18052  *
18053  * Usage patterns.
18054  *
18055  * Classic Roo
18056  *
18057  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
18058  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
18059  *
18060  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
18061  *
18062  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
18063  * - if mulitple topModules exist, the last one is defined as the top module.
18064  *
18065  * Embeded Roo
18066  * 
18067  * When the top level or multiple modules are to embedded into a existing HTML page,
18068  * the parent element can container '#id' of the element where the module will be drawn.
18069  *
18070  * Bootstrap Roo
18071  *
18072  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
18073  * it relies more on a include mechanism, where sub modules are included into an outer page.
18074  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
18075  * 
18076  * Bootstrap Roo Included elements
18077  *
18078  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
18079  * hence confusing the component builder as it thinks there are multiple top level elements. 
18080  *
18081  * String Over-ride & Translations
18082  *
18083  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
18084  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
18085  * are needed. @see Roo.XComponent.overlayString  
18086  * 
18087  * 
18088  * 
18089  * @extends Roo.util.Observable
18090  * @constructor
18091  * @param cfg {Object} configuration of component
18092  * 
18093  */
18094 Roo.XComponent = function(cfg) {
18095     Roo.apply(this, cfg);
18096     this.addEvents({ 
18097         /**
18098              * @event built
18099              * Fires when this the componnt is built
18100              * @param {Roo.XComponent} c the component
18101              */
18102         'built' : true
18103         
18104     });
18105     this.region = this.region || 'center'; // default..
18106     Roo.XComponent.register(this);
18107     this.modules = false;
18108     this.el = false; // where the layout goes..
18109     
18110     
18111 }
18112 Roo.extend(Roo.XComponent, Roo.util.Observable, {
18113     /**
18114      * @property el
18115      * The created element (with Roo.factory())
18116      * @type {Roo.Layout}
18117      */
18118     el  : false,
18119     
18120     /**
18121      * @property el
18122      * for BC  - use el in new code
18123      * @type {Roo.Layout}
18124      */
18125     panel : false,
18126     
18127     /**
18128      * @property layout
18129      * for BC  - use el in new code
18130      * @type {Roo.Layout}
18131      */
18132     layout : false,
18133     
18134      /**
18135      * @cfg {Function|boolean} disabled
18136      * If this module is disabled by some rule, return true from the funtion
18137      */
18138     disabled : false,
18139     
18140     /**
18141      * @cfg {String} parent 
18142      * Name of parent element which it get xtype added to..
18143      */
18144     parent: false,
18145     
18146     /**
18147      * @cfg {String} order
18148      * Used to set the order in which elements are created (usefull for multiple tabs)
18149      */
18150     
18151     order : false,
18152     /**
18153      * @cfg {String} name
18154      * String to display while loading.
18155      */
18156     name : false,
18157     /**
18158      * @cfg {String} region
18159      * Region to render component to (defaults to center)
18160      */
18161     region : 'center',
18162     
18163     /**
18164      * @cfg {Array} items
18165      * A single item array - the first element is the root of the tree..
18166      * It's done this way to stay compatible with the Xtype system...
18167      */
18168     items : false,
18169     
18170     /**
18171      * @property _tree
18172      * The method that retuns the tree of parts that make up this compoennt 
18173      * @type {function}
18174      */
18175     _tree  : false,
18176     
18177      /**
18178      * render
18179      * render element to dom or tree
18180      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
18181      */
18182     
18183     render : function(el)
18184     {
18185         
18186         el = el || false;
18187         var hp = this.parent ? 1 : 0;
18188         Roo.debug &&  Roo.log(this);
18189         
18190         var tree = this._tree ? this._tree() : this.tree();
18191
18192         
18193         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
18194             // if parent is a '#.....' string, then let's use that..
18195             var ename = this.parent.substr(1);
18196             this.parent = false;
18197             Roo.debug && Roo.log(ename);
18198             switch (ename) {
18199                 case 'bootstrap-body':
18200                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
18201                         // this is the BorderLayout standard?
18202                        this.parent = { el : true };
18203                        break;
18204                     }
18205                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
18206                         // need to insert stuff...
18207                         this.parent =  {
18208                              el : new Roo.bootstrap.layout.Border({
18209                                  el : document.body, 
18210                      
18211                                  center: {
18212                                     titlebar: false,
18213                                     autoScroll:false,
18214                                     closeOnTab: true,
18215                                     tabPosition: 'top',
18216                                       //resizeTabs: true,
18217                                     alwaysShowTabs: true,
18218                                     hideTabs: false
18219                                      //minTabWidth: 140
18220                                  }
18221                              })
18222                         
18223                          };
18224                          break;
18225                     }
18226                          
18227                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18228                         this.parent = { el :  new  Roo.bootstrap.Body() };
18229                         Roo.debug && Roo.log("setting el to doc body");
18230                          
18231                     } else {
18232                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18233                     }
18234                     break;
18235                 case 'bootstrap':
18236                     this.parent = { el : true};
18237                     // fall through
18238                 default:
18239                     el = Roo.get(ename);
18240                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18241                         this.parent = { el : true};
18242                     }
18243                     
18244                     break;
18245             }
18246                 
18247             
18248             if (!el && !this.parent) {
18249                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18250                 return;
18251             }
18252         }
18253         
18254         Roo.debug && Roo.log("EL:");
18255         Roo.debug && Roo.log(el);
18256         Roo.debug && Roo.log("this.parent.el:");
18257         Roo.debug && Roo.log(this.parent.el);
18258         
18259
18260         // altertive root elements ??? - we need a better way to indicate these.
18261         var is_alt = Roo.XComponent.is_alt ||
18262                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18263                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18264                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18265         
18266         
18267         
18268         if (!this.parent && is_alt) {
18269             //el = Roo.get(document.body);
18270             this.parent = { el : true };
18271         }
18272             
18273             
18274         
18275         if (!this.parent) {
18276             
18277             Roo.debug && Roo.log("no parent - creating one");
18278             
18279             el = el ? Roo.get(el) : false;      
18280             
18281             if (typeof(Roo.BorderLayout) == 'undefined' ) {
18282                 
18283                 this.parent =  {
18284                     el : new Roo.bootstrap.layout.Border({
18285                         el: el || document.body,
18286                     
18287                         center: {
18288                             titlebar: false,
18289                             autoScroll:false,
18290                             closeOnTab: true,
18291                             tabPosition: 'top',
18292                              //resizeTabs: true,
18293                             alwaysShowTabs: false,
18294                             hideTabs: true,
18295                             minTabWidth: 140,
18296                             overflow: 'visible'
18297                          }
18298                      })
18299                 };
18300             } else {
18301             
18302                 // it's a top level one..
18303                 this.parent =  {
18304                     el : new Roo.BorderLayout(el || document.body, {
18305                         center: {
18306                             titlebar: false,
18307                             autoScroll:false,
18308                             closeOnTab: true,
18309                             tabPosition: 'top',
18310                              //resizeTabs: true,
18311                             alwaysShowTabs: el && hp? false :  true,
18312                             hideTabs: el || !hp ? true :  false,
18313                             minTabWidth: 140
18314                          }
18315                     })
18316                 };
18317             }
18318         }
18319         
18320         if (!this.parent.el) {
18321                 // probably an old style ctor, which has been disabled.
18322                 return;
18323
18324         }
18325                 // The 'tree' method is  '_tree now' 
18326             
18327         tree.region = tree.region || this.region;
18328         var is_body = false;
18329         if (this.parent.el === true) {
18330             // bootstrap... - body..
18331             if (el) {
18332                 tree.el = el;
18333             }
18334             this.parent.el = Roo.factory(tree);
18335             is_body = true;
18336         }
18337         
18338         this.el = this.parent.el.addxtype(tree, undefined, is_body);
18339         this.fireEvent('built', this);
18340         
18341         this.panel = this.el;
18342         this.layout = this.panel.layout;
18343         this.parentLayout = this.parent.layout  || false;  
18344          
18345     }
18346     
18347 });
18348
18349 Roo.apply(Roo.XComponent, {
18350     /**
18351      * @property  hideProgress
18352      * true to disable the building progress bar.. usefull on single page renders.
18353      * @type Boolean
18354      */
18355     hideProgress : false,
18356     /**
18357      * @property  buildCompleted
18358      * True when the builder has completed building the interface.
18359      * @type Boolean
18360      */
18361     buildCompleted : false,
18362      
18363     /**
18364      * @property  topModule
18365      * the upper most module - uses document.element as it's constructor.
18366      * @type Object
18367      */
18368      
18369     topModule  : false,
18370       
18371     /**
18372      * @property  modules
18373      * array of modules to be created by registration system.
18374      * @type {Array} of Roo.XComponent
18375      */
18376     
18377     modules : [],
18378     /**
18379      * @property  elmodules
18380      * array of modules to be created by which use #ID 
18381      * @type {Array} of Roo.XComponent
18382      */
18383      
18384     elmodules : [],
18385
18386      /**
18387      * @property  is_alt
18388      * Is an alternative Root - normally used by bootstrap or other systems,
18389      *    where the top element in the tree can wrap 'body' 
18390      * @type {boolean}  (default false)
18391      */
18392      
18393     is_alt : false,
18394     /**
18395      * @property  build_from_html
18396      * Build elements from html - used by bootstrap HTML stuff 
18397      *    - this is cleared after build is completed
18398      * @type {boolean}    (default false)
18399      */
18400      
18401     build_from_html : false,
18402     /**
18403      * Register components to be built later.
18404      *
18405      * This solves the following issues
18406      * - Building is not done on page load, but after an authentication process has occured.
18407      * - Interface elements are registered on page load
18408      * - Parent Interface elements may not be loaded before child, so this handles that..
18409      * 
18410      *
18411      * example:
18412      * 
18413      * MyApp.register({
18414           order : '000001',
18415           module : 'Pman.Tab.projectMgr',
18416           region : 'center',
18417           parent : 'Pman.layout',
18418           disabled : false,  // or use a function..
18419         })
18420      
18421      * * @param {Object} details about module
18422      */
18423     register : function(obj) {
18424                 
18425         Roo.XComponent.event.fireEvent('register', obj);
18426         switch(typeof(obj.disabled) ) {
18427                 
18428             case 'undefined':
18429                 break;
18430             
18431             case 'function':
18432                 if ( obj.disabled() ) {
18433                         return;
18434                 }
18435                 break;
18436             
18437             default:
18438                 if (obj.disabled || obj.region == '#disabled') {
18439                         return;
18440                 }
18441                 break;
18442         }
18443                 
18444         this.modules.push(obj);
18445          
18446     },
18447     /**
18448      * convert a string to an object..
18449      * eg. 'AAA.BBB' -> finds AAA.BBB
18450
18451      */
18452     
18453     toObject : function(str)
18454     {
18455         if (!str || typeof(str) == 'object') {
18456             return str;
18457         }
18458         if (str.substring(0,1) == '#') {
18459             return str;
18460         }
18461
18462         var ar = str.split('.');
18463         var rt, o;
18464         rt = ar.shift();
18465             /** eval:var:o */
18466         try {
18467             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18468         } catch (e) {
18469             throw "Module not found : " + str;
18470         }
18471         
18472         if (o === false) {
18473             throw "Module not found : " + str;
18474         }
18475         Roo.each(ar, function(e) {
18476             if (typeof(o[e]) == 'undefined') {
18477                 throw "Module not found : " + str;
18478             }
18479             o = o[e];
18480         });
18481         
18482         return o;
18483         
18484     },
18485     
18486     
18487     /**
18488      * move modules into their correct place in the tree..
18489      * 
18490      */
18491     preBuild : function ()
18492     {
18493         var _t = this;
18494         Roo.each(this.modules , function (obj)
18495         {
18496             Roo.XComponent.event.fireEvent('beforebuild', obj);
18497             
18498             var opar = obj.parent;
18499             try { 
18500                 obj.parent = this.toObject(opar);
18501             } catch(e) {
18502                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18503                 return;
18504             }
18505             
18506             if (!obj.parent) {
18507                 Roo.debug && Roo.log("GOT top level module");
18508                 Roo.debug && Roo.log(obj);
18509                 obj.modules = new Roo.util.MixedCollection(false, 
18510                     function(o) { return o.order + '' }
18511                 );
18512                 this.topModule = obj;
18513                 return;
18514             }
18515                         // parent is a string (usually a dom element name..)
18516             if (typeof(obj.parent) == 'string') {
18517                 this.elmodules.push(obj);
18518                 return;
18519             }
18520             if (obj.parent.constructor != Roo.XComponent) {
18521                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18522             }
18523             if (!obj.parent.modules) {
18524                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18525                     function(o) { return o.order + '' }
18526                 );
18527             }
18528             if (obj.parent.disabled) {
18529                 obj.disabled = true;
18530             }
18531             obj.parent.modules.add(obj);
18532         }, this);
18533     },
18534     
18535      /**
18536      * make a list of modules to build.
18537      * @return {Array} list of modules. 
18538      */ 
18539     
18540     buildOrder : function()
18541     {
18542         var _this = this;
18543         var cmp = function(a,b) {   
18544             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18545         };
18546         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18547             throw "No top level modules to build";
18548         }
18549         
18550         // make a flat list in order of modules to build.
18551         var mods = this.topModule ? [ this.topModule ] : [];
18552                 
18553         
18554         // elmodules (is a list of DOM based modules )
18555         Roo.each(this.elmodules, function(e) {
18556             mods.push(e);
18557             if (!this.topModule &&
18558                 typeof(e.parent) == 'string' &&
18559                 e.parent.substring(0,1) == '#' &&
18560                 Roo.get(e.parent.substr(1))
18561                ) {
18562                 
18563                 _this.topModule = e;
18564             }
18565             
18566         });
18567
18568         
18569         // add modules to their parents..
18570         var addMod = function(m) {
18571             Roo.debug && Roo.log("build Order: add: " + m.name);
18572                 
18573             mods.push(m);
18574             if (m.modules && !m.disabled) {
18575                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18576                 m.modules.keySort('ASC',  cmp );
18577                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18578     
18579                 m.modules.each(addMod);
18580             } else {
18581                 Roo.debug && Roo.log("build Order: no child modules");
18582             }
18583             // not sure if this is used any more..
18584             if (m.finalize) {
18585                 m.finalize.name = m.name + " (clean up) ";
18586                 mods.push(m.finalize);
18587             }
18588             
18589         }
18590         if (this.topModule && this.topModule.modules) { 
18591             this.topModule.modules.keySort('ASC',  cmp );
18592             this.topModule.modules.each(addMod);
18593         } 
18594         return mods;
18595     },
18596     
18597      /**
18598      * Build the registered modules.
18599      * @param {Object} parent element.
18600      * @param {Function} optional method to call after module has been added.
18601      * 
18602      */ 
18603    
18604     build : function(opts) 
18605     {
18606         
18607         if (typeof(opts) != 'undefined') {
18608             Roo.apply(this,opts);
18609         }
18610         
18611         this.preBuild();
18612         var mods = this.buildOrder();
18613       
18614         //this.allmods = mods;
18615         //Roo.debug && Roo.log(mods);
18616         //return;
18617         if (!mods.length) { // should not happen
18618             throw "NO modules!!!";
18619         }
18620         
18621         
18622         var msg = "Building Interface...";
18623         // flash it up as modal - so we store the mask!?
18624         if (!this.hideProgress && Roo.MessageBox) {
18625             Roo.MessageBox.show({ title: 'loading' });
18626             Roo.MessageBox.show({
18627                title: "Please wait...",
18628                msg: msg,
18629                width:450,
18630                progress:true,
18631                buttons : false,
18632                closable:false,
18633                modal: false
18634               
18635             });
18636         }
18637         var total = mods.length;
18638         
18639         var _this = this;
18640         var progressRun = function() {
18641             if (!mods.length) {
18642                 Roo.debug && Roo.log('hide?');
18643                 if (!this.hideProgress && Roo.MessageBox) {
18644                     Roo.MessageBox.hide();
18645                 }
18646                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18647                 
18648                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18649                 
18650                 // THE END...
18651                 return false;   
18652             }
18653             
18654             var m = mods.shift();
18655             
18656             
18657             Roo.debug && Roo.log(m);
18658             // not sure if this is supported any more.. - modules that are are just function
18659             if (typeof(m) == 'function') { 
18660                 m.call(this);
18661                 return progressRun.defer(10, _this);
18662             } 
18663             
18664             
18665             msg = "Building Interface " + (total  - mods.length) + 
18666                     " of " + total + 
18667                     (m.name ? (' - ' + m.name) : '');
18668                         Roo.debug && Roo.log(msg);
18669             if (!_this.hideProgress &&  Roo.MessageBox) { 
18670                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18671             }
18672             
18673          
18674             // is the module disabled?
18675             var disabled = (typeof(m.disabled) == 'function') ?
18676                 m.disabled.call(m.module.disabled) : m.disabled;    
18677             
18678             
18679             if (disabled) {
18680                 return progressRun(); // we do not update the display!
18681             }
18682             
18683             // now build 
18684             
18685                         
18686                         
18687             m.render();
18688             // it's 10 on top level, and 1 on others??? why...
18689             return progressRun.defer(10, _this);
18690              
18691         }
18692         progressRun.defer(1, _this);
18693      
18694         
18695         
18696     },
18697     /**
18698      * Overlay a set of modified strings onto a component
18699      * This is dependant on our builder exporting the strings and 'named strings' elements.
18700      * 
18701      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18702      * @param {Object} associative array of 'named' string and it's new value.
18703      * 
18704      */
18705         overlayStrings : function( component, strings )
18706     {
18707         if (typeof(component['_named_strings']) == 'undefined') {
18708             throw "ERROR: component does not have _named_strings";
18709         }
18710         for ( var k in strings ) {
18711             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18712             if (md !== false) {
18713                 component['_strings'][md] = strings[k];
18714             } else {
18715                 Roo.log('could not find named string: ' + k + ' in');
18716                 Roo.log(component);
18717             }
18718             
18719         }
18720         
18721     },
18722     
18723         
18724         /**
18725          * Event Object.
18726          *
18727          *
18728          */
18729         event: false, 
18730     /**
18731          * wrapper for event.on - aliased later..  
18732          * Typically use to register a event handler for register:
18733          *
18734          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18735          *
18736          */
18737     on : false
18738    
18739     
18740     
18741 });
18742
18743 Roo.XComponent.event = new Roo.util.Observable({
18744                 events : { 
18745                         /**
18746                          * @event register
18747                          * Fires when an Component is registered,
18748                          * set the disable property on the Component to stop registration.
18749                          * @param {Roo.XComponent} c the component being registerd.
18750                          * 
18751                          */
18752                         'register' : true,
18753             /**
18754                          * @event beforebuild
18755                          * Fires before each Component is built
18756                          * can be used to apply permissions.
18757                          * @param {Roo.XComponent} c the component being registerd.
18758                          * 
18759                          */
18760                         'beforebuild' : true,
18761                         /**
18762                          * @event buildcomplete
18763                          * Fires on the top level element when all elements have been built
18764                          * @param {Roo.XComponent} the top level component.
18765                          */
18766                         'buildcomplete' : true
18767                         
18768                 }
18769 });
18770
18771 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18772  //
18773  /**
18774  * marked - a markdown parser
18775  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18776  * https://github.com/chjj/marked
18777  */
18778
18779
18780 /**
18781  *
18782  * Roo.Markdown - is a very crude wrapper around marked..
18783  *
18784  * usage:
18785  * 
18786  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18787  * 
18788  * Note: move the sample code to the bottom of this
18789  * file before uncommenting it.
18790  *
18791  */
18792
18793 Roo.Markdown = {};
18794 Roo.Markdown.toHtml = function(text) {
18795     
18796     var c = new Roo.Markdown.marked.setOptions({
18797             renderer: new Roo.Markdown.marked.Renderer(),
18798             gfm: true,
18799             tables: true,
18800             breaks: false,
18801             pedantic: false,
18802             sanitize: false,
18803             smartLists: true,
18804             smartypants: false
18805           });
18806     // A FEW HACKS!!?
18807     
18808     text = text.replace(/\\\n/g,' ');
18809     return Roo.Markdown.marked(text);
18810 };
18811 //
18812 // converter
18813 //
18814 // Wraps all "globals" so that the only thing
18815 // exposed is makeHtml().
18816 //
18817 (function() {
18818     
18819      /**
18820          * eval:var:escape
18821          * eval:var:unescape
18822          * eval:var:replace
18823          */
18824       
18825     /**
18826      * Helpers
18827      */
18828     
18829     var escape = function (html, encode) {
18830       return html
18831         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18832         .replace(/</g, '&lt;')
18833         .replace(/>/g, '&gt;')
18834         .replace(/"/g, '&quot;')
18835         .replace(/'/g, '&#39;');
18836     }
18837     
18838     var unescape = function (html) {
18839         // explicitly match decimal, hex, and named HTML entities 
18840       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18841         n = n.toLowerCase();
18842         if (n === 'colon') { return ':'; }
18843         if (n.charAt(0) === '#') {
18844           return n.charAt(1) === 'x'
18845             ? String.fromCharCode(parseInt(n.substring(2), 16))
18846             : String.fromCharCode(+n.substring(1));
18847         }
18848         return '';
18849       });
18850     }
18851     
18852     var replace = function (regex, opt) {
18853       regex = regex.source;
18854       opt = opt || '';
18855       return function self(name, val) {
18856         if (!name) { return new RegExp(regex, opt); }
18857         val = val.source || val;
18858         val = val.replace(/(^|[^\[])\^/g, '$1');
18859         regex = regex.replace(name, val);
18860         return self;
18861       };
18862     }
18863
18864
18865          /**
18866          * eval:var:noop
18867     */
18868     var noop = function () {}
18869     noop.exec = noop;
18870     
18871          /**
18872          * eval:var:merge
18873     */
18874     var merge = function (obj) {
18875       var i = 1
18876         , target
18877         , key;
18878     
18879       for (; i < arguments.length; i++) {
18880         target = arguments[i];
18881         for (key in target) {
18882           if (Object.prototype.hasOwnProperty.call(target, key)) {
18883             obj[key] = target[key];
18884           }
18885         }
18886       }
18887     
18888       return obj;
18889     }
18890     
18891     
18892     /**
18893      * Block-Level Grammar
18894      */
18895     
18896     
18897     
18898     
18899     var block = {
18900       newline: /^\n+/,
18901       code: /^( {4}[^\n]+\n*)+/,
18902       fences: noop,
18903       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18904       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18905       nptable: noop,
18906       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18907       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18908       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18909       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18910       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18911       table: noop,
18912       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18913       text: /^[^\n]+/
18914     };
18915     
18916     block.bullet = /(?:[*+-]|\d+\.)/;
18917     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18918     block.item = replace(block.item, 'gm')
18919       (/bull/g, block.bullet)
18920       ();
18921     
18922     block.list = replace(block.list)
18923       (/bull/g, block.bullet)
18924       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18925       ('def', '\\n+(?=' + block.def.source + ')')
18926       ();
18927     
18928     block.blockquote = replace(block.blockquote)
18929       ('def', block.def)
18930       ();
18931     
18932     block._tag = '(?!(?:'
18933       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18934       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18935       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18936     
18937     block.html = replace(block.html)
18938       ('comment', /<!--[\s\S]*?-->/)
18939       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18940       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18941       (/tag/g, block._tag)
18942       ();
18943     
18944     block.paragraph = replace(block.paragraph)
18945       ('hr', block.hr)
18946       ('heading', block.heading)
18947       ('lheading', block.lheading)
18948       ('blockquote', block.blockquote)
18949       ('tag', '<' + block._tag)
18950       ('def', block.def)
18951       ();
18952     
18953     /**
18954      * Normal Block Grammar
18955      */
18956     
18957     block.normal = merge({}, block);
18958     
18959     /**
18960      * GFM Block Grammar
18961      */
18962     
18963     block.gfm = merge({}, block.normal, {
18964       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18965       paragraph: /^/,
18966       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18967     });
18968     
18969     block.gfm.paragraph = replace(block.paragraph)
18970       ('(?!', '(?!'
18971         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18972         + block.list.source.replace('\\1', '\\3') + '|')
18973       ();
18974     
18975     /**
18976      * GFM + Tables Block Grammar
18977      */
18978     
18979     block.tables = merge({}, block.gfm, {
18980       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18981       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18982     });
18983     
18984     /**
18985      * Block Lexer
18986      */
18987     
18988     var Lexer = function (options) {
18989       this.tokens = [];
18990       this.tokens.links = {};
18991       this.options = options || marked.defaults;
18992       this.rules = block.normal;
18993     
18994       if (this.options.gfm) {
18995         if (this.options.tables) {
18996           this.rules = block.tables;
18997         } else {
18998           this.rules = block.gfm;
18999         }
19000       }
19001     }
19002     
19003     /**
19004      * Expose Block Rules
19005      */
19006     
19007     Lexer.rules = block;
19008     
19009     /**
19010      * Static Lex Method
19011      */
19012     
19013     Lexer.lex = function(src, options) {
19014       var lexer = new Lexer(options);
19015       return lexer.lex(src);
19016     };
19017     
19018     /**
19019      * Preprocessing
19020      */
19021     
19022     Lexer.prototype.lex = function(src) {
19023       src = src
19024         .replace(/\r\n|\r/g, '\n')
19025         .replace(/\t/g, '    ')
19026         .replace(/\u00a0/g, ' ')
19027         .replace(/\u2424/g, '\n');
19028     
19029       return this.token(src, true);
19030     };
19031     
19032     /**
19033      * Lexing
19034      */
19035     
19036     Lexer.prototype.token = function(src, top, bq) {
19037       var src = src.replace(/^ +$/gm, '')
19038         , next
19039         , loose
19040         , cap
19041         , bull
19042         , b
19043         , item
19044         , space
19045         , i
19046         , l;
19047     
19048       while (src) {
19049         // newline
19050         if (cap = this.rules.newline.exec(src)) {
19051           src = src.substring(cap[0].length);
19052           if (cap[0].length > 1) {
19053             this.tokens.push({
19054               type: 'space'
19055             });
19056           }
19057         }
19058     
19059         // code
19060         if (cap = this.rules.code.exec(src)) {
19061           src = src.substring(cap[0].length);
19062           cap = cap[0].replace(/^ {4}/gm, '');
19063           this.tokens.push({
19064             type: 'code',
19065             text: !this.options.pedantic
19066               ? cap.replace(/\n+$/, '')
19067               : cap
19068           });
19069           continue;
19070         }
19071     
19072         // fences (gfm)
19073         if (cap = this.rules.fences.exec(src)) {
19074           src = src.substring(cap[0].length);
19075           this.tokens.push({
19076             type: 'code',
19077             lang: cap[2],
19078             text: cap[3] || ''
19079           });
19080           continue;
19081         }
19082     
19083         // heading
19084         if (cap = this.rules.heading.exec(src)) {
19085           src = src.substring(cap[0].length);
19086           this.tokens.push({
19087             type: 'heading',
19088             depth: cap[1].length,
19089             text: cap[2]
19090           });
19091           continue;
19092         }
19093     
19094         // table no leading pipe (gfm)
19095         if (top && (cap = this.rules.nptable.exec(src))) {
19096           src = src.substring(cap[0].length);
19097     
19098           item = {
19099             type: 'table',
19100             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19101             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19102             cells: cap[3].replace(/\n$/, '').split('\n')
19103           };
19104     
19105           for (i = 0; i < item.align.length; i++) {
19106             if (/^ *-+: *$/.test(item.align[i])) {
19107               item.align[i] = 'right';
19108             } else if (/^ *:-+: *$/.test(item.align[i])) {
19109               item.align[i] = 'center';
19110             } else if (/^ *:-+ *$/.test(item.align[i])) {
19111               item.align[i] = 'left';
19112             } else {
19113               item.align[i] = null;
19114             }
19115           }
19116     
19117           for (i = 0; i < item.cells.length; i++) {
19118             item.cells[i] = item.cells[i].split(/ *\| */);
19119           }
19120     
19121           this.tokens.push(item);
19122     
19123           continue;
19124         }
19125     
19126         // lheading
19127         if (cap = this.rules.lheading.exec(src)) {
19128           src = src.substring(cap[0].length);
19129           this.tokens.push({
19130             type: 'heading',
19131             depth: cap[2] === '=' ? 1 : 2,
19132             text: cap[1]
19133           });
19134           continue;
19135         }
19136     
19137         // hr
19138         if (cap = this.rules.hr.exec(src)) {
19139           src = src.substring(cap[0].length);
19140           this.tokens.push({
19141             type: 'hr'
19142           });
19143           continue;
19144         }
19145     
19146         // blockquote
19147         if (cap = this.rules.blockquote.exec(src)) {
19148           src = src.substring(cap[0].length);
19149     
19150           this.tokens.push({
19151             type: 'blockquote_start'
19152           });
19153     
19154           cap = cap[0].replace(/^ *> ?/gm, '');
19155     
19156           // Pass `top` to keep the current
19157           // "toplevel" state. This is exactly
19158           // how markdown.pl works.
19159           this.token(cap, top, true);
19160     
19161           this.tokens.push({
19162             type: 'blockquote_end'
19163           });
19164     
19165           continue;
19166         }
19167     
19168         // list
19169         if (cap = this.rules.list.exec(src)) {
19170           src = src.substring(cap[0].length);
19171           bull = cap[2];
19172     
19173           this.tokens.push({
19174             type: 'list_start',
19175             ordered: bull.length > 1
19176           });
19177     
19178           // Get each top-level item.
19179           cap = cap[0].match(this.rules.item);
19180     
19181           next = false;
19182           l = cap.length;
19183           i = 0;
19184     
19185           for (; i < l; i++) {
19186             item = cap[i];
19187     
19188             // Remove the list item's bullet
19189             // so it is seen as the next token.
19190             space = item.length;
19191             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19192     
19193             // Outdent whatever the
19194             // list item contains. Hacky.
19195             if (~item.indexOf('\n ')) {
19196               space -= item.length;
19197               item = !this.options.pedantic
19198                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19199                 : item.replace(/^ {1,4}/gm, '');
19200             }
19201     
19202             // Determine whether the next list item belongs here.
19203             // Backpedal if it does not belong in this list.
19204             if (this.options.smartLists && i !== l - 1) {
19205               b = block.bullet.exec(cap[i + 1])[0];
19206               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19207                 src = cap.slice(i + 1).join('\n') + src;
19208                 i = l - 1;
19209               }
19210             }
19211     
19212             // Determine whether item is loose or not.
19213             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19214             // for discount behavior.
19215             loose = next || /\n\n(?!\s*$)/.test(item);
19216             if (i !== l - 1) {
19217               next = item.charAt(item.length - 1) === '\n';
19218               if (!loose) { loose = next; }
19219             }
19220     
19221             this.tokens.push({
19222               type: loose
19223                 ? 'loose_item_start'
19224                 : 'list_item_start'
19225             });
19226     
19227             // Recurse.
19228             this.token(item, false, bq);
19229     
19230             this.tokens.push({
19231               type: 'list_item_end'
19232             });
19233           }
19234     
19235           this.tokens.push({
19236             type: 'list_end'
19237           });
19238     
19239           continue;
19240         }
19241     
19242         // html
19243         if (cap = this.rules.html.exec(src)) {
19244           src = src.substring(cap[0].length);
19245           this.tokens.push({
19246             type: this.options.sanitize
19247               ? 'paragraph'
19248               : 'html',
19249             pre: !this.options.sanitizer
19250               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19251             text: cap[0]
19252           });
19253           continue;
19254         }
19255     
19256         // def
19257         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19258           src = src.substring(cap[0].length);
19259           this.tokens.links[cap[1].toLowerCase()] = {
19260             href: cap[2],
19261             title: cap[3]
19262           };
19263           continue;
19264         }
19265     
19266         // table (gfm)
19267         if (top && (cap = this.rules.table.exec(src))) {
19268           src = src.substring(cap[0].length);
19269     
19270           item = {
19271             type: 'table',
19272             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19273             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19274             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19275           };
19276     
19277           for (i = 0; i < item.align.length; i++) {
19278             if (/^ *-+: *$/.test(item.align[i])) {
19279               item.align[i] = 'right';
19280             } else if (/^ *:-+: *$/.test(item.align[i])) {
19281               item.align[i] = 'center';
19282             } else if (/^ *:-+ *$/.test(item.align[i])) {
19283               item.align[i] = 'left';
19284             } else {
19285               item.align[i] = null;
19286             }
19287           }
19288     
19289           for (i = 0; i < item.cells.length; i++) {
19290             item.cells[i] = item.cells[i]
19291               .replace(/^ *\| *| *\| *$/g, '')
19292               .split(/ *\| */);
19293           }
19294     
19295           this.tokens.push(item);
19296     
19297           continue;
19298         }
19299     
19300         // top-level paragraph
19301         if (top && (cap = this.rules.paragraph.exec(src))) {
19302           src = src.substring(cap[0].length);
19303           this.tokens.push({
19304             type: 'paragraph',
19305             text: cap[1].charAt(cap[1].length - 1) === '\n'
19306               ? cap[1].slice(0, -1)
19307               : cap[1]
19308           });
19309           continue;
19310         }
19311     
19312         // text
19313         if (cap = this.rules.text.exec(src)) {
19314           // Top-level should never reach here.
19315           src = src.substring(cap[0].length);
19316           this.tokens.push({
19317             type: 'text',
19318             text: cap[0]
19319           });
19320           continue;
19321         }
19322     
19323         if (src) {
19324           throw new
19325             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19326         }
19327       }
19328     
19329       return this.tokens;
19330     };
19331     
19332     /**
19333      * Inline-Level Grammar
19334      */
19335     
19336     var inline = {
19337       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19338       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19339       url: noop,
19340       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19341       link: /^!?\[(inside)\]\(href\)/,
19342       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19343       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19344       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19345       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19346       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19347       br: /^ {2,}\n(?!\s*$)/,
19348       del: noop,
19349       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19350     };
19351     
19352     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19353     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19354     
19355     inline.link = replace(inline.link)
19356       ('inside', inline._inside)
19357       ('href', inline._href)
19358       ();
19359     
19360     inline.reflink = replace(inline.reflink)
19361       ('inside', inline._inside)
19362       ();
19363     
19364     /**
19365      * Normal Inline Grammar
19366      */
19367     
19368     inline.normal = merge({}, inline);
19369     
19370     /**
19371      * Pedantic Inline Grammar
19372      */
19373     
19374     inline.pedantic = merge({}, inline.normal, {
19375       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19376       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19377     });
19378     
19379     /**
19380      * GFM Inline Grammar
19381      */
19382     
19383     inline.gfm = merge({}, inline.normal, {
19384       escape: replace(inline.escape)('])', '~|])')(),
19385       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19386       del: /^~~(?=\S)([\s\S]*?\S)~~/,
19387       text: replace(inline.text)
19388         (']|', '~]|')
19389         ('|', '|https?://|')
19390         ()
19391     });
19392     
19393     /**
19394      * GFM + Line Breaks Inline Grammar
19395      */
19396     
19397     inline.breaks = merge({}, inline.gfm, {
19398       br: replace(inline.br)('{2,}', '*')(),
19399       text: replace(inline.gfm.text)('{2,}', '*')()
19400     });
19401     
19402     /**
19403      * Inline Lexer & Compiler
19404      */
19405     
19406     var InlineLexer  = function (links, options) {
19407       this.options = options || marked.defaults;
19408       this.links = links;
19409       this.rules = inline.normal;
19410       this.renderer = this.options.renderer || new Renderer;
19411       this.renderer.options = this.options;
19412     
19413       if (!this.links) {
19414         throw new
19415           Error('Tokens array requires a `links` property.');
19416       }
19417     
19418       if (this.options.gfm) {
19419         if (this.options.breaks) {
19420           this.rules = inline.breaks;
19421         } else {
19422           this.rules = inline.gfm;
19423         }
19424       } else if (this.options.pedantic) {
19425         this.rules = inline.pedantic;
19426       }
19427     }
19428     
19429     /**
19430      * Expose Inline Rules
19431      */
19432     
19433     InlineLexer.rules = inline;
19434     
19435     /**
19436      * Static Lexing/Compiling Method
19437      */
19438     
19439     InlineLexer.output = function(src, links, options) {
19440       var inline = new InlineLexer(links, options);
19441       return inline.output(src);
19442     };
19443     
19444     /**
19445      * Lexing/Compiling
19446      */
19447     
19448     InlineLexer.prototype.output = function(src) {
19449       var out = ''
19450         , link
19451         , text
19452         , href
19453         , cap;
19454     
19455       while (src) {
19456         // escape
19457         if (cap = this.rules.escape.exec(src)) {
19458           src = src.substring(cap[0].length);
19459           out += cap[1];
19460           continue;
19461         }
19462     
19463         // autolink
19464         if (cap = this.rules.autolink.exec(src)) {
19465           src = src.substring(cap[0].length);
19466           if (cap[2] === '@') {
19467             text = cap[1].charAt(6) === ':'
19468               ? this.mangle(cap[1].substring(7))
19469               : this.mangle(cap[1]);
19470             href = this.mangle('mailto:') + text;
19471           } else {
19472             text = escape(cap[1]);
19473             href = text;
19474           }
19475           out += this.renderer.link(href, null, text);
19476           continue;
19477         }
19478     
19479         // url (gfm)
19480         if (!this.inLink && (cap = this.rules.url.exec(src))) {
19481           src = src.substring(cap[0].length);
19482           text = escape(cap[1]);
19483           href = text;
19484           out += this.renderer.link(href, null, text);
19485           continue;
19486         }
19487     
19488         // tag
19489         if (cap = this.rules.tag.exec(src)) {
19490           if (!this.inLink && /^<a /i.test(cap[0])) {
19491             this.inLink = true;
19492           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19493             this.inLink = false;
19494           }
19495           src = src.substring(cap[0].length);
19496           out += this.options.sanitize
19497             ? this.options.sanitizer
19498               ? this.options.sanitizer(cap[0])
19499               : escape(cap[0])
19500             : cap[0];
19501           continue;
19502         }
19503     
19504         // link
19505         if (cap = this.rules.link.exec(src)) {
19506           src = src.substring(cap[0].length);
19507           this.inLink = true;
19508           out += this.outputLink(cap, {
19509             href: cap[2],
19510             title: cap[3]
19511           });
19512           this.inLink = false;
19513           continue;
19514         }
19515     
19516         // reflink, nolink
19517         if ((cap = this.rules.reflink.exec(src))
19518             || (cap = this.rules.nolink.exec(src))) {
19519           src = src.substring(cap[0].length);
19520           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19521           link = this.links[link.toLowerCase()];
19522           if (!link || !link.href) {
19523             out += cap[0].charAt(0);
19524             src = cap[0].substring(1) + src;
19525             continue;
19526           }
19527           this.inLink = true;
19528           out += this.outputLink(cap, link);
19529           this.inLink = false;
19530           continue;
19531         }
19532     
19533         // strong
19534         if (cap = this.rules.strong.exec(src)) {
19535           src = src.substring(cap[0].length);
19536           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19537           continue;
19538         }
19539     
19540         // em
19541         if (cap = this.rules.em.exec(src)) {
19542           src = src.substring(cap[0].length);
19543           out += this.renderer.em(this.output(cap[2] || cap[1]));
19544           continue;
19545         }
19546     
19547         // code
19548         if (cap = this.rules.code.exec(src)) {
19549           src = src.substring(cap[0].length);
19550           out += this.renderer.codespan(escape(cap[2], true));
19551           continue;
19552         }
19553     
19554         // br
19555         if (cap = this.rules.br.exec(src)) {
19556           src = src.substring(cap[0].length);
19557           out += this.renderer.br();
19558           continue;
19559         }
19560     
19561         // del (gfm)
19562         if (cap = this.rules.del.exec(src)) {
19563           src = src.substring(cap[0].length);
19564           out += this.renderer.del(this.output(cap[1]));
19565           continue;
19566         }
19567     
19568         // text
19569         if (cap = this.rules.text.exec(src)) {
19570           src = src.substring(cap[0].length);
19571           out += this.renderer.text(escape(this.smartypants(cap[0])));
19572           continue;
19573         }
19574     
19575         if (src) {
19576           throw new
19577             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19578         }
19579       }
19580     
19581       return out;
19582     };
19583     
19584     /**
19585      * Compile Link
19586      */
19587     
19588     InlineLexer.prototype.outputLink = function(cap, link) {
19589       var href = escape(link.href)
19590         , title = link.title ? escape(link.title) : null;
19591     
19592       return cap[0].charAt(0) !== '!'
19593         ? this.renderer.link(href, title, this.output(cap[1]))
19594         : this.renderer.image(href, title, escape(cap[1]));
19595     };
19596     
19597     /**
19598      * Smartypants Transformations
19599      */
19600     
19601     InlineLexer.prototype.smartypants = function(text) {
19602       if (!this.options.smartypants)  { return text; }
19603       return text
19604         // em-dashes
19605         .replace(/---/g, '\u2014')
19606         // en-dashes
19607         .replace(/--/g, '\u2013')
19608         // opening singles
19609         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19610         // closing singles & apostrophes
19611         .replace(/'/g, '\u2019')
19612         // opening doubles
19613         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19614         // closing doubles
19615         .replace(/"/g, '\u201d')
19616         // ellipses
19617         .replace(/\.{3}/g, '\u2026');
19618     };
19619     
19620     /**
19621      * Mangle Links
19622      */
19623     
19624     InlineLexer.prototype.mangle = function(text) {
19625       if (!this.options.mangle) { return text; }
19626       var out = ''
19627         , l = text.length
19628         , i = 0
19629         , ch;
19630     
19631       for (; i < l; i++) {
19632         ch = text.charCodeAt(i);
19633         if (Math.random() > 0.5) {
19634           ch = 'x' + ch.toString(16);
19635         }
19636         out += '&#' + ch + ';';
19637       }
19638     
19639       return out;
19640     };
19641     
19642     /**
19643      * Renderer
19644      */
19645     
19646      /**
19647          * eval:var:Renderer
19648     */
19649     
19650     var Renderer   = function (options) {
19651       this.options = options || {};
19652     }
19653     
19654     Renderer.prototype.code = function(code, lang, escaped) {
19655       if (this.options.highlight) {
19656         var out = this.options.highlight(code, lang);
19657         if (out != null && out !== code) {
19658           escaped = true;
19659           code = out;
19660         }
19661       } else {
19662             // hack!!! - it's already escapeD?
19663             escaped = true;
19664       }
19665     
19666       if (!lang) {
19667         return '<pre><code>'
19668           + (escaped ? code : escape(code, true))
19669           + '\n</code></pre>';
19670       }
19671     
19672       return '<pre><code class="'
19673         + this.options.langPrefix
19674         + escape(lang, true)
19675         + '">'
19676         + (escaped ? code : escape(code, true))
19677         + '\n</code></pre>\n';
19678     };
19679     
19680     Renderer.prototype.blockquote = function(quote) {
19681       return '<blockquote>\n' + quote + '</blockquote>\n';
19682     };
19683     
19684     Renderer.prototype.html = function(html) {
19685       return html;
19686     };
19687     
19688     Renderer.prototype.heading = function(text, level, raw) {
19689       return '<h'
19690         + level
19691         + ' id="'
19692         + this.options.headerPrefix
19693         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19694         + '">'
19695         + text
19696         + '</h'
19697         + level
19698         + '>\n';
19699     };
19700     
19701     Renderer.prototype.hr = function() {
19702       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19703     };
19704     
19705     Renderer.prototype.list = function(body, ordered) {
19706       var type = ordered ? 'ol' : 'ul';
19707       return '<' + type + '>\n' + body + '</' + type + '>\n';
19708     };
19709     
19710     Renderer.prototype.listitem = function(text) {
19711       return '<li>' + text + '</li>\n';
19712     };
19713     
19714     Renderer.prototype.paragraph = function(text) {
19715       return '<p>' + text + '</p>\n';
19716     };
19717     
19718     Renderer.prototype.table = function(header, body) {
19719       return '<table class="table table-striped">\n'
19720         + '<thead>\n'
19721         + header
19722         + '</thead>\n'
19723         + '<tbody>\n'
19724         + body
19725         + '</tbody>\n'
19726         + '</table>\n';
19727     };
19728     
19729     Renderer.prototype.tablerow = function(content) {
19730       return '<tr>\n' + content + '</tr>\n';
19731     };
19732     
19733     Renderer.prototype.tablecell = function(content, flags) {
19734       var type = flags.header ? 'th' : 'td';
19735       var tag = flags.align
19736         ? '<' + type + ' style="text-align:' + flags.align + '">'
19737         : '<' + type + '>';
19738       return tag + content + '</' + type + '>\n';
19739     };
19740     
19741     // span level renderer
19742     Renderer.prototype.strong = function(text) {
19743       return '<strong>' + text + '</strong>';
19744     };
19745     
19746     Renderer.prototype.em = function(text) {
19747       return '<em>' + text + '</em>';
19748     };
19749     
19750     Renderer.prototype.codespan = function(text) {
19751       return '<code>' + text + '</code>';
19752     };
19753     
19754     Renderer.prototype.br = function() {
19755       return this.options.xhtml ? '<br/>' : '<br>';
19756     };
19757     
19758     Renderer.prototype.del = function(text) {
19759       return '<del>' + text + '</del>';
19760     };
19761     
19762     Renderer.prototype.link = function(href, title, text) {
19763       if (this.options.sanitize) {
19764         try {
19765           var prot = decodeURIComponent(unescape(href))
19766             .replace(/[^\w:]/g, '')
19767             .toLowerCase();
19768         } catch (e) {
19769           return '';
19770         }
19771         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19772           return '';
19773         }
19774       }
19775       var out = '<a href="' + href + '"';
19776       if (title) {
19777         out += ' title="' + title + '"';
19778       }
19779       out += '>' + text + '</a>';
19780       return out;
19781     };
19782     
19783     Renderer.prototype.image = function(href, title, text) {
19784       var out = '<img src="' + href + '" alt="' + text + '"';
19785       if (title) {
19786         out += ' title="' + title + '"';
19787       }
19788       out += this.options.xhtml ? '/>' : '>';
19789       return out;
19790     };
19791     
19792     Renderer.prototype.text = function(text) {
19793       return text;
19794     };
19795     
19796     /**
19797      * Parsing & Compiling
19798      */
19799          /**
19800          * eval:var:Parser
19801     */
19802     
19803     var Parser= function (options) {
19804       this.tokens = [];
19805       this.token = null;
19806       this.options = options || marked.defaults;
19807       this.options.renderer = this.options.renderer || new Renderer;
19808       this.renderer = this.options.renderer;
19809       this.renderer.options = this.options;
19810     }
19811     
19812     /**
19813      * Static Parse Method
19814      */
19815     
19816     Parser.parse = function(src, options, renderer) {
19817       var parser = new Parser(options, renderer);
19818       return parser.parse(src);
19819     };
19820     
19821     /**
19822      * Parse Loop
19823      */
19824     
19825     Parser.prototype.parse = function(src) {
19826       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19827       this.tokens = src.reverse();
19828     
19829       var out = '';
19830       while (this.next()) {
19831         out += this.tok();
19832       }
19833     
19834       return out;
19835     };
19836     
19837     /**
19838      * Next Token
19839      */
19840     
19841     Parser.prototype.next = function() {
19842       return this.token = this.tokens.pop();
19843     };
19844     
19845     /**
19846      * Preview Next Token
19847      */
19848     
19849     Parser.prototype.peek = function() {
19850       return this.tokens[this.tokens.length - 1] || 0;
19851     };
19852     
19853     /**
19854      * Parse Text Tokens
19855      */
19856     
19857     Parser.prototype.parseText = function() {
19858       var body = this.token.text;
19859     
19860       while (this.peek().type === 'text') {
19861         body += '\n' + this.next().text;
19862       }
19863     
19864       return this.inline.output(body);
19865     };
19866     
19867     /**
19868      * Parse Current Token
19869      */
19870     
19871     Parser.prototype.tok = function() {
19872       switch (this.token.type) {
19873         case 'space': {
19874           return '';
19875         }
19876         case 'hr': {
19877           return this.renderer.hr();
19878         }
19879         case 'heading': {
19880           return this.renderer.heading(
19881             this.inline.output(this.token.text),
19882             this.token.depth,
19883             this.token.text);
19884         }
19885         case 'code': {
19886           return this.renderer.code(this.token.text,
19887             this.token.lang,
19888             this.token.escaped);
19889         }
19890         case 'table': {
19891           var header = ''
19892             , body = ''
19893             , i
19894             , row
19895             , cell
19896             , flags
19897             , j;
19898     
19899           // header
19900           cell = '';
19901           for (i = 0; i < this.token.header.length; i++) {
19902             flags = { header: true, align: this.token.align[i] };
19903             cell += this.renderer.tablecell(
19904               this.inline.output(this.token.header[i]),
19905               { header: true, align: this.token.align[i] }
19906             );
19907           }
19908           header += this.renderer.tablerow(cell);
19909     
19910           for (i = 0; i < this.token.cells.length; i++) {
19911             row = this.token.cells[i];
19912     
19913             cell = '';
19914             for (j = 0; j < row.length; j++) {
19915               cell += this.renderer.tablecell(
19916                 this.inline.output(row[j]),
19917                 { header: false, align: this.token.align[j] }
19918               );
19919             }
19920     
19921             body += this.renderer.tablerow(cell);
19922           }
19923           return this.renderer.table(header, body);
19924         }
19925         case 'blockquote_start': {
19926           var body = '';
19927     
19928           while (this.next().type !== 'blockquote_end') {
19929             body += this.tok();
19930           }
19931     
19932           return this.renderer.blockquote(body);
19933         }
19934         case 'list_start': {
19935           var body = ''
19936             , ordered = this.token.ordered;
19937     
19938           while (this.next().type !== 'list_end') {
19939             body += this.tok();
19940           }
19941     
19942           return this.renderer.list(body, ordered);
19943         }
19944         case 'list_item_start': {
19945           var body = '';
19946     
19947           while (this.next().type !== 'list_item_end') {
19948             body += this.token.type === 'text'
19949               ? this.parseText()
19950               : this.tok();
19951           }
19952     
19953           return this.renderer.listitem(body);
19954         }
19955         case 'loose_item_start': {
19956           var body = '';
19957     
19958           while (this.next().type !== 'list_item_end') {
19959             body += this.tok();
19960           }
19961     
19962           return this.renderer.listitem(body);
19963         }
19964         case 'html': {
19965           var html = !this.token.pre && !this.options.pedantic
19966             ? this.inline.output(this.token.text)
19967             : this.token.text;
19968           return this.renderer.html(html);
19969         }
19970         case 'paragraph': {
19971           return this.renderer.paragraph(this.inline.output(this.token.text));
19972         }
19973         case 'text': {
19974           return this.renderer.paragraph(this.parseText());
19975         }
19976       }
19977     };
19978   
19979     
19980     /**
19981      * Marked
19982      */
19983          /**
19984          * eval:var:marked
19985     */
19986     var marked = function (src, opt, callback) {
19987       if (callback || typeof opt === 'function') {
19988         if (!callback) {
19989           callback = opt;
19990           opt = null;
19991         }
19992     
19993         opt = merge({}, marked.defaults, opt || {});
19994     
19995         var highlight = opt.highlight
19996           , tokens
19997           , pending
19998           , i = 0;
19999     
20000         try {
20001           tokens = Lexer.lex(src, opt)
20002         } catch (e) {
20003           return callback(e);
20004         }
20005     
20006         pending = tokens.length;
20007          /**
20008          * eval:var:done
20009     */
20010         var done = function(err) {
20011           if (err) {
20012             opt.highlight = highlight;
20013             return callback(err);
20014           }
20015     
20016           var out;
20017     
20018           try {
20019             out = Parser.parse(tokens, opt);
20020           } catch (e) {
20021             err = e;
20022           }
20023     
20024           opt.highlight = highlight;
20025     
20026           return err
20027             ? callback(err)
20028             : callback(null, out);
20029         };
20030     
20031         if (!highlight || highlight.length < 3) {
20032           return done();
20033         }
20034     
20035         delete opt.highlight;
20036     
20037         if (!pending) { return done(); }
20038     
20039         for (; i < tokens.length; i++) {
20040           (function(token) {
20041             if (token.type !== 'code') {
20042               return --pending || done();
20043             }
20044             return highlight(token.text, token.lang, function(err, code) {
20045               if (err) { return done(err); }
20046               if (code == null || code === token.text) {
20047                 return --pending || done();
20048               }
20049               token.text = code;
20050               token.escaped = true;
20051               --pending || done();
20052             });
20053           })(tokens[i]);
20054         }
20055     
20056         return;
20057       }
20058       try {
20059         if (opt) { opt = merge({}, marked.defaults, opt); }
20060         return Parser.parse(Lexer.lex(src, opt), opt);
20061       } catch (e) {
20062         e.message += '\nPlease report this to https://github.com/chjj/marked.';
20063         if ((opt || marked.defaults).silent) {
20064           return '<p>An error occured:</p><pre>'
20065             + escape(e.message + '', true)
20066             + '</pre>';
20067         }
20068         throw e;
20069       }
20070     }
20071     
20072     /**
20073      * Options
20074      */
20075     
20076     marked.options =
20077     marked.setOptions = function(opt) {
20078       merge(marked.defaults, opt);
20079       return marked;
20080     };
20081     
20082     marked.defaults = {
20083       gfm: true,
20084       tables: true,
20085       breaks: false,
20086       pedantic: false,
20087       sanitize: false,
20088       sanitizer: null,
20089       mangle: true,
20090       smartLists: false,
20091       silent: false,
20092       highlight: null,
20093       langPrefix: 'lang-',
20094       smartypants: false,
20095       headerPrefix: '',
20096       renderer: new Renderer,
20097       xhtml: false
20098     };
20099     
20100     /**
20101      * Expose
20102      */
20103     
20104     marked.Parser = Parser;
20105     marked.parser = Parser.parse;
20106     
20107     marked.Renderer = Renderer;
20108     
20109     marked.Lexer = Lexer;
20110     marked.lexer = Lexer.lex;
20111     
20112     marked.InlineLexer = InlineLexer;
20113     marked.inlineLexer = InlineLexer.output;
20114     
20115     marked.parse = marked;
20116     
20117     Roo.Markdown.marked = marked;
20118
20119 })();/*
20120  * Based on:
20121  * Ext JS Library 1.1.1
20122  * Copyright(c) 2006-2007, Ext JS, LLC.
20123  *
20124  * Originally Released Under LGPL - original licence link has changed is not relivant.
20125  *
20126  * Fork - LGPL
20127  * <script type="text/javascript">
20128  */
20129
20130
20131
20132 /*
20133  * These classes are derivatives of the similarly named classes in the YUI Library.
20134  * The original license:
20135  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
20136  * Code licensed under the BSD License:
20137  * http://developer.yahoo.net/yui/license.txt
20138  */
20139
20140 (function() {
20141
20142 var Event=Roo.EventManager;
20143 var Dom=Roo.lib.Dom;
20144
20145 /**
20146  * @class Roo.dd.DragDrop
20147  * @extends Roo.util.Observable
20148  * Defines the interface and base operation of items that that can be
20149  * dragged or can be drop targets.  It was designed to be extended, overriding
20150  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
20151  * Up to three html elements can be associated with a DragDrop instance:
20152  * <ul>
20153  * <li>linked element: the element that is passed into the constructor.
20154  * This is the element which defines the boundaries for interaction with
20155  * other DragDrop objects.</li>
20156  * <li>handle element(s): The drag operation only occurs if the element that
20157  * was clicked matches a handle element.  By default this is the linked
20158  * element, but there are times that you will want only a portion of the
20159  * linked element to initiate the drag operation, and the setHandleElId()
20160  * method provides a way to define this.</li>
20161  * <li>drag element: this represents the element that would be moved along
20162  * with the cursor during a drag operation.  By default, this is the linked
20163  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
20164  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
20165  * </li>
20166  * </ul>
20167  * This class should not be instantiated until the onload event to ensure that
20168  * the associated elements are available.
20169  * The following would define a DragDrop obj that would interact with any
20170  * other DragDrop obj in the "group1" group:
20171  * <pre>
20172  *  dd = new Roo.dd.DragDrop("div1", "group1");
20173  * </pre>
20174  * Since none of the event handlers have been implemented, nothing would
20175  * actually happen if you were to run the code above.  Normally you would
20176  * override this class or one of the default implementations, but you can
20177  * also override the methods you want on an instance of the class...
20178  * <pre>
20179  *  dd.onDragDrop = function(e, id) {
20180  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
20181  *  }
20182  * </pre>
20183  * @constructor
20184  * @param {String} id of the element that is linked to this instance
20185  * @param {String} sGroup the group of related DragDrop objects
20186  * @param {object} config an object containing configurable attributes
20187  *                Valid properties for DragDrop:
20188  *                    padding, isTarget, maintainOffset, primaryButtonOnly
20189  */
20190 Roo.dd.DragDrop = function(id, sGroup, config) {
20191     if (id) {
20192         this.init(id, sGroup, config);
20193     }
20194     
20195 };
20196
20197 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
20198
20199     /**
20200      * The id of the element associated with this object.  This is what we
20201      * refer to as the "linked element" because the size and position of
20202      * this element is used to determine when the drag and drop objects have
20203      * interacted.
20204      * @property id
20205      * @type String
20206      */
20207     id: null,
20208
20209     /**
20210      * Configuration attributes passed into the constructor
20211      * @property config
20212      * @type object
20213      */
20214     config: null,
20215
20216     /**
20217      * The id of the element that will be dragged.  By default this is same
20218      * as the linked element , but could be changed to another element. Ex:
20219      * Roo.dd.DDProxy
20220      * @property dragElId
20221      * @type String
20222      * @private
20223      */
20224     dragElId: null,
20225
20226     /**
20227      * the id of the element that initiates the drag operation.  By default
20228      * this is the linked element, but could be changed to be a child of this
20229      * element.  This lets us do things like only starting the drag when the
20230      * header element within the linked html element is clicked.
20231      * @property handleElId
20232      * @type String
20233      * @private
20234      */
20235     handleElId: null,
20236
20237     /**
20238      * An associative array of HTML tags that will be ignored if clicked.
20239      * @property invalidHandleTypes
20240      * @type {string: string}
20241      */
20242     invalidHandleTypes: null,
20243
20244     /**
20245      * An associative array of ids for elements that will be ignored if clicked
20246      * @property invalidHandleIds
20247      * @type {string: string}
20248      */
20249     invalidHandleIds: null,
20250
20251     /**
20252      * An indexted array of css class names for elements that will be ignored
20253      * if clicked.
20254      * @property invalidHandleClasses
20255      * @type string[]
20256      */
20257     invalidHandleClasses: null,
20258
20259     /**
20260      * The linked element's absolute X position at the time the drag was
20261      * started
20262      * @property startPageX
20263      * @type int
20264      * @private
20265      */
20266     startPageX: 0,
20267
20268     /**
20269      * The linked element's absolute X position at the time the drag was
20270      * started
20271      * @property startPageY
20272      * @type int
20273      * @private
20274      */
20275     startPageY: 0,
20276
20277     /**
20278      * The group defines a logical collection of DragDrop objects that are
20279      * related.  Instances only get events when interacting with other
20280      * DragDrop object in the same group.  This lets us define multiple
20281      * groups using a single DragDrop subclass if we want.
20282      * @property groups
20283      * @type {string: string}
20284      */
20285     groups: null,
20286
20287     /**
20288      * Individual drag/drop instances can be locked.  This will prevent
20289      * onmousedown start drag.
20290      * @property locked
20291      * @type boolean
20292      * @private
20293      */
20294     locked: false,
20295
20296     /**
20297      * Lock this instance
20298      * @method lock
20299      */
20300     lock: function() { this.locked = true; },
20301
20302     /**
20303      * Unlock this instace
20304      * @method unlock
20305      */
20306     unlock: function() { this.locked = false; },
20307
20308     /**
20309      * By default, all insances can be a drop target.  This can be disabled by
20310      * setting isTarget to false.
20311      * @method isTarget
20312      * @type boolean
20313      */
20314     isTarget: true,
20315
20316     /**
20317      * The padding configured for this drag and drop object for calculating
20318      * the drop zone intersection with this object.
20319      * @method padding
20320      * @type int[]
20321      */
20322     padding: null,
20323
20324     /**
20325      * Cached reference to the linked element
20326      * @property _domRef
20327      * @private
20328      */
20329     _domRef: null,
20330
20331     /**
20332      * Internal typeof flag
20333      * @property __ygDragDrop
20334      * @private
20335      */
20336     __ygDragDrop: true,
20337
20338     /**
20339      * Set to true when horizontal contraints are applied
20340      * @property constrainX
20341      * @type boolean
20342      * @private
20343      */
20344     constrainX: false,
20345
20346     /**
20347      * Set to true when vertical contraints are applied
20348      * @property constrainY
20349      * @type boolean
20350      * @private
20351      */
20352     constrainY: false,
20353
20354     /**
20355      * The left constraint
20356      * @property minX
20357      * @type int
20358      * @private
20359      */
20360     minX: 0,
20361
20362     /**
20363      * The right constraint
20364      * @property maxX
20365      * @type int
20366      * @private
20367      */
20368     maxX: 0,
20369
20370     /**
20371      * The up constraint
20372      * @property minY
20373      * @type int
20374      * @type int
20375      * @private
20376      */
20377     minY: 0,
20378
20379     /**
20380      * The down constraint
20381      * @property maxY
20382      * @type int
20383      * @private
20384      */
20385     maxY: 0,
20386
20387     /**
20388      * Maintain offsets when we resetconstraints.  Set to true when you want
20389      * the position of the element relative to its parent to stay the same
20390      * when the page changes
20391      *
20392      * @property maintainOffset
20393      * @type boolean
20394      */
20395     maintainOffset: false,
20396
20397     /**
20398      * Array of pixel locations the element will snap to if we specified a
20399      * horizontal graduation/interval.  This array is generated automatically
20400      * when you define a tick interval.
20401      * @property xTicks
20402      * @type int[]
20403      */
20404     xTicks: null,
20405
20406     /**
20407      * Array of pixel locations the element will snap to if we specified a
20408      * vertical graduation/interval.  This array is generated automatically
20409      * when you define a tick interval.
20410      * @property yTicks
20411      * @type int[]
20412      */
20413     yTicks: null,
20414
20415     /**
20416      * By default the drag and drop instance will only respond to the primary
20417      * button click (left button for a right-handed mouse).  Set to true to
20418      * allow drag and drop to start with any mouse click that is propogated
20419      * by the browser
20420      * @property primaryButtonOnly
20421      * @type boolean
20422      */
20423     primaryButtonOnly: true,
20424
20425     /**
20426      * The availabe property is false until the linked dom element is accessible.
20427      * @property available
20428      * @type boolean
20429      */
20430     available: false,
20431
20432     /**
20433      * By default, drags can only be initiated if the mousedown occurs in the
20434      * region the linked element is.  This is done in part to work around a
20435      * bug in some browsers that mis-report the mousedown if the previous
20436      * mouseup happened outside of the window.  This property is set to true
20437      * if outer handles are defined.
20438      *
20439      * @property hasOuterHandles
20440      * @type boolean
20441      * @default false
20442      */
20443     hasOuterHandles: false,
20444
20445     /**
20446      * Code that executes immediately before the startDrag event
20447      * @method b4StartDrag
20448      * @private
20449      */
20450     b4StartDrag: function(x, y) { },
20451
20452     /**
20453      * Abstract method called after a drag/drop object is clicked
20454      * and the drag or mousedown time thresholds have beeen met.
20455      * @method startDrag
20456      * @param {int} X click location
20457      * @param {int} Y click location
20458      */
20459     startDrag: function(x, y) { /* override this */ },
20460
20461     /**
20462      * Code that executes immediately before the onDrag event
20463      * @method b4Drag
20464      * @private
20465      */
20466     b4Drag: function(e) { },
20467
20468     /**
20469      * Abstract method called during the onMouseMove event while dragging an
20470      * object.
20471      * @method onDrag
20472      * @param {Event} e the mousemove event
20473      */
20474     onDrag: function(e) { /* override this */ },
20475
20476     /**
20477      * Abstract method called when this element fist begins hovering over
20478      * another DragDrop obj
20479      * @method onDragEnter
20480      * @param {Event} e the mousemove event
20481      * @param {String|DragDrop[]} id In POINT mode, the element
20482      * id this is hovering over.  In INTERSECT mode, an array of one or more
20483      * dragdrop items being hovered over.
20484      */
20485     onDragEnter: function(e, id) { /* override this */ },
20486
20487     /**
20488      * Code that executes immediately before the onDragOver event
20489      * @method b4DragOver
20490      * @private
20491      */
20492     b4DragOver: function(e) { },
20493
20494     /**
20495      * Abstract method called when this element is hovering over another
20496      * DragDrop obj
20497      * @method onDragOver
20498      * @param {Event} e the mousemove event
20499      * @param {String|DragDrop[]} id In POINT mode, the element
20500      * id this is hovering over.  In INTERSECT mode, an array of dd items
20501      * being hovered over.
20502      */
20503     onDragOver: function(e, id) { /* override this */ },
20504
20505     /**
20506      * Code that executes immediately before the onDragOut event
20507      * @method b4DragOut
20508      * @private
20509      */
20510     b4DragOut: function(e) { },
20511
20512     /**
20513      * Abstract method called when we are no longer hovering over an element
20514      * @method onDragOut
20515      * @param {Event} e the mousemove event
20516      * @param {String|DragDrop[]} id In POINT mode, the element
20517      * id this was hovering over.  In INTERSECT mode, an array of dd items
20518      * that the mouse is no longer over.
20519      */
20520     onDragOut: function(e, id) { /* override this */ },
20521
20522     /**
20523      * Code that executes immediately before the onDragDrop event
20524      * @method b4DragDrop
20525      * @private
20526      */
20527     b4DragDrop: function(e) { },
20528
20529     /**
20530      * Abstract method called when this item is dropped on another DragDrop
20531      * obj
20532      * @method onDragDrop
20533      * @param {Event} e the mouseup event
20534      * @param {String|DragDrop[]} id In POINT mode, the element
20535      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20536      * was dropped on.
20537      */
20538     onDragDrop: function(e, id) { /* override this */ },
20539
20540     /**
20541      * Abstract method called when this item is dropped on an area with no
20542      * drop target
20543      * @method onInvalidDrop
20544      * @param {Event} e the mouseup event
20545      */
20546     onInvalidDrop: function(e) { /* override this */ },
20547
20548     /**
20549      * Code that executes immediately before the endDrag event
20550      * @method b4EndDrag
20551      * @private
20552      */
20553     b4EndDrag: function(e) { },
20554
20555     /**
20556      * Fired when we are done dragging the object
20557      * @method endDrag
20558      * @param {Event} e the mouseup event
20559      */
20560     endDrag: function(e) { /* override this */ },
20561
20562     /**
20563      * Code executed immediately before the onMouseDown event
20564      * @method b4MouseDown
20565      * @param {Event} e the mousedown event
20566      * @private
20567      */
20568     b4MouseDown: function(e) {  },
20569
20570     /**
20571      * Event handler that fires when a drag/drop obj gets a mousedown
20572      * @method onMouseDown
20573      * @param {Event} e the mousedown event
20574      */
20575     onMouseDown: function(e) { /* override this */ },
20576
20577     /**
20578      * Event handler that fires when a drag/drop obj gets a mouseup
20579      * @method onMouseUp
20580      * @param {Event} e the mouseup event
20581      */
20582     onMouseUp: function(e) { /* override this */ },
20583
20584     /**
20585      * Override the onAvailable method to do what is needed after the initial
20586      * position was determined.
20587      * @method onAvailable
20588      */
20589     onAvailable: function () {
20590     },
20591
20592     /*
20593      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20594      * @type Object
20595      */
20596     defaultPadding : {left:0, right:0, top:0, bottom:0},
20597
20598     /*
20599      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20600  *
20601  * Usage:
20602  <pre><code>
20603  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20604                 { dragElId: "existingProxyDiv" });
20605  dd.startDrag = function(){
20606      this.constrainTo("parent-id");
20607  };
20608  </code></pre>
20609  * Or you can initalize it using the {@link Roo.Element} object:
20610  <pre><code>
20611  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20612      startDrag : function(){
20613          this.constrainTo("parent-id");
20614      }
20615  });
20616  </code></pre>
20617      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20618      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20619      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20620      * an object containing the sides to pad. For example: {right:10, bottom:10}
20621      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20622      */
20623     constrainTo : function(constrainTo, pad, inContent){
20624         if(typeof pad == "number"){
20625             pad = {left: pad, right:pad, top:pad, bottom:pad};
20626         }
20627         pad = pad || this.defaultPadding;
20628         var b = Roo.get(this.getEl()).getBox();
20629         var ce = Roo.get(constrainTo);
20630         var s = ce.getScroll();
20631         var c, cd = ce.dom;
20632         if(cd == document.body){
20633             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20634         }else{
20635             xy = ce.getXY();
20636             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20637         }
20638
20639
20640         var topSpace = b.y - c.y;
20641         var leftSpace = b.x - c.x;
20642
20643         this.resetConstraints();
20644         this.setXConstraint(leftSpace - (pad.left||0), // left
20645                 c.width - leftSpace - b.width - (pad.right||0) //right
20646         );
20647         this.setYConstraint(topSpace - (pad.top||0), //top
20648                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20649         );
20650     },
20651
20652     /**
20653      * Returns a reference to the linked element
20654      * @method getEl
20655      * @return {HTMLElement} the html element
20656      */
20657     getEl: function() {
20658         if (!this._domRef) {
20659             this._domRef = Roo.getDom(this.id);
20660         }
20661
20662         return this._domRef;
20663     },
20664
20665     /**
20666      * Returns a reference to the actual element to drag.  By default this is
20667      * the same as the html element, but it can be assigned to another
20668      * element. An example of this can be found in Roo.dd.DDProxy
20669      * @method getDragEl
20670      * @return {HTMLElement} the html element
20671      */
20672     getDragEl: function() {
20673         return Roo.getDom(this.dragElId);
20674     },
20675
20676     /**
20677      * Sets up the DragDrop object.  Must be called in the constructor of any
20678      * Roo.dd.DragDrop subclass
20679      * @method init
20680      * @param id the id of the linked element
20681      * @param {String} sGroup the group of related items
20682      * @param {object} config configuration attributes
20683      */
20684     init: function(id, sGroup, config) {
20685         this.initTarget(id, sGroup, config);
20686         if (!Roo.isTouch) {
20687             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20688         }
20689         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20690         // Event.on(this.id, "selectstart", Event.preventDefault);
20691     },
20692
20693     /**
20694      * Initializes Targeting functionality only... the object does not
20695      * get a mousedown handler.
20696      * @method initTarget
20697      * @param id the id of the linked element
20698      * @param {String} sGroup the group of related items
20699      * @param {object} config configuration attributes
20700      */
20701     initTarget: function(id, sGroup, config) {
20702
20703         // configuration attributes
20704         this.config = config || {};
20705
20706         // create a local reference to the drag and drop manager
20707         this.DDM = Roo.dd.DDM;
20708         // initialize the groups array
20709         this.groups = {};
20710
20711         // assume that we have an element reference instead of an id if the
20712         // parameter is not a string
20713         if (typeof id !== "string") {
20714             id = Roo.id(id);
20715         }
20716
20717         // set the id
20718         this.id = id;
20719
20720         // add to an interaction group
20721         this.addToGroup((sGroup) ? sGroup : "default");
20722
20723         // We don't want to register this as the handle with the manager
20724         // so we just set the id rather than calling the setter.
20725         this.handleElId = id;
20726
20727         // the linked element is the element that gets dragged by default
20728         this.setDragElId(id);
20729
20730         // by default, clicked anchors will not start drag operations.
20731         this.invalidHandleTypes = { A: "A" };
20732         this.invalidHandleIds = {};
20733         this.invalidHandleClasses = [];
20734
20735         this.applyConfig();
20736
20737         this.handleOnAvailable();
20738     },
20739
20740     /**
20741      * Applies the configuration parameters that were passed into the constructor.
20742      * This is supposed to happen at each level through the inheritance chain.  So
20743      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20744      * DragDrop in order to get all of the parameters that are available in
20745      * each object.
20746      * @method applyConfig
20747      */
20748     applyConfig: function() {
20749
20750         // configurable properties:
20751         //    padding, isTarget, maintainOffset, primaryButtonOnly
20752         this.padding           = this.config.padding || [0, 0, 0, 0];
20753         this.isTarget          = (this.config.isTarget !== false);
20754         this.maintainOffset    = (this.config.maintainOffset);
20755         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20756
20757     },
20758
20759     /**
20760      * Executed when the linked element is available
20761      * @method handleOnAvailable
20762      * @private
20763      */
20764     handleOnAvailable: function() {
20765         this.available = true;
20766         this.resetConstraints();
20767         this.onAvailable();
20768     },
20769
20770      /**
20771      * Configures the padding for the target zone in px.  Effectively expands
20772      * (or reduces) the virtual object size for targeting calculations.
20773      * Supports css-style shorthand; if only one parameter is passed, all sides
20774      * will have that padding, and if only two are passed, the top and bottom
20775      * will have the first param, the left and right the second.
20776      * @method setPadding
20777      * @param {int} iTop    Top pad
20778      * @param {int} iRight  Right pad
20779      * @param {int} iBot    Bot pad
20780      * @param {int} iLeft   Left pad
20781      */
20782     setPadding: function(iTop, iRight, iBot, iLeft) {
20783         // this.padding = [iLeft, iRight, iTop, iBot];
20784         if (!iRight && 0 !== iRight) {
20785             this.padding = [iTop, iTop, iTop, iTop];
20786         } else if (!iBot && 0 !== iBot) {
20787             this.padding = [iTop, iRight, iTop, iRight];
20788         } else {
20789             this.padding = [iTop, iRight, iBot, iLeft];
20790         }
20791     },
20792
20793     /**
20794      * Stores the initial placement of the linked element.
20795      * @method setInitialPosition
20796      * @param {int} diffX   the X offset, default 0
20797      * @param {int} diffY   the Y offset, default 0
20798      */
20799     setInitPosition: function(diffX, diffY) {
20800         var el = this.getEl();
20801
20802         if (!this.DDM.verifyEl(el)) {
20803             return;
20804         }
20805
20806         var dx = diffX || 0;
20807         var dy = diffY || 0;
20808
20809         var p = Dom.getXY( el );
20810
20811         this.initPageX = p[0] - dx;
20812         this.initPageY = p[1] - dy;
20813
20814         this.lastPageX = p[0];
20815         this.lastPageY = p[1];
20816
20817
20818         this.setStartPosition(p);
20819     },
20820
20821     /**
20822      * Sets the start position of the element.  This is set when the obj
20823      * is initialized, the reset when a drag is started.
20824      * @method setStartPosition
20825      * @param pos current position (from previous lookup)
20826      * @private
20827      */
20828     setStartPosition: function(pos) {
20829         var p = pos || Dom.getXY( this.getEl() );
20830         this.deltaSetXY = null;
20831
20832         this.startPageX = p[0];
20833         this.startPageY = p[1];
20834     },
20835
20836     /**
20837      * Add this instance to a group of related drag/drop objects.  All
20838      * instances belong to at least one group, and can belong to as many
20839      * groups as needed.
20840      * @method addToGroup
20841      * @param sGroup {string} the name of the group
20842      */
20843     addToGroup: function(sGroup) {
20844         this.groups[sGroup] = true;
20845         this.DDM.regDragDrop(this, sGroup);
20846     },
20847
20848     /**
20849      * Remove's this instance from the supplied interaction group
20850      * @method removeFromGroup
20851      * @param {string}  sGroup  The group to drop
20852      */
20853     removeFromGroup: function(sGroup) {
20854         if (this.groups[sGroup]) {
20855             delete this.groups[sGroup];
20856         }
20857
20858         this.DDM.removeDDFromGroup(this, sGroup);
20859     },
20860
20861     /**
20862      * Allows you to specify that an element other than the linked element
20863      * will be moved with the cursor during a drag
20864      * @method setDragElId
20865      * @param id {string} the id of the element that will be used to initiate the drag
20866      */
20867     setDragElId: function(id) {
20868         this.dragElId = id;
20869     },
20870
20871     /**
20872      * Allows you to specify a child of the linked element that should be
20873      * used to initiate the drag operation.  An example of this would be if
20874      * you have a content div with text and links.  Clicking anywhere in the
20875      * content area would normally start the drag operation.  Use this method
20876      * to specify that an element inside of the content div is the element
20877      * that starts the drag operation.
20878      * @method setHandleElId
20879      * @param id {string} the id of the element that will be used to
20880      * initiate the drag.
20881      */
20882     setHandleElId: function(id) {
20883         if (typeof id !== "string") {
20884             id = Roo.id(id);
20885         }
20886         this.handleElId = id;
20887         this.DDM.regHandle(this.id, id);
20888     },
20889
20890     /**
20891      * Allows you to set an element outside of the linked element as a drag
20892      * handle
20893      * @method setOuterHandleElId
20894      * @param id the id of the element that will be used to initiate the drag
20895      */
20896     setOuterHandleElId: function(id) {
20897         if (typeof id !== "string") {
20898             id = Roo.id(id);
20899         }
20900         Event.on(id, "mousedown",
20901                 this.handleMouseDown, this);
20902         this.setHandleElId(id);
20903
20904         this.hasOuterHandles = true;
20905     },
20906
20907     /**
20908      * Remove all drag and drop hooks for this element
20909      * @method unreg
20910      */
20911     unreg: function() {
20912         Event.un(this.id, "mousedown",
20913                 this.handleMouseDown);
20914         Event.un(this.id, "touchstart",
20915                 this.handleMouseDown);
20916         this._domRef = null;
20917         this.DDM._remove(this);
20918     },
20919
20920     destroy : function(){
20921         this.unreg();
20922     },
20923
20924     /**
20925      * Returns true if this instance is locked, or the drag drop mgr is locked
20926      * (meaning that all drag/drop is disabled on the page.)
20927      * @method isLocked
20928      * @return {boolean} true if this obj or all drag/drop is locked, else
20929      * false
20930      */
20931     isLocked: function() {
20932         return (this.DDM.isLocked() || this.locked);
20933     },
20934
20935     /**
20936      * Fired when this object is clicked
20937      * @method handleMouseDown
20938      * @param {Event} e
20939      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20940      * @private
20941      */
20942     handleMouseDown: function(e, oDD){
20943      
20944         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20945             //Roo.log('not touch/ button !=0');
20946             return;
20947         }
20948         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20949             return; // double touch..
20950         }
20951         
20952
20953         if (this.isLocked()) {
20954             //Roo.log('locked');
20955             return;
20956         }
20957
20958         this.DDM.refreshCache(this.groups);
20959 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20960         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20961         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20962             //Roo.log('no outer handes or not over target');
20963                 // do nothing.
20964         } else {
20965 //            Roo.log('check validator');
20966             if (this.clickValidator(e)) {
20967 //                Roo.log('validate success');
20968                 // set the initial element position
20969                 this.setStartPosition();
20970
20971
20972                 this.b4MouseDown(e);
20973                 this.onMouseDown(e);
20974
20975                 this.DDM.handleMouseDown(e, this);
20976
20977                 this.DDM.stopEvent(e);
20978             } else {
20979
20980
20981             }
20982         }
20983     },
20984
20985     clickValidator: function(e) {
20986         var target = e.getTarget();
20987         return ( this.isValidHandleChild(target) &&
20988                     (this.id == this.handleElId ||
20989                         this.DDM.handleWasClicked(target, this.id)) );
20990     },
20991
20992     /**
20993      * Allows you to specify a tag name that should not start a drag operation
20994      * when clicked.  This is designed to facilitate embedding links within a
20995      * drag handle that do something other than start the drag.
20996      * @method addInvalidHandleType
20997      * @param {string} tagName the type of element to exclude
20998      */
20999     addInvalidHandleType: function(tagName) {
21000         var type = tagName.toUpperCase();
21001         this.invalidHandleTypes[type] = type;
21002     },
21003
21004     /**
21005      * Lets you to specify an element id for a child of a drag handle
21006      * that should not initiate a drag
21007      * @method addInvalidHandleId
21008      * @param {string} id the element id of the element you wish to ignore
21009      */
21010     addInvalidHandleId: function(id) {
21011         if (typeof id !== "string") {
21012             id = Roo.id(id);
21013         }
21014         this.invalidHandleIds[id] = id;
21015     },
21016
21017     /**
21018      * Lets you specify a css class of elements that will not initiate a drag
21019      * @method addInvalidHandleClass
21020      * @param {string} cssClass the class of the elements you wish to ignore
21021      */
21022     addInvalidHandleClass: function(cssClass) {
21023         this.invalidHandleClasses.push(cssClass);
21024     },
21025
21026     /**
21027      * Unsets an excluded tag name set by addInvalidHandleType
21028      * @method removeInvalidHandleType
21029      * @param {string} tagName the type of element to unexclude
21030      */
21031     removeInvalidHandleType: function(tagName) {
21032         var type = tagName.toUpperCase();
21033         // this.invalidHandleTypes[type] = null;
21034         delete this.invalidHandleTypes[type];
21035     },
21036
21037     /**
21038      * Unsets an invalid handle id
21039      * @method removeInvalidHandleId
21040      * @param {string} id the id of the element to re-enable
21041      */
21042     removeInvalidHandleId: function(id) {
21043         if (typeof id !== "string") {
21044             id = Roo.id(id);
21045         }
21046         delete this.invalidHandleIds[id];
21047     },
21048
21049     /**
21050      * Unsets an invalid css class
21051      * @method removeInvalidHandleClass
21052      * @param {string} cssClass the class of the element(s) you wish to
21053      * re-enable
21054      */
21055     removeInvalidHandleClass: function(cssClass) {
21056         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
21057             if (this.invalidHandleClasses[i] == cssClass) {
21058                 delete this.invalidHandleClasses[i];
21059             }
21060         }
21061     },
21062
21063     /**
21064      * Checks the tag exclusion list to see if this click should be ignored
21065      * @method isValidHandleChild
21066      * @param {HTMLElement} node the HTMLElement to evaluate
21067      * @return {boolean} true if this is a valid tag type, false if not
21068      */
21069     isValidHandleChild: function(node) {
21070
21071         var valid = true;
21072         // var n = (node.nodeName == "#text") ? node.parentNode : node;
21073         var nodeName;
21074         try {
21075             nodeName = node.nodeName.toUpperCase();
21076         } catch(e) {
21077             nodeName = node.nodeName;
21078         }
21079         valid = valid && !this.invalidHandleTypes[nodeName];
21080         valid = valid && !this.invalidHandleIds[node.id];
21081
21082         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
21083             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
21084         }
21085
21086
21087         return valid;
21088
21089     },
21090
21091     /**
21092      * Create the array of horizontal tick marks if an interval was specified
21093      * in setXConstraint().
21094      * @method setXTicks
21095      * @private
21096      */
21097     setXTicks: function(iStartX, iTickSize) {
21098         this.xTicks = [];
21099         this.xTickSize = iTickSize;
21100
21101         var tickMap = {};
21102
21103         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
21104             if (!tickMap[i]) {
21105                 this.xTicks[this.xTicks.length] = i;
21106                 tickMap[i] = true;
21107             }
21108         }
21109
21110         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
21111             if (!tickMap[i]) {
21112                 this.xTicks[this.xTicks.length] = i;
21113                 tickMap[i] = true;
21114             }
21115         }
21116
21117         this.xTicks.sort(this.DDM.numericSort) ;
21118     },
21119
21120     /**
21121      * Create the array of vertical tick marks if an interval was specified in
21122      * setYConstraint().
21123      * @method setYTicks
21124      * @private
21125      */
21126     setYTicks: function(iStartY, iTickSize) {
21127         this.yTicks = [];
21128         this.yTickSize = iTickSize;
21129
21130         var tickMap = {};
21131
21132         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
21133             if (!tickMap[i]) {
21134                 this.yTicks[this.yTicks.length] = i;
21135                 tickMap[i] = true;
21136             }
21137         }
21138
21139         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
21140             if (!tickMap[i]) {
21141                 this.yTicks[this.yTicks.length] = i;
21142                 tickMap[i] = true;
21143             }
21144         }
21145
21146         this.yTicks.sort(this.DDM.numericSort) ;
21147     },
21148
21149     /**
21150      * By default, the element can be dragged any place on the screen.  Use
21151      * this method to limit the horizontal travel of the element.  Pass in
21152      * 0,0 for the parameters if you want to lock the drag to the y axis.
21153      * @method setXConstraint
21154      * @param {int} iLeft the number of pixels the element can move to the left
21155      * @param {int} iRight the number of pixels the element can move to the
21156      * right
21157      * @param {int} iTickSize optional parameter for specifying that the
21158      * element
21159      * should move iTickSize pixels at a time.
21160      */
21161     setXConstraint: function(iLeft, iRight, iTickSize) {
21162         this.leftConstraint = iLeft;
21163         this.rightConstraint = iRight;
21164
21165         this.minX = this.initPageX - iLeft;
21166         this.maxX = this.initPageX + iRight;
21167         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
21168
21169         this.constrainX = true;
21170     },
21171
21172     /**
21173      * Clears any constraints applied to this instance.  Also clears ticks
21174      * since they can't exist independent of a constraint at this time.
21175      * @method clearConstraints
21176      */
21177     clearConstraints: function() {
21178         this.constrainX = false;
21179         this.constrainY = false;
21180         this.clearTicks();
21181     },
21182
21183     /**
21184      * Clears any tick interval defined for this instance
21185      * @method clearTicks
21186      */
21187     clearTicks: function() {
21188         this.xTicks = null;
21189         this.yTicks = null;
21190         this.xTickSize = 0;
21191         this.yTickSize = 0;
21192     },
21193
21194     /**
21195      * By default, the element can be dragged any place on the screen.  Set
21196      * this to limit the vertical travel of the element.  Pass in 0,0 for the
21197      * parameters if you want to lock the drag to the x axis.
21198      * @method setYConstraint
21199      * @param {int} iUp the number of pixels the element can move up
21200      * @param {int} iDown the number of pixels the element can move down
21201      * @param {int} iTickSize optional parameter for specifying that the
21202      * element should move iTickSize pixels at a time.
21203      */
21204     setYConstraint: function(iUp, iDown, iTickSize) {
21205         this.topConstraint = iUp;
21206         this.bottomConstraint = iDown;
21207
21208         this.minY = this.initPageY - iUp;
21209         this.maxY = this.initPageY + iDown;
21210         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21211
21212         this.constrainY = true;
21213
21214     },
21215
21216     /**
21217      * resetConstraints must be called if you manually reposition a dd element.
21218      * @method resetConstraints
21219      * @param {boolean} maintainOffset
21220      */
21221     resetConstraints: function() {
21222
21223
21224         // Maintain offsets if necessary
21225         if (this.initPageX || this.initPageX === 0) {
21226             // figure out how much this thing has moved
21227             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21228             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21229
21230             this.setInitPosition(dx, dy);
21231
21232         // This is the first time we have detected the element's position
21233         } else {
21234             this.setInitPosition();
21235         }
21236
21237         if (this.constrainX) {
21238             this.setXConstraint( this.leftConstraint,
21239                                  this.rightConstraint,
21240                                  this.xTickSize        );
21241         }
21242
21243         if (this.constrainY) {
21244             this.setYConstraint( this.topConstraint,
21245                                  this.bottomConstraint,
21246                                  this.yTickSize         );
21247         }
21248     },
21249
21250     /**
21251      * Normally the drag element is moved pixel by pixel, but we can specify
21252      * that it move a number of pixels at a time.  This method resolves the
21253      * location when we have it set up like this.
21254      * @method getTick
21255      * @param {int} val where we want to place the object
21256      * @param {int[]} tickArray sorted array of valid points
21257      * @return {int} the closest tick
21258      * @private
21259      */
21260     getTick: function(val, tickArray) {
21261
21262         if (!tickArray) {
21263             // If tick interval is not defined, it is effectively 1 pixel,
21264             // so we return the value passed to us.
21265             return val;
21266         } else if (tickArray[0] >= val) {
21267             // The value is lower than the first tick, so we return the first
21268             // tick.
21269             return tickArray[0];
21270         } else {
21271             for (var i=0, len=tickArray.length; i<len; ++i) {
21272                 var next = i + 1;
21273                 if (tickArray[next] && tickArray[next] >= val) {
21274                     var diff1 = val - tickArray[i];
21275                     var diff2 = tickArray[next] - val;
21276                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21277                 }
21278             }
21279
21280             // The value is larger than the last tick, so we return the last
21281             // tick.
21282             return tickArray[tickArray.length - 1];
21283         }
21284     },
21285
21286     /**
21287      * toString method
21288      * @method toString
21289      * @return {string} string representation of the dd obj
21290      */
21291     toString: function() {
21292         return ("DragDrop " + this.id);
21293     }
21294
21295 });
21296
21297 })();
21298 /*
21299  * Based on:
21300  * Ext JS Library 1.1.1
21301  * Copyright(c) 2006-2007, Ext JS, LLC.
21302  *
21303  * Originally Released Under LGPL - original licence link has changed is not relivant.
21304  *
21305  * Fork - LGPL
21306  * <script type="text/javascript">
21307  */
21308
21309
21310 /**
21311  * The drag and drop utility provides a framework for building drag and drop
21312  * applications.  In addition to enabling drag and drop for specific elements,
21313  * the drag and drop elements are tracked by the manager class, and the
21314  * interactions between the various elements are tracked during the drag and
21315  * the implementing code is notified about these important moments.
21316  */
21317
21318 // Only load the library once.  Rewriting the manager class would orphan
21319 // existing drag and drop instances.
21320 if (!Roo.dd.DragDropMgr) {
21321
21322 /**
21323  * @class Roo.dd.DragDropMgr
21324  * DragDropMgr is a singleton that tracks the element interaction for
21325  * all DragDrop items in the window.  Generally, you will not call
21326  * this class directly, but it does have helper methods that could
21327  * be useful in your DragDrop implementations.
21328  * @static
21329  */
21330 Roo.dd.DragDropMgr = function() {
21331
21332     var Event = Roo.EventManager;
21333
21334     return {
21335
21336         /**
21337          * Two dimensional Array of registered DragDrop objects.  The first
21338          * dimension is the DragDrop item group, the second the DragDrop
21339          * object.
21340          * @property ids
21341          * @type {string: string}
21342          * @private
21343          * @static
21344          */
21345         ids: {},
21346
21347         /**
21348          * Array of element ids defined as drag handles.  Used to determine
21349          * if the element that generated the mousedown event is actually the
21350          * handle and not the html element itself.
21351          * @property handleIds
21352          * @type {string: string}
21353          * @private
21354          * @static
21355          */
21356         handleIds: {},
21357
21358         /**
21359          * the DragDrop object that is currently being dragged
21360          * @property dragCurrent
21361          * @type DragDrop
21362          * @private
21363          * @static
21364          **/
21365         dragCurrent: null,
21366
21367         /**
21368          * the DragDrop object(s) that are being hovered over
21369          * @property dragOvers
21370          * @type Array
21371          * @private
21372          * @static
21373          */
21374         dragOvers: {},
21375
21376         /**
21377          * the X distance between the cursor and the object being dragged
21378          * @property deltaX
21379          * @type int
21380          * @private
21381          * @static
21382          */
21383         deltaX: 0,
21384
21385         /**
21386          * the Y distance between the cursor and the object being dragged
21387          * @property deltaY
21388          * @type int
21389          * @private
21390          * @static
21391          */
21392         deltaY: 0,
21393
21394         /**
21395          * Flag to determine if we should prevent the default behavior of the
21396          * events we define. By default this is true, but this can be set to
21397          * false if you need the default behavior (not recommended)
21398          * @property preventDefault
21399          * @type boolean
21400          * @static
21401          */
21402         preventDefault: true,
21403
21404         /**
21405          * Flag to determine if we should stop the propagation of the events
21406          * we generate. This is true by default but you may want to set it to
21407          * false if the html element contains other features that require the
21408          * mouse click.
21409          * @property stopPropagation
21410          * @type boolean
21411          * @static
21412          */
21413         stopPropagation: true,
21414
21415         /**
21416          * Internal flag that is set to true when drag and drop has been
21417          * intialized
21418          * @property initialized
21419          * @private
21420          * @static
21421          */
21422         initalized: false,
21423
21424         /**
21425          * All drag and drop can be disabled.
21426          * @property locked
21427          * @private
21428          * @static
21429          */
21430         locked: false,
21431
21432         /**
21433          * Called the first time an element is registered.
21434          * @method init
21435          * @private
21436          * @static
21437          */
21438         init: function() {
21439             this.initialized = true;
21440         },
21441
21442         /**
21443          * In point mode, drag and drop interaction is defined by the
21444          * location of the cursor during the drag/drop
21445          * @property POINT
21446          * @type int
21447          * @static
21448          */
21449         POINT: 0,
21450
21451         /**
21452          * In intersect mode, drag and drop interactio nis defined by the
21453          * overlap of two or more drag and drop objects.
21454          * @property INTERSECT
21455          * @type int
21456          * @static
21457          */
21458         INTERSECT: 1,
21459
21460         /**
21461          * The current drag and drop mode.  Default: POINT
21462          * @property mode
21463          * @type int
21464          * @static
21465          */
21466         mode: 0,
21467
21468         /**
21469          * Runs method on all drag and drop objects
21470          * @method _execOnAll
21471          * @private
21472          * @static
21473          */
21474         _execOnAll: function(sMethod, args) {
21475             for (var i in this.ids) {
21476                 for (var j in this.ids[i]) {
21477                     var oDD = this.ids[i][j];
21478                     if (! this.isTypeOfDD(oDD)) {
21479                         continue;
21480                     }
21481                     oDD[sMethod].apply(oDD, args);
21482                 }
21483             }
21484         },
21485
21486         /**
21487          * Drag and drop initialization.  Sets up the global event handlers
21488          * @method _onLoad
21489          * @private
21490          * @static
21491          */
21492         _onLoad: function() {
21493
21494             this.init();
21495
21496             if (!Roo.isTouch) {
21497                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21498                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21499             }
21500             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21501             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21502             
21503             Event.on(window,   "unload",    this._onUnload, this, true);
21504             Event.on(window,   "resize",    this._onResize, this, true);
21505             // Event.on(window,   "mouseout",    this._test);
21506
21507         },
21508
21509         /**
21510          * Reset constraints on all drag and drop objs
21511          * @method _onResize
21512          * @private
21513          * @static
21514          */
21515         _onResize: function(e) {
21516             this._execOnAll("resetConstraints", []);
21517         },
21518
21519         /**
21520          * Lock all drag and drop functionality
21521          * @method lock
21522          * @static
21523          */
21524         lock: function() { this.locked = true; },
21525
21526         /**
21527          * Unlock all drag and drop functionality
21528          * @method unlock
21529          * @static
21530          */
21531         unlock: function() { this.locked = false; },
21532
21533         /**
21534          * Is drag and drop locked?
21535          * @method isLocked
21536          * @return {boolean} True if drag and drop is locked, false otherwise.
21537          * @static
21538          */
21539         isLocked: function() { return this.locked; },
21540
21541         /**
21542          * Location cache that is set for all drag drop objects when a drag is
21543          * initiated, cleared when the drag is finished.
21544          * @property locationCache
21545          * @private
21546          * @static
21547          */
21548         locationCache: {},
21549
21550         /**
21551          * Set useCache to false if you want to force object the lookup of each
21552          * drag and drop linked element constantly during a drag.
21553          * @property useCache
21554          * @type boolean
21555          * @static
21556          */
21557         useCache: true,
21558
21559         /**
21560          * The number of pixels that the mouse needs to move after the
21561          * mousedown before the drag is initiated.  Default=3;
21562          * @property clickPixelThresh
21563          * @type int
21564          * @static
21565          */
21566         clickPixelThresh: 3,
21567
21568         /**
21569          * The number of milliseconds after the mousedown event to initiate the
21570          * drag if we don't get a mouseup event. Default=1000
21571          * @property clickTimeThresh
21572          * @type int
21573          * @static
21574          */
21575         clickTimeThresh: 350,
21576
21577         /**
21578          * Flag that indicates that either the drag pixel threshold or the
21579          * mousdown time threshold has been met
21580          * @property dragThreshMet
21581          * @type boolean
21582          * @private
21583          * @static
21584          */
21585         dragThreshMet: false,
21586
21587         /**
21588          * Timeout used for the click time threshold
21589          * @property clickTimeout
21590          * @type Object
21591          * @private
21592          * @static
21593          */
21594         clickTimeout: null,
21595
21596         /**
21597          * The X position of the mousedown event stored for later use when a
21598          * drag threshold is met.
21599          * @property startX
21600          * @type int
21601          * @private
21602          * @static
21603          */
21604         startX: 0,
21605
21606         /**
21607          * The Y position of the mousedown event stored for later use when a
21608          * drag threshold is met.
21609          * @property startY
21610          * @type int
21611          * @private
21612          * @static
21613          */
21614         startY: 0,
21615
21616         /**
21617          * Each DragDrop instance must be registered with the DragDropMgr.
21618          * This is executed in DragDrop.init()
21619          * @method regDragDrop
21620          * @param {DragDrop} oDD the DragDrop object to register
21621          * @param {String} sGroup the name of the group this element belongs to
21622          * @static
21623          */
21624         regDragDrop: function(oDD, sGroup) {
21625             if (!this.initialized) { this.init(); }
21626
21627             if (!this.ids[sGroup]) {
21628                 this.ids[sGroup] = {};
21629             }
21630             this.ids[sGroup][oDD.id] = oDD;
21631         },
21632
21633         /**
21634          * Removes the supplied dd instance from the supplied group. Executed
21635          * by DragDrop.removeFromGroup, so don't call this function directly.
21636          * @method removeDDFromGroup
21637          * @private
21638          * @static
21639          */
21640         removeDDFromGroup: function(oDD, sGroup) {
21641             if (!this.ids[sGroup]) {
21642                 this.ids[sGroup] = {};
21643             }
21644
21645             var obj = this.ids[sGroup];
21646             if (obj && obj[oDD.id]) {
21647                 delete obj[oDD.id];
21648             }
21649         },
21650
21651         /**
21652          * Unregisters a drag and drop item.  This is executed in
21653          * DragDrop.unreg, use that method instead of calling this directly.
21654          * @method _remove
21655          * @private
21656          * @static
21657          */
21658         _remove: function(oDD) {
21659             for (var g in oDD.groups) {
21660                 if (g && this.ids[g][oDD.id]) {
21661                     delete this.ids[g][oDD.id];
21662                 }
21663             }
21664             delete this.handleIds[oDD.id];
21665         },
21666
21667         /**
21668          * Each DragDrop handle element must be registered.  This is done
21669          * automatically when executing DragDrop.setHandleElId()
21670          * @method regHandle
21671          * @param {String} sDDId the DragDrop id this element is a handle for
21672          * @param {String} sHandleId the id of the element that is the drag
21673          * handle
21674          * @static
21675          */
21676         regHandle: function(sDDId, sHandleId) {
21677             if (!this.handleIds[sDDId]) {
21678                 this.handleIds[sDDId] = {};
21679             }
21680             this.handleIds[sDDId][sHandleId] = sHandleId;
21681         },
21682
21683         /**
21684          * Utility function to determine if a given element has been
21685          * registered as a drag drop item.
21686          * @method isDragDrop
21687          * @param {String} id the element id to check
21688          * @return {boolean} true if this element is a DragDrop item,
21689          * false otherwise
21690          * @static
21691          */
21692         isDragDrop: function(id) {
21693             return ( this.getDDById(id) ) ? true : false;
21694         },
21695
21696         /**
21697          * Returns the drag and drop instances that are in all groups the
21698          * passed in instance belongs to.
21699          * @method getRelated
21700          * @param {DragDrop} p_oDD the obj to get related data for
21701          * @param {boolean} bTargetsOnly if true, only return targetable objs
21702          * @return {DragDrop[]} the related instances
21703          * @static
21704          */
21705         getRelated: function(p_oDD, bTargetsOnly) {
21706             var oDDs = [];
21707             for (var i in p_oDD.groups) {
21708                 for (j in this.ids[i]) {
21709                     var dd = this.ids[i][j];
21710                     if (! this.isTypeOfDD(dd)) {
21711                         continue;
21712                     }
21713                     if (!bTargetsOnly || dd.isTarget) {
21714                         oDDs[oDDs.length] = dd;
21715                     }
21716                 }
21717             }
21718
21719             return oDDs;
21720         },
21721
21722         /**
21723          * Returns true if the specified dd target is a legal target for
21724          * the specifice drag obj
21725          * @method isLegalTarget
21726          * @param {DragDrop} the drag obj
21727          * @param {DragDrop} the target
21728          * @return {boolean} true if the target is a legal target for the
21729          * dd obj
21730          * @static
21731          */
21732         isLegalTarget: function (oDD, oTargetDD) {
21733             var targets = this.getRelated(oDD, true);
21734             for (var i=0, len=targets.length;i<len;++i) {
21735                 if (targets[i].id == oTargetDD.id) {
21736                     return true;
21737                 }
21738             }
21739
21740             return false;
21741         },
21742
21743         /**
21744          * My goal is to be able to transparently determine if an object is
21745          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21746          * returns "object", oDD.constructor.toString() always returns
21747          * "DragDrop" and not the name of the subclass.  So for now it just
21748          * evaluates a well-known variable in DragDrop.
21749          * @method isTypeOfDD
21750          * @param {Object} the object to evaluate
21751          * @return {boolean} true if typeof oDD = DragDrop
21752          * @static
21753          */
21754         isTypeOfDD: function (oDD) {
21755             return (oDD && oDD.__ygDragDrop);
21756         },
21757
21758         /**
21759          * Utility function to determine if a given element has been
21760          * registered as a drag drop handle for the given Drag Drop object.
21761          * @method isHandle
21762          * @param {String} id the element id to check
21763          * @return {boolean} true if this element is a DragDrop handle, false
21764          * otherwise
21765          * @static
21766          */
21767         isHandle: function(sDDId, sHandleId) {
21768             return ( this.handleIds[sDDId] &&
21769                             this.handleIds[sDDId][sHandleId] );
21770         },
21771
21772         /**
21773          * Returns the DragDrop instance for a given id
21774          * @method getDDById
21775          * @param {String} id the id of the DragDrop object
21776          * @return {DragDrop} the drag drop object, null if it is not found
21777          * @static
21778          */
21779         getDDById: function(id) {
21780             for (var i in this.ids) {
21781                 if (this.ids[i][id]) {
21782                     return this.ids[i][id];
21783                 }
21784             }
21785             return null;
21786         },
21787
21788         /**
21789          * Fired after a registered DragDrop object gets the mousedown event.
21790          * Sets up the events required to track the object being dragged
21791          * @method handleMouseDown
21792          * @param {Event} e the event
21793          * @param oDD the DragDrop object being dragged
21794          * @private
21795          * @static
21796          */
21797         handleMouseDown: function(e, oDD) {
21798             if(Roo.QuickTips){
21799                 Roo.QuickTips.disable();
21800             }
21801             this.currentTarget = e.getTarget();
21802
21803             this.dragCurrent = oDD;
21804
21805             var el = oDD.getEl();
21806
21807             // track start position
21808             this.startX = e.getPageX();
21809             this.startY = e.getPageY();
21810
21811             this.deltaX = this.startX - el.offsetLeft;
21812             this.deltaY = this.startY - el.offsetTop;
21813
21814             this.dragThreshMet = false;
21815
21816             this.clickTimeout = setTimeout(
21817                     function() {
21818                         var DDM = Roo.dd.DDM;
21819                         DDM.startDrag(DDM.startX, DDM.startY);
21820                     },
21821                     this.clickTimeThresh );
21822         },
21823
21824         /**
21825          * Fired when either the drag pixel threshol or the mousedown hold
21826          * time threshold has been met.
21827          * @method startDrag
21828          * @param x {int} the X position of the original mousedown
21829          * @param y {int} the Y position of the original mousedown
21830          * @static
21831          */
21832         startDrag: function(x, y) {
21833             clearTimeout(this.clickTimeout);
21834             if (this.dragCurrent) {
21835                 this.dragCurrent.b4StartDrag(x, y);
21836                 this.dragCurrent.startDrag(x, y);
21837             }
21838             this.dragThreshMet = true;
21839         },
21840
21841         /**
21842          * Internal function to handle the mouseup event.  Will be invoked
21843          * from the context of the document.
21844          * @method handleMouseUp
21845          * @param {Event} e the event
21846          * @private
21847          * @static
21848          */
21849         handleMouseUp: function(e) {
21850
21851             if(Roo.QuickTips){
21852                 Roo.QuickTips.enable();
21853             }
21854             if (! this.dragCurrent) {
21855                 return;
21856             }
21857
21858             clearTimeout(this.clickTimeout);
21859
21860             if (this.dragThreshMet) {
21861                 this.fireEvents(e, true);
21862             } else {
21863             }
21864
21865             this.stopDrag(e);
21866
21867             this.stopEvent(e);
21868         },
21869
21870         /**
21871          * Utility to stop event propagation and event default, if these
21872          * features are turned on.
21873          * @method stopEvent
21874          * @param {Event} e the event as returned by this.getEvent()
21875          * @static
21876          */
21877         stopEvent: function(e){
21878             if(this.stopPropagation) {
21879                 e.stopPropagation();
21880             }
21881
21882             if (this.preventDefault) {
21883                 e.preventDefault();
21884             }
21885         },
21886
21887         /**
21888          * Internal function to clean up event handlers after the drag
21889          * operation is complete
21890          * @method stopDrag
21891          * @param {Event} e the event
21892          * @private
21893          * @static
21894          */
21895         stopDrag: function(e) {
21896             // Fire the drag end event for the item that was dragged
21897             if (this.dragCurrent) {
21898                 if (this.dragThreshMet) {
21899                     this.dragCurrent.b4EndDrag(e);
21900                     this.dragCurrent.endDrag(e);
21901                 }
21902
21903                 this.dragCurrent.onMouseUp(e);
21904             }
21905
21906             this.dragCurrent = null;
21907             this.dragOvers = {};
21908         },
21909
21910         /**
21911          * Internal function to handle the mousemove event.  Will be invoked
21912          * from the context of the html element.
21913          *
21914          * @TODO figure out what we can do about mouse events lost when the
21915          * user drags objects beyond the window boundary.  Currently we can
21916          * detect this in internet explorer by verifying that the mouse is
21917          * down during the mousemove event.  Firefox doesn't give us the
21918          * button state on the mousemove event.
21919          * @method handleMouseMove
21920          * @param {Event} e the event
21921          * @private
21922          * @static
21923          */
21924         handleMouseMove: function(e) {
21925             if (! this.dragCurrent) {
21926                 return true;
21927             }
21928
21929             // var button = e.which || e.button;
21930
21931             // check for IE mouseup outside of page boundary
21932             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21933                 this.stopEvent(e);
21934                 return this.handleMouseUp(e);
21935             }
21936
21937             if (!this.dragThreshMet) {
21938                 var diffX = Math.abs(this.startX - e.getPageX());
21939                 var diffY = Math.abs(this.startY - e.getPageY());
21940                 if (diffX > this.clickPixelThresh ||
21941                             diffY > this.clickPixelThresh) {
21942                     this.startDrag(this.startX, this.startY);
21943                 }
21944             }
21945
21946             if (this.dragThreshMet) {
21947                 this.dragCurrent.b4Drag(e);
21948                 this.dragCurrent.onDrag(e);
21949                 if(!this.dragCurrent.moveOnly){
21950                     this.fireEvents(e, false);
21951                 }
21952             }
21953
21954             this.stopEvent(e);
21955
21956             return true;
21957         },
21958
21959         /**
21960          * Iterates over all of the DragDrop elements to find ones we are
21961          * hovering over or dropping on
21962          * @method fireEvents
21963          * @param {Event} e the event
21964          * @param {boolean} isDrop is this a drop op or a mouseover op?
21965          * @private
21966          * @static
21967          */
21968         fireEvents: function(e, isDrop) {
21969             var dc = this.dragCurrent;
21970
21971             // If the user did the mouse up outside of the window, we could
21972             // get here even though we have ended the drag.
21973             if (!dc || dc.isLocked()) {
21974                 return;
21975             }
21976
21977             var pt = e.getPoint();
21978
21979             // cache the previous dragOver array
21980             var oldOvers = [];
21981
21982             var outEvts   = [];
21983             var overEvts  = [];
21984             var dropEvts  = [];
21985             var enterEvts = [];
21986
21987             // Check to see if the object(s) we were hovering over is no longer
21988             // being hovered over so we can fire the onDragOut event
21989             for (var i in this.dragOvers) {
21990
21991                 var ddo = this.dragOvers[i];
21992
21993                 if (! this.isTypeOfDD(ddo)) {
21994                     continue;
21995                 }
21996
21997                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21998                     outEvts.push( ddo );
21999                 }
22000
22001                 oldOvers[i] = true;
22002                 delete this.dragOvers[i];
22003             }
22004
22005             for (var sGroup in dc.groups) {
22006
22007                 if ("string" != typeof sGroup) {
22008                     continue;
22009                 }
22010
22011                 for (i in this.ids[sGroup]) {
22012                     var oDD = this.ids[sGroup][i];
22013                     if (! this.isTypeOfDD(oDD)) {
22014                         continue;
22015                     }
22016
22017                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
22018                         if (this.isOverTarget(pt, oDD, this.mode)) {
22019                             // look for drop interactions
22020                             if (isDrop) {
22021                                 dropEvts.push( oDD );
22022                             // look for drag enter and drag over interactions
22023                             } else {
22024
22025                                 // initial drag over: dragEnter fires
22026                                 if (!oldOvers[oDD.id]) {
22027                                     enterEvts.push( oDD );
22028                                 // subsequent drag overs: dragOver fires
22029                                 } else {
22030                                     overEvts.push( oDD );
22031                                 }
22032
22033                                 this.dragOvers[oDD.id] = oDD;
22034                             }
22035                         }
22036                     }
22037                 }
22038             }
22039
22040             if (this.mode) {
22041                 if (outEvts.length) {
22042                     dc.b4DragOut(e, outEvts);
22043                     dc.onDragOut(e, outEvts);
22044                 }
22045
22046                 if (enterEvts.length) {
22047                     dc.onDragEnter(e, enterEvts);
22048                 }
22049
22050                 if (overEvts.length) {
22051                     dc.b4DragOver(e, overEvts);
22052                     dc.onDragOver(e, overEvts);
22053                 }
22054
22055                 if (dropEvts.length) {
22056                     dc.b4DragDrop(e, dropEvts);
22057                     dc.onDragDrop(e, dropEvts);
22058                 }
22059
22060             } else {
22061                 // fire dragout events
22062                 var len = 0;
22063                 for (i=0, len=outEvts.length; i<len; ++i) {
22064                     dc.b4DragOut(e, outEvts[i].id);
22065                     dc.onDragOut(e, outEvts[i].id);
22066                 }
22067
22068                 // fire enter events
22069                 for (i=0,len=enterEvts.length; i<len; ++i) {
22070                     // dc.b4DragEnter(e, oDD.id);
22071                     dc.onDragEnter(e, enterEvts[i].id);
22072                 }
22073
22074                 // fire over events
22075                 for (i=0,len=overEvts.length; i<len; ++i) {
22076                     dc.b4DragOver(e, overEvts[i].id);
22077                     dc.onDragOver(e, overEvts[i].id);
22078                 }
22079
22080                 // fire drop events
22081                 for (i=0, len=dropEvts.length; i<len; ++i) {
22082                     dc.b4DragDrop(e, dropEvts[i].id);
22083                     dc.onDragDrop(e, dropEvts[i].id);
22084                 }
22085
22086             }
22087
22088             // notify about a drop that did not find a target
22089             if (isDrop && !dropEvts.length) {
22090                 dc.onInvalidDrop(e);
22091             }
22092
22093         },
22094
22095         /**
22096          * Helper function for getting the best match from the list of drag
22097          * and drop objects returned by the drag and drop events when we are
22098          * in INTERSECT mode.  It returns either the first object that the
22099          * cursor is over, or the object that has the greatest overlap with
22100          * the dragged element.
22101          * @method getBestMatch
22102          * @param  {DragDrop[]} dds The array of drag and drop objects
22103          * targeted
22104          * @return {DragDrop}       The best single match
22105          * @static
22106          */
22107         getBestMatch: function(dds) {
22108             var winner = null;
22109             // Return null if the input is not what we expect
22110             //if (!dds || !dds.length || dds.length == 0) {
22111                // winner = null;
22112             // If there is only one item, it wins
22113             //} else if (dds.length == 1) {
22114
22115             var len = dds.length;
22116
22117             if (len == 1) {
22118                 winner = dds[0];
22119             } else {
22120                 // Loop through the targeted items
22121                 for (var i=0; i<len; ++i) {
22122                     var dd = dds[i];
22123                     // If the cursor is over the object, it wins.  If the
22124                     // cursor is over multiple matches, the first one we come
22125                     // to wins.
22126                     if (dd.cursorIsOver) {
22127                         winner = dd;
22128                         break;
22129                     // Otherwise the object with the most overlap wins
22130                     } else {
22131                         if (!winner ||
22132                             winner.overlap.getArea() < dd.overlap.getArea()) {
22133                             winner = dd;
22134                         }
22135                     }
22136                 }
22137             }
22138
22139             return winner;
22140         },
22141
22142         /**
22143          * Refreshes the cache of the top-left and bottom-right points of the
22144          * drag and drop objects in the specified group(s).  This is in the
22145          * format that is stored in the drag and drop instance, so typical
22146          * usage is:
22147          * <code>
22148          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
22149          * </code>
22150          * Alternatively:
22151          * <code>
22152          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
22153          * </code>
22154          * @TODO this really should be an indexed array.  Alternatively this
22155          * method could accept both.
22156          * @method refreshCache
22157          * @param {Object} groups an associative array of groups to refresh
22158          * @static
22159          */
22160         refreshCache: function(groups) {
22161             for (var sGroup in groups) {
22162                 if ("string" != typeof sGroup) {
22163                     continue;
22164                 }
22165                 for (var i in this.ids[sGroup]) {
22166                     var oDD = this.ids[sGroup][i];
22167
22168                     if (this.isTypeOfDD(oDD)) {
22169                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
22170                         var loc = this.getLocation(oDD);
22171                         if (loc) {
22172                             this.locationCache[oDD.id] = loc;
22173                         } else {
22174                             delete this.locationCache[oDD.id];
22175                             // this will unregister the drag and drop object if
22176                             // the element is not in a usable state
22177                             // oDD.unreg();
22178                         }
22179                     }
22180                 }
22181             }
22182         },
22183
22184         /**
22185          * This checks to make sure an element exists and is in the DOM.  The
22186          * main purpose is to handle cases where innerHTML is used to remove
22187          * drag and drop objects from the DOM.  IE provides an 'unspecified
22188          * error' when trying to access the offsetParent of such an element
22189          * @method verifyEl
22190          * @param {HTMLElement} el the element to check
22191          * @return {boolean} true if the element looks usable
22192          * @static
22193          */
22194         verifyEl: function(el) {
22195             if (el) {
22196                 var parent;
22197                 if(Roo.isIE){
22198                     try{
22199                         parent = el.offsetParent;
22200                     }catch(e){}
22201                 }else{
22202                     parent = el.offsetParent;
22203                 }
22204                 if (parent) {
22205                     return true;
22206                 }
22207             }
22208
22209             return false;
22210         },
22211
22212         /**
22213          * Returns a Region object containing the drag and drop element's position
22214          * and size, including the padding configured for it
22215          * @method getLocation
22216          * @param {DragDrop} oDD the drag and drop object to get the
22217          *                       location for
22218          * @return {Roo.lib.Region} a Region object representing the total area
22219          *                             the element occupies, including any padding
22220          *                             the instance is configured for.
22221          * @static
22222          */
22223         getLocation: function(oDD) {
22224             if (! this.isTypeOfDD(oDD)) {
22225                 return null;
22226             }
22227
22228             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22229
22230             try {
22231                 pos= Roo.lib.Dom.getXY(el);
22232             } catch (e) { }
22233
22234             if (!pos) {
22235                 return null;
22236             }
22237
22238             x1 = pos[0];
22239             x2 = x1 + el.offsetWidth;
22240             y1 = pos[1];
22241             y2 = y1 + el.offsetHeight;
22242
22243             t = y1 - oDD.padding[0];
22244             r = x2 + oDD.padding[1];
22245             b = y2 + oDD.padding[2];
22246             l = x1 - oDD.padding[3];
22247
22248             return new Roo.lib.Region( t, r, b, l );
22249         },
22250
22251         /**
22252          * Checks the cursor location to see if it over the target
22253          * @method isOverTarget
22254          * @param {Roo.lib.Point} pt The point to evaluate
22255          * @param {DragDrop} oTarget the DragDrop object we are inspecting
22256          * @return {boolean} true if the mouse is over the target
22257          * @private
22258          * @static
22259          */
22260         isOverTarget: function(pt, oTarget, intersect) {
22261             // use cache if available
22262             var loc = this.locationCache[oTarget.id];
22263             if (!loc || !this.useCache) {
22264                 loc = this.getLocation(oTarget);
22265                 this.locationCache[oTarget.id] = loc;
22266
22267             }
22268
22269             if (!loc) {
22270                 return false;
22271             }
22272
22273             oTarget.cursorIsOver = loc.contains( pt );
22274
22275             // DragDrop is using this as a sanity check for the initial mousedown
22276             // in this case we are done.  In POINT mode, if the drag obj has no
22277             // contraints, we are also done. Otherwise we need to evaluate the
22278             // location of the target as related to the actual location of the
22279             // dragged element.
22280             var dc = this.dragCurrent;
22281             if (!dc || !dc.getTargetCoord ||
22282                     (!intersect && !dc.constrainX && !dc.constrainY)) {
22283                 return oTarget.cursorIsOver;
22284             }
22285
22286             oTarget.overlap = null;
22287
22288             // Get the current location of the drag element, this is the
22289             // location of the mouse event less the delta that represents
22290             // where the original mousedown happened on the element.  We
22291             // need to consider constraints and ticks as well.
22292             var pos = dc.getTargetCoord(pt.x, pt.y);
22293
22294             var el = dc.getDragEl();
22295             var curRegion = new Roo.lib.Region( pos.y,
22296                                                    pos.x + el.offsetWidth,
22297                                                    pos.y + el.offsetHeight,
22298                                                    pos.x );
22299
22300             var overlap = curRegion.intersect(loc);
22301
22302             if (overlap) {
22303                 oTarget.overlap = overlap;
22304                 return (intersect) ? true : oTarget.cursorIsOver;
22305             } else {
22306                 return false;
22307             }
22308         },
22309
22310         /**
22311          * unload event handler
22312          * @method _onUnload
22313          * @private
22314          * @static
22315          */
22316         _onUnload: function(e, me) {
22317             Roo.dd.DragDropMgr.unregAll();
22318         },
22319
22320         /**
22321          * Cleans up the drag and drop events and objects.
22322          * @method unregAll
22323          * @private
22324          * @static
22325          */
22326         unregAll: function() {
22327
22328             if (this.dragCurrent) {
22329                 this.stopDrag();
22330                 this.dragCurrent = null;
22331             }
22332
22333             this._execOnAll("unreg", []);
22334
22335             for (i in this.elementCache) {
22336                 delete this.elementCache[i];
22337             }
22338
22339             this.elementCache = {};
22340             this.ids = {};
22341         },
22342
22343         /**
22344          * A cache of DOM elements
22345          * @property elementCache
22346          * @private
22347          * @static
22348          */
22349         elementCache: {},
22350
22351         /**
22352          * Get the wrapper for the DOM element specified
22353          * @method getElWrapper
22354          * @param {String} id the id of the element to get
22355          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22356          * @private
22357          * @deprecated This wrapper isn't that useful
22358          * @static
22359          */
22360         getElWrapper: function(id) {
22361             var oWrapper = this.elementCache[id];
22362             if (!oWrapper || !oWrapper.el) {
22363                 oWrapper = this.elementCache[id] =
22364                     new this.ElementWrapper(Roo.getDom(id));
22365             }
22366             return oWrapper;
22367         },
22368
22369         /**
22370          * Returns the actual DOM element
22371          * @method getElement
22372          * @param {String} id the id of the elment to get
22373          * @return {Object} The element
22374          * @deprecated use Roo.getDom instead
22375          * @static
22376          */
22377         getElement: function(id) {
22378             return Roo.getDom(id);
22379         },
22380
22381         /**
22382          * Returns the style property for the DOM element (i.e.,
22383          * document.getElById(id).style)
22384          * @method getCss
22385          * @param {String} id the id of the elment to get
22386          * @return {Object} The style property of the element
22387          * @deprecated use Roo.getDom instead
22388          * @static
22389          */
22390         getCss: function(id) {
22391             var el = Roo.getDom(id);
22392             return (el) ? el.style : null;
22393         },
22394
22395         /**
22396          * Inner class for cached elements
22397          * @class DragDropMgr.ElementWrapper
22398          * @for DragDropMgr
22399          * @private
22400          * @deprecated
22401          */
22402         ElementWrapper: function(el) {
22403                 /**
22404                  * The element
22405                  * @property el
22406                  */
22407                 this.el = el || null;
22408                 /**
22409                  * The element id
22410                  * @property id
22411                  */
22412                 this.id = this.el && el.id;
22413                 /**
22414                  * A reference to the style property
22415                  * @property css
22416                  */
22417                 this.css = this.el && el.style;
22418             },
22419
22420         /**
22421          * Returns the X position of an html element
22422          * @method getPosX
22423          * @param el the element for which to get the position
22424          * @return {int} the X coordinate
22425          * @for DragDropMgr
22426          * @deprecated use Roo.lib.Dom.getX instead
22427          * @static
22428          */
22429         getPosX: function(el) {
22430             return Roo.lib.Dom.getX(el);
22431         },
22432
22433         /**
22434          * Returns the Y position of an html element
22435          * @method getPosY
22436          * @param el the element for which to get the position
22437          * @return {int} the Y coordinate
22438          * @deprecated use Roo.lib.Dom.getY instead
22439          * @static
22440          */
22441         getPosY: function(el) {
22442             return Roo.lib.Dom.getY(el);
22443         },
22444
22445         /**
22446          * Swap two nodes.  In IE, we use the native method, for others we
22447          * emulate the IE behavior
22448          * @method swapNode
22449          * @param n1 the first node to swap
22450          * @param n2 the other node to swap
22451          * @static
22452          */
22453         swapNode: function(n1, n2) {
22454             if (n1.swapNode) {
22455                 n1.swapNode(n2);
22456             } else {
22457                 var p = n2.parentNode;
22458                 var s = n2.nextSibling;
22459
22460                 if (s == n1) {
22461                     p.insertBefore(n1, n2);
22462                 } else if (n2 == n1.nextSibling) {
22463                     p.insertBefore(n2, n1);
22464                 } else {
22465                     n1.parentNode.replaceChild(n2, n1);
22466                     p.insertBefore(n1, s);
22467                 }
22468             }
22469         },
22470
22471         /**
22472          * Returns the current scroll position
22473          * @method getScroll
22474          * @private
22475          * @static
22476          */
22477         getScroll: function () {
22478             var t, l, dde=document.documentElement, db=document.body;
22479             if (dde && (dde.scrollTop || dde.scrollLeft)) {
22480                 t = dde.scrollTop;
22481                 l = dde.scrollLeft;
22482             } else if (db) {
22483                 t = db.scrollTop;
22484                 l = db.scrollLeft;
22485             } else {
22486
22487             }
22488             return { top: t, left: l };
22489         },
22490
22491         /**
22492          * Returns the specified element style property
22493          * @method getStyle
22494          * @param {HTMLElement} el          the element
22495          * @param {string}      styleProp   the style property
22496          * @return {string} The value of the style property
22497          * @deprecated use Roo.lib.Dom.getStyle
22498          * @static
22499          */
22500         getStyle: function(el, styleProp) {
22501             return Roo.fly(el).getStyle(styleProp);
22502         },
22503
22504         /**
22505          * Gets the scrollTop
22506          * @method getScrollTop
22507          * @return {int} the document's scrollTop
22508          * @static
22509          */
22510         getScrollTop: function () { return this.getScroll().top; },
22511
22512         /**
22513          * Gets the scrollLeft
22514          * @method getScrollLeft
22515          * @return {int} the document's scrollTop
22516          * @static
22517          */
22518         getScrollLeft: function () { return this.getScroll().left; },
22519
22520         /**
22521          * Sets the x/y position of an element to the location of the
22522          * target element.
22523          * @method moveToEl
22524          * @param {HTMLElement} moveEl      The element to move
22525          * @param {HTMLElement} targetEl    The position reference element
22526          * @static
22527          */
22528         moveToEl: function (moveEl, targetEl) {
22529             var aCoord = Roo.lib.Dom.getXY(targetEl);
22530             Roo.lib.Dom.setXY(moveEl, aCoord);
22531         },
22532
22533         /**
22534          * Numeric array sort function
22535          * @method numericSort
22536          * @static
22537          */
22538         numericSort: function(a, b) { return (a - b); },
22539
22540         /**
22541          * Internal counter
22542          * @property _timeoutCount
22543          * @private
22544          * @static
22545          */
22546         _timeoutCount: 0,
22547
22548         /**
22549          * Trying to make the load order less important.  Without this we get
22550          * an error if this file is loaded before the Event Utility.
22551          * @method _addListeners
22552          * @private
22553          * @static
22554          */
22555         _addListeners: function() {
22556             var DDM = Roo.dd.DDM;
22557             if ( Roo.lib.Event && document ) {
22558                 DDM._onLoad();
22559             } else {
22560                 if (DDM._timeoutCount > 2000) {
22561                 } else {
22562                     setTimeout(DDM._addListeners, 10);
22563                     if (document && document.body) {
22564                         DDM._timeoutCount += 1;
22565                     }
22566                 }
22567             }
22568         },
22569
22570         /**
22571          * Recursively searches the immediate parent and all child nodes for
22572          * the handle element in order to determine wheter or not it was
22573          * clicked.
22574          * @method handleWasClicked
22575          * @param node the html element to inspect
22576          * @static
22577          */
22578         handleWasClicked: function(node, id) {
22579             if (this.isHandle(id, node.id)) {
22580                 return true;
22581             } else {
22582                 // check to see if this is a text node child of the one we want
22583                 var p = node.parentNode;
22584
22585                 while (p) {
22586                     if (this.isHandle(id, p.id)) {
22587                         return true;
22588                     } else {
22589                         p = p.parentNode;
22590                     }
22591                 }
22592             }
22593
22594             return false;
22595         }
22596
22597     };
22598
22599 }();
22600
22601 // shorter alias, save a few bytes
22602 Roo.dd.DDM = Roo.dd.DragDropMgr;
22603 Roo.dd.DDM._addListeners();
22604
22605 }/*
22606  * Based on:
22607  * Ext JS Library 1.1.1
22608  * Copyright(c) 2006-2007, Ext JS, LLC.
22609  *
22610  * Originally Released Under LGPL - original licence link has changed is not relivant.
22611  *
22612  * Fork - LGPL
22613  * <script type="text/javascript">
22614  */
22615
22616 /**
22617  * @class Roo.dd.DD
22618  * A DragDrop implementation where the linked element follows the
22619  * mouse cursor during a drag.
22620  * @extends Roo.dd.DragDrop
22621  * @constructor
22622  * @param {String} id the id of the linked element
22623  * @param {String} sGroup the group of related DragDrop items
22624  * @param {object} config an object containing configurable attributes
22625  *                Valid properties for DD:
22626  *                    scroll
22627  */
22628 Roo.dd.DD = function(id, sGroup, config) {
22629     if (id) {
22630         this.init(id, sGroup, config);
22631     }
22632 };
22633
22634 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22635
22636     /**
22637      * When set to true, the utility automatically tries to scroll the browser
22638      * window wehn a drag and drop element is dragged near the viewport boundary.
22639      * Defaults to true.
22640      * @property scroll
22641      * @type boolean
22642      */
22643     scroll: true,
22644
22645     /**
22646      * Sets the pointer offset to the distance between the linked element's top
22647      * left corner and the location the element was clicked
22648      * @method autoOffset
22649      * @param {int} iPageX the X coordinate of the click
22650      * @param {int} iPageY the Y coordinate of the click
22651      */
22652     autoOffset: function(iPageX, iPageY) {
22653         var x = iPageX - this.startPageX;
22654         var y = iPageY - this.startPageY;
22655         this.setDelta(x, y);
22656     },
22657
22658     /**
22659      * Sets the pointer offset.  You can call this directly to force the
22660      * offset to be in a particular location (e.g., pass in 0,0 to set it
22661      * to the center of the object)
22662      * @method setDelta
22663      * @param {int} iDeltaX the distance from the left
22664      * @param {int} iDeltaY the distance from the top
22665      */
22666     setDelta: function(iDeltaX, iDeltaY) {
22667         this.deltaX = iDeltaX;
22668         this.deltaY = iDeltaY;
22669     },
22670
22671     /**
22672      * Sets the drag element to the location of the mousedown or click event,
22673      * maintaining the cursor location relative to the location on the element
22674      * that was clicked.  Override this if you want to place the element in a
22675      * location other than where the cursor is.
22676      * @method setDragElPos
22677      * @param {int} iPageX the X coordinate of the mousedown or drag event
22678      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22679      */
22680     setDragElPos: function(iPageX, iPageY) {
22681         // the first time we do this, we are going to check to make sure
22682         // the element has css positioning
22683
22684         var el = this.getDragEl();
22685         this.alignElWithMouse(el, iPageX, iPageY);
22686     },
22687
22688     /**
22689      * Sets the element to the location of the mousedown or click event,
22690      * maintaining the cursor location relative to the location on the element
22691      * that was clicked.  Override this if you want to place the element in a
22692      * location other than where the cursor is.
22693      * @method alignElWithMouse
22694      * @param {HTMLElement} el the element to move
22695      * @param {int} iPageX the X coordinate of the mousedown or drag event
22696      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22697      */
22698     alignElWithMouse: function(el, iPageX, iPageY) {
22699         var oCoord = this.getTargetCoord(iPageX, iPageY);
22700         var fly = el.dom ? el : Roo.fly(el);
22701         if (!this.deltaSetXY) {
22702             var aCoord = [oCoord.x, oCoord.y];
22703             fly.setXY(aCoord);
22704             var newLeft = fly.getLeft(true);
22705             var newTop  = fly.getTop(true);
22706             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22707         } else {
22708             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22709         }
22710
22711         this.cachePosition(oCoord.x, oCoord.y);
22712         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22713         return oCoord;
22714     },
22715
22716     /**
22717      * Saves the most recent position so that we can reset the constraints and
22718      * tick marks on-demand.  We need to know this so that we can calculate the
22719      * number of pixels the element is offset from its original position.
22720      * @method cachePosition
22721      * @param iPageX the current x position (optional, this just makes it so we
22722      * don't have to look it up again)
22723      * @param iPageY the current y position (optional, this just makes it so we
22724      * don't have to look it up again)
22725      */
22726     cachePosition: function(iPageX, iPageY) {
22727         if (iPageX) {
22728             this.lastPageX = iPageX;
22729             this.lastPageY = iPageY;
22730         } else {
22731             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22732             this.lastPageX = aCoord[0];
22733             this.lastPageY = aCoord[1];
22734         }
22735     },
22736
22737     /**
22738      * Auto-scroll the window if the dragged object has been moved beyond the
22739      * visible window boundary.
22740      * @method autoScroll
22741      * @param {int} x the drag element's x position
22742      * @param {int} y the drag element's y position
22743      * @param {int} h the height of the drag element
22744      * @param {int} w the width of the drag element
22745      * @private
22746      */
22747     autoScroll: function(x, y, h, w) {
22748
22749         if (this.scroll) {
22750             // The client height
22751             var clientH = Roo.lib.Dom.getViewWidth();
22752
22753             // The client width
22754             var clientW = Roo.lib.Dom.getViewHeight();
22755
22756             // The amt scrolled down
22757             var st = this.DDM.getScrollTop();
22758
22759             // The amt scrolled right
22760             var sl = this.DDM.getScrollLeft();
22761
22762             // Location of the bottom of the element
22763             var bot = h + y;
22764
22765             // Location of the right of the element
22766             var right = w + x;
22767
22768             // The distance from the cursor to the bottom of the visible area,
22769             // adjusted so that we don't scroll if the cursor is beyond the
22770             // element drag constraints
22771             var toBot = (clientH + st - y - this.deltaY);
22772
22773             // The distance from the cursor to the right of the visible area
22774             var toRight = (clientW + sl - x - this.deltaX);
22775
22776
22777             // How close to the edge the cursor must be before we scroll
22778             // var thresh = (document.all) ? 100 : 40;
22779             var thresh = 40;
22780
22781             // How many pixels to scroll per autoscroll op.  This helps to reduce
22782             // clunky scrolling. IE is more sensitive about this ... it needs this
22783             // value to be higher.
22784             var scrAmt = (document.all) ? 80 : 30;
22785
22786             // Scroll down if we are near the bottom of the visible page and the
22787             // obj extends below the crease
22788             if ( bot > clientH && toBot < thresh ) {
22789                 window.scrollTo(sl, st + scrAmt);
22790             }
22791
22792             // Scroll up if the window is scrolled down and the top of the object
22793             // goes above the top border
22794             if ( y < st && st > 0 && y - st < thresh ) {
22795                 window.scrollTo(sl, st - scrAmt);
22796             }
22797
22798             // Scroll right if the obj is beyond the right border and the cursor is
22799             // near the border.
22800             if ( right > clientW && toRight < thresh ) {
22801                 window.scrollTo(sl + scrAmt, st);
22802             }
22803
22804             // Scroll left if the window has been scrolled to the right and the obj
22805             // extends past the left border
22806             if ( x < sl && sl > 0 && x - sl < thresh ) {
22807                 window.scrollTo(sl - scrAmt, st);
22808             }
22809         }
22810     },
22811
22812     /**
22813      * Finds the location the element should be placed if we want to move
22814      * it to where the mouse location less the click offset would place us.
22815      * @method getTargetCoord
22816      * @param {int} iPageX the X coordinate of the click
22817      * @param {int} iPageY the Y coordinate of the click
22818      * @return an object that contains the coordinates (Object.x and Object.y)
22819      * @private
22820      */
22821     getTargetCoord: function(iPageX, iPageY) {
22822
22823
22824         var x = iPageX - this.deltaX;
22825         var y = iPageY - this.deltaY;
22826
22827         if (this.constrainX) {
22828             if (x < this.minX) { x = this.minX; }
22829             if (x > this.maxX) { x = this.maxX; }
22830         }
22831
22832         if (this.constrainY) {
22833             if (y < this.minY) { y = this.minY; }
22834             if (y > this.maxY) { y = this.maxY; }
22835         }
22836
22837         x = this.getTick(x, this.xTicks);
22838         y = this.getTick(y, this.yTicks);
22839
22840
22841         return {x:x, y:y};
22842     },
22843
22844     /*
22845      * Sets up config options specific to this class. Overrides
22846      * Roo.dd.DragDrop, but all versions of this method through the
22847      * inheritance chain are called
22848      */
22849     applyConfig: function() {
22850         Roo.dd.DD.superclass.applyConfig.call(this);
22851         this.scroll = (this.config.scroll !== false);
22852     },
22853
22854     /*
22855      * Event that fires prior to the onMouseDown event.  Overrides
22856      * Roo.dd.DragDrop.
22857      */
22858     b4MouseDown: function(e) {
22859         // this.resetConstraints();
22860         this.autoOffset(e.getPageX(),
22861                             e.getPageY());
22862     },
22863
22864     /*
22865      * Event that fires prior to the onDrag event.  Overrides
22866      * Roo.dd.DragDrop.
22867      */
22868     b4Drag: function(e) {
22869         this.setDragElPos(e.getPageX(),
22870                             e.getPageY());
22871     },
22872
22873     toString: function() {
22874         return ("DD " + this.id);
22875     }
22876
22877     //////////////////////////////////////////////////////////////////////////
22878     // Debugging ygDragDrop events that can be overridden
22879     //////////////////////////////////////////////////////////////////////////
22880     /*
22881     startDrag: function(x, y) {
22882     },
22883
22884     onDrag: function(e) {
22885     },
22886
22887     onDragEnter: function(e, id) {
22888     },
22889
22890     onDragOver: function(e, id) {
22891     },
22892
22893     onDragOut: function(e, id) {
22894     },
22895
22896     onDragDrop: function(e, id) {
22897     },
22898
22899     endDrag: function(e) {
22900     }
22901
22902     */
22903
22904 });/*
22905  * Based on:
22906  * Ext JS Library 1.1.1
22907  * Copyright(c) 2006-2007, Ext JS, LLC.
22908  *
22909  * Originally Released Under LGPL - original licence link has changed is not relivant.
22910  *
22911  * Fork - LGPL
22912  * <script type="text/javascript">
22913  */
22914
22915 /**
22916  * @class Roo.dd.DDProxy
22917  * A DragDrop implementation that inserts an empty, bordered div into
22918  * the document that follows the cursor during drag operations.  At the time of
22919  * the click, the frame div is resized to the dimensions of the linked html
22920  * element, and moved to the exact location of the linked element.
22921  *
22922  * References to the "frame" element refer to the single proxy element that
22923  * was created to be dragged in place of all DDProxy elements on the
22924  * page.
22925  *
22926  * @extends Roo.dd.DD
22927  * @constructor
22928  * @param {String} id the id of the linked html element
22929  * @param {String} sGroup the group of related DragDrop objects
22930  * @param {object} config an object containing configurable attributes
22931  *                Valid properties for DDProxy in addition to those in DragDrop:
22932  *                   resizeFrame, centerFrame, dragElId
22933  */
22934 Roo.dd.DDProxy = function(id, sGroup, config) {
22935     if (id) {
22936         this.init(id, sGroup, config);
22937         this.initFrame();
22938     }
22939 };
22940
22941 /**
22942  * The default drag frame div id
22943  * @property Roo.dd.DDProxy.dragElId
22944  * @type String
22945  * @static
22946  */
22947 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22948
22949 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22950
22951     /**
22952      * By default we resize the drag frame to be the same size as the element
22953      * we want to drag (this is to get the frame effect).  We can turn it off
22954      * if we want a different behavior.
22955      * @property resizeFrame
22956      * @type boolean
22957      */
22958     resizeFrame: true,
22959
22960     /**
22961      * By default the frame is positioned exactly where the drag element is, so
22962      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22963      * you do not have constraints on the obj is to have the drag frame centered
22964      * around the cursor.  Set centerFrame to true for this effect.
22965      * @property centerFrame
22966      * @type boolean
22967      */
22968     centerFrame: false,
22969
22970     /**
22971      * Creates the proxy element if it does not yet exist
22972      * @method createFrame
22973      */
22974     createFrame: function() {
22975         var self = this;
22976         var body = document.body;
22977
22978         if (!body || !body.firstChild) {
22979             setTimeout( function() { self.createFrame(); }, 50 );
22980             return;
22981         }
22982
22983         var div = this.getDragEl();
22984
22985         if (!div) {
22986             div    = document.createElement("div");
22987             div.id = this.dragElId;
22988             var s  = div.style;
22989
22990             s.position   = "absolute";
22991             s.visibility = "hidden";
22992             s.cursor     = "move";
22993             s.border     = "2px solid #aaa";
22994             s.zIndex     = 999;
22995
22996             // appendChild can blow up IE if invoked prior to the window load event
22997             // while rendering a table.  It is possible there are other scenarios
22998             // that would cause this to happen as well.
22999             body.insertBefore(div, body.firstChild);
23000         }
23001     },
23002
23003     /**
23004      * Initialization for the drag frame element.  Must be called in the
23005      * constructor of all subclasses
23006      * @method initFrame
23007      */
23008     initFrame: function() {
23009         this.createFrame();
23010     },
23011
23012     applyConfig: function() {
23013         Roo.dd.DDProxy.superclass.applyConfig.call(this);
23014
23015         this.resizeFrame = (this.config.resizeFrame !== false);
23016         this.centerFrame = (this.config.centerFrame);
23017         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
23018     },
23019
23020     /**
23021      * Resizes the drag frame to the dimensions of the clicked object, positions
23022      * it over the object, and finally displays it
23023      * @method showFrame
23024      * @param {int} iPageX X click position
23025      * @param {int} iPageY Y click position
23026      * @private
23027      */
23028     showFrame: function(iPageX, iPageY) {
23029         var el = this.getEl();
23030         var dragEl = this.getDragEl();
23031         var s = dragEl.style;
23032
23033         this._resizeProxy();
23034
23035         if (this.centerFrame) {
23036             this.setDelta( Math.round(parseInt(s.width,  10)/2),
23037                            Math.round(parseInt(s.height, 10)/2) );
23038         }
23039
23040         this.setDragElPos(iPageX, iPageY);
23041
23042         Roo.fly(dragEl).show();
23043     },
23044
23045     /**
23046      * The proxy is automatically resized to the dimensions of the linked
23047      * element when a drag is initiated, unless resizeFrame is set to false
23048      * @method _resizeProxy
23049      * @private
23050      */
23051     _resizeProxy: function() {
23052         if (this.resizeFrame) {
23053             var el = this.getEl();
23054             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
23055         }
23056     },
23057
23058     // overrides Roo.dd.DragDrop
23059     b4MouseDown: function(e) {
23060         var x = e.getPageX();
23061         var y = e.getPageY();
23062         this.autoOffset(x, y);
23063         this.setDragElPos(x, y);
23064     },
23065
23066     // overrides Roo.dd.DragDrop
23067     b4StartDrag: function(x, y) {
23068         // show the drag frame
23069         this.showFrame(x, y);
23070     },
23071
23072     // overrides Roo.dd.DragDrop
23073     b4EndDrag: function(e) {
23074         Roo.fly(this.getDragEl()).hide();
23075     },
23076
23077     // overrides Roo.dd.DragDrop
23078     // By default we try to move the element to the last location of the frame.
23079     // This is so that the default behavior mirrors that of Roo.dd.DD.
23080     endDrag: function(e) {
23081
23082         var lel = this.getEl();
23083         var del = this.getDragEl();
23084
23085         // Show the drag frame briefly so we can get its position
23086         del.style.visibility = "";
23087
23088         this.beforeMove();
23089         // Hide the linked element before the move to get around a Safari
23090         // rendering bug.
23091         lel.style.visibility = "hidden";
23092         Roo.dd.DDM.moveToEl(lel, del);
23093         del.style.visibility = "hidden";
23094         lel.style.visibility = "";
23095
23096         this.afterDrag();
23097     },
23098
23099     beforeMove : function(){
23100
23101     },
23102
23103     afterDrag : function(){
23104
23105     },
23106
23107     toString: function() {
23108         return ("DDProxy " + this.id);
23109     }
23110
23111 });
23112 /*
23113  * Based on:
23114  * Ext JS Library 1.1.1
23115  * Copyright(c) 2006-2007, Ext JS, LLC.
23116  *
23117  * Originally Released Under LGPL - original licence link has changed is not relivant.
23118  *
23119  * Fork - LGPL
23120  * <script type="text/javascript">
23121  */
23122
23123  /**
23124  * @class Roo.dd.DDTarget
23125  * A DragDrop implementation that does not move, but can be a drop
23126  * target.  You would get the same result by simply omitting implementation
23127  * for the event callbacks, but this way we reduce the processing cost of the
23128  * event listener and the callbacks.
23129  * @extends Roo.dd.DragDrop
23130  * @constructor
23131  * @param {String} id the id of the element that is a drop target
23132  * @param {String} sGroup the group of related DragDrop objects
23133  * @param {object} config an object containing configurable attributes
23134  *                 Valid properties for DDTarget in addition to those in
23135  *                 DragDrop:
23136  *                    none
23137  */
23138 Roo.dd.DDTarget = function(id, sGroup, config) {
23139     if (id) {
23140         this.initTarget(id, sGroup, config);
23141     }
23142     if (config && (config.listeners || config.events)) { 
23143         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
23144             listeners : config.listeners || {}, 
23145             events : config.events || {} 
23146         });    
23147     }
23148 };
23149
23150 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
23151 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
23152     toString: function() {
23153         return ("DDTarget " + this.id);
23154     }
23155 });
23156 /*
23157  * Based on:
23158  * Ext JS Library 1.1.1
23159  * Copyright(c) 2006-2007, Ext JS, LLC.
23160  *
23161  * Originally Released Under LGPL - original licence link has changed is not relivant.
23162  *
23163  * Fork - LGPL
23164  * <script type="text/javascript">
23165  */
23166  
23167
23168 /**
23169  * @class Roo.dd.ScrollManager
23170  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
23171  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
23172  * @static
23173  */
23174 Roo.dd.ScrollManager = function(){
23175     var ddm = Roo.dd.DragDropMgr;
23176     var els = {};
23177     var dragEl = null;
23178     var proc = {};
23179     
23180     
23181     
23182     var onStop = function(e){
23183         dragEl = null;
23184         clearProc();
23185     };
23186     
23187     var triggerRefresh = function(){
23188         if(ddm.dragCurrent){
23189              ddm.refreshCache(ddm.dragCurrent.groups);
23190         }
23191     };
23192     
23193     var doScroll = function(){
23194         if(ddm.dragCurrent){
23195             var dds = Roo.dd.ScrollManager;
23196             if(!dds.animate){
23197                 if(proc.el.scroll(proc.dir, dds.increment)){
23198                     triggerRefresh();
23199                 }
23200             }else{
23201                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23202             }
23203         }
23204     };
23205     
23206     var clearProc = function(){
23207         if(proc.id){
23208             clearInterval(proc.id);
23209         }
23210         proc.id = 0;
23211         proc.el = null;
23212         proc.dir = "";
23213     };
23214     
23215     var startProc = function(el, dir){
23216          Roo.log('scroll startproc');
23217         clearProc();
23218         proc.el = el;
23219         proc.dir = dir;
23220         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23221     };
23222     
23223     var onFire = function(e, isDrop){
23224        
23225         if(isDrop || !ddm.dragCurrent){ return; }
23226         var dds = Roo.dd.ScrollManager;
23227         if(!dragEl || dragEl != ddm.dragCurrent){
23228             dragEl = ddm.dragCurrent;
23229             // refresh regions on drag start
23230             dds.refreshCache();
23231         }
23232         
23233         var xy = Roo.lib.Event.getXY(e);
23234         var pt = new Roo.lib.Point(xy[0], xy[1]);
23235         for(var id in els){
23236             var el = els[id], r = el._region;
23237             if(r && r.contains(pt) && el.isScrollable()){
23238                 if(r.bottom - pt.y <= dds.thresh){
23239                     if(proc.el != el){
23240                         startProc(el, "down");
23241                     }
23242                     return;
23243                 }else if(r.right - pt.x <= dds.thresh){
23244                     if(proc.el != el){
23245                         startProc(el, "left");
23246                     }
23247                     return;
23248                 }else if(pt.y - r.top <= dds.thresh){
23249                     if(proc.el != el){
23250                         startProc(el, "up");
23251                     }
23252                     return;
23253                 }else if(pt.x - r.left <= dds.thresh){
23254                     if(proc.el != el){
23255                         startProc(el, "right");
23256                     }
23257                     return;
23258                 }
23259             }
23260         }
23261         clearProc();
23262     };
23263     
23264     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23265     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23266     
23267     return {
23268         /**
23269          * Registers new overflow element(s) to auto scroll
23270          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23271          */
23272         register : function(el){
23273             if(el instanceof Array){
23274                 for(var i = 0, len = el.length; i < len; i++) {
23275                         this.register(el[i]);
23276                 }
23277             }else{
23278                 el = Roo.get(el);
23279                 els[el.id] = el;
23280             }
23281             Roo.dd.ScrollManager.els = els;
23282         },
23283         
23284         /**
23285          * Unregisters overflow element(s) so they are no longer scrolled
23286          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23287          */
23288         unregister : function(el){
23289             if(el instanceof Array){
23290                 for(var i = 0, len = el.length; i < len; i++) {
23291                         this.unregister(el[i]);
23292                 }
23293             }else{
23294                 el = Roo.get(el);
23295                 delete els[el.id];
23296             }
23297         },
23298         
23299         /**
23300          * The number of pixels from the edge of a container the pointer needs to be to 
23301          * trigger scrolling (defaults to 25)
23302          * @type Number
23303          */
23304         thresh : 25,
23305         
23306         /**
23307          * The number of pixels to scroll in each scroll increment (defaults to 50)
23308          * @type Number
23309          */
23310         increment : 100,
23311         
23312         /**
23313          * The frequency of scrolls in milliseconds (defaults to 500)
23314          * @type Number
23315          */
23316         frequency : 500,
23317         
23318         /**
23319          * True to animate the scroll (defaults to true)
23320          * @type Boolean
23321          */
23322         animate: true,
23323         
23324         /**
23325          * The animation duration in seconds - 
23326          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23327          * @type Number
23328          */
23329         animDuration: .4,
23330         
23331         /**
23332          * Manually trigger a cache refresh.
23333          */
23334         refreshCache : function(){
23335             for(var id in els){
23336                 if(typeof els[id] == 'object'){ // for people extending the object prototype
23337                     els[id]._region = els[id].getRegion();
23338                 }
23339             }
23340         }
23341     };
23342 }();/*
23343  * Based on:
23344  * Ext JS Library 1.1.1
23345  * Copyright(c) 2006-2007, Ext JS, LLC.
23346  *
23347  * Originally Released Under LGPL - original licence link has changed is not relivant.
23348  *
23349  * Fork - LGPL
23350  * <script type="text/javascript">
23351  */
23352  
23353
23354 /**
23355  * @class Roo.dd.Registry
23356  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
23357  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23358  * @static
23359  */
23360 Roo.dd.Registry = function(){
23361     var elements = {}; 
23362     var handles = {}; 
23363     var autoIdSeed = 0;
23364
23365     var getId = function(el, autogen){
23366         if(typeof el == "string"){
23367             return el;
23368         }
23369         var id = el.id;
23370         if(!id && autogen !== false){
23371             id = "roodd-" + (++autoIdSeed);
23372             el.id = id;
23373         }
23374         return id;
23375     };
23376     
23377     return {
23378     /**
23379      * Register a drag drop element
23380      * @param {String|HTMLElement} element The id or DOM node to register
23381      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23382      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
23383      * knows how to interpret, plus there are some specific properties known to the Registry that should be
23384      * populated in the data object (if applicable):
23385      * <pre>
23386 Value      Description<br />
23387 ---------  ------------------------------------------<br />
23388 handles    Array of DOM nodes that trigger dragging<br />
23389            for the element being registered<br />
23390 isHandle   True if the element passed in triggers<br />
23391            dragging itself, else false
23392 </pre>
23393      */
23394         register : function(el, data){
23395             data = data || {};
23396             if(typeof el == "string"){
23397                 el = document.getElementById(el);
23398             }
23399             data.ddel = el;
23400             elements[getId(el)] = data;
23401             if(data.isHandle !== false){
23402                 handles[data.ddel.id] = data;
23403             }
23404             if(data.handles){
23405                 var hs = data.handles;
23406                 for(var i = 0, len = hs.length; i < len; i++){
23407                         handles[getId(hs[i])] = data;
23408                 }
23409             }
23410         },
23411
23412     /**
23413      * Unregister a drag drop element
23414      * @param {String|HTMLElement}  element The id or DOM node to unregister
23415      */
23416         unregister : function(el){
23417             var id = getId(el, false);
23418             var data = elements[id];
23419             if(data){
23420                 delete elements[id];
23421                 if(data.handles){
23422                     var hs = data.handles;
23423                     for(var i = 0, len = hs.length; i < len; i++){
23424                         delete handles[getId(hs[i], false)];
23425                     }
23426                 }
23427             }
23428         },
23429
23430     /**
23431      * Returns the handle registered for a DOM Node by id
23432      * @param {String|HTMLElement} id The DOM node or id to look up
23433      * @return {Object} handle The custom handle data
23434      */
23435         getHandle : function(id){
23436             if(typeof id != "string"){ // must be element?
23437                 id = id.id;
23438             }
23439             return handles[id];
23440         },
23441
23442     /**
23443      * Returns the handle that is registered for the DOM node that is the target of the event
23444      * @param {Event} e The event
23445      * @return {Object} handle The custom handle data
23446      */
23447         getHandleFromEvent : function(e){
23448             var t = Roo.lib.Event.getTarget(e);
23449             return t ? handles[t.id] : null;
23450         },
23451
23452     /**
23453      * Returns a custom data object that is registered for a DOM node by id
23454      * @param {String|HTMLElement} id The DOM node or id to look up
23455      * @return {Object} data The custom data
23456      */
23457         getTarget : function(id){
23458             if(typeof id != "string"){ // must be element?
23459                 id = id.id;
23460             }
23461             return elements[id];
23462         },
23463
23464     /**
23465      * Returns a custom data object that is registered for the DOM node that is the target of the event
23466      * @param {Event} e The event
23467      * @return {Object} data The custom data
23468      */
23469         getTargetFromEvent : function(e){
23470             var t = Roo.lib.Event.getTarget(e);
23471             return t ? elements[t.id] || handles[t.id] : null;
23472         }
23473     };
23474 }();/*
23475  * Based on:
23476  * Ext JS Library 1.1.1
23477  * Copyright(c) 2006-2007, Ext JS, LLC.
23478  *
23479  * Originally Released Under LGPL - original licence link has changed is not relivant.
23480  *
23481  * Fork - LGPL
23482  * <script type="text/javascript">
23483  */
23484  
23485
23486 /**
23487  * @class Roo.dd.StatusProxy
23488  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23489  * default drag proxy used by all Roo.dd components.
23490  * @constructor
23491  * @param {Object} config
23492  */
23493 Roo.dd.StatusProxy = function(config){
23494     Roo.apply(this, config);
23495     this.id = this.id || Roo.id();
23496     this.el = new Roo.Layer({
23497         dh: {
23498             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23499                 {tag: "div", cls: "x-dd-drop-icon"},
23500                 {tag: "div", cls: "x-dd-drag-ghost"}
23501             ]
23502         }, 
23503         shadow: !config || config.shadow !== false
23504     });
23505     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23506     this.dropStatus = this.dropNotAllowed;
23507 };
23508
23509 Roo.dd.StatusProxy.prototype = {
23510     /**
23511      * @cfg {String} dropAllowed
23512      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23513      */
23514     dropAllowed : "x-dd-drop-ok",
23515     /**
23516      * @cfg {String} dropNotAllowed
23517      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23518      */
23519     dropNotAllowed : "x-dd-drop-nodrop",
23520
23521     /**
23522      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23523      * over the current target element.
23524      * @param {String} cssClass The css class for the new drop status indicator image
23525      */
23526     setStatus : function(cssClass){
23527         cssClass = cssClass || this.dropNotAllowed;
23528         if(this.dropStatus != cssClass){
23529             this.el.replaceClass(this.dropStatus, cssClass);
23530             this.dropStatus = cssClass;
23531         }
23532     },
23533
23534     /**
23535      * Resets the status indicator to the default dropNotAllowed value
23536      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23537      */
23538     reset : function(clearGhost){
23539         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23540         this.dropStatus = this.dropNotAllowed;
23541         if(clearGhost){
23542             this.ghost.update("");
23543         }
23544     },
23545
23546     /**
23547      * Updates the contents of the ghost element
23548      * @param {String} html The html that will replace the current innerHTML of the ghost element
23549      */
23550     update : function(html){
23551         if(typeof html == "string"){
23552             this.ghost.update(html);
23553         }else{
23554             this.ghost.update("");
23555             html.style.margin = "0";
23556             this.ghost.dom.appendChild(html);
23557         }
23558         // ensure float = none set?? cant remember why though.
23559         var el = this.ghost.dom.firstChild;
23560                 if(el){
23561                         Roo.fly(el).setStyle('float', 'none');
23562                 }
23563     },
23564     
23565     /**
23566      * Returns the underlying proxy {@link Roo.Layer}
23567      * @return {Roo.Layer} el
23568     */
23569     getEl : function(){
23570         return this.el;
23571     },
23572
23573     /**
23574      * Returns the ghost element
23575      * @return {Roo.Element} el
23576      */
23577     getGhost : function(){
23578         return this.ghost;
23579     },
23580
23581     /**
23582      * Hides the proxy
23583      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23584      */
23585     hide : function(clear){
23586         this.el.hide();
23587         if(clear){
23588             this.reset(true);
23589         }
23590     },
23591
23592     /**
23593      * Stops the repair animation if it's currently running
23594      */
23595     stop : function(){
23596         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23597             this.anim.stop();
23598         }
23599     },
23600
23601     /**
23602      * Displays this proxy
23603      */
23604     show : function(){
23605         this.el.show();
23606     },
23607
23608     /**
23609      * Force the Layer to sync its shadow and shim positions to the element
23610      */
23611     sync : function(){
23612         this.el.sync();
23613     },
23614
23615     /**
23616      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23617      * invalid drop operation by the item being dragged.
23618      * @param {Array} xy The XY position of the element ([x, y])
23619      * @param {Function} callback The function to call after the repair is complete
23620      * @param {Object} scope The scope in which to execute the callback
23621      */
23622     repair : function(xy, callback, scope){
23623         this.callback = callback;
23624         this.scope = scope;
23625         if(xy && this.animRepair !== false){
23626             this.el.addClass("x-dd-drag-repair");
23627             this.el.hideUnders(true);
23628             this.anim = this.el.shift({
23629                 duration: this.repairDuration || .5,
23630                 easing: 'easeOut',
23631                 xy: xy,
23632                 stopFx: true,
23633                 callback: this.afterRepair,
23634                 scope: this
23635             });
23636         }else{
23637             this.afterRepair();
23638         }
23639     },
23640
23641     // private
23642     afterRepair : function(){
23643         this.hide(true);
23644         if(typeof this.callback == "function"){
23645             this.callback.call(this.scope || this);
23646         }
23647         this.callback = null;
23648         this.scope = null;
23649     }
23650 };/*
23651  * Based on:
23652  * Ext JS Library 1.1.1
23653  * Copyright(c) 2006-2007, Ext JS, LLC.
23654  *
23655  * Originally Released Under LGPL - original licence link has changed is not relivant.
23656  *
23657  * Fork - LGPL
23658  * <script type="text/javascript">
23659  */
23660
23661 /**
23662  * @class Roo.dd.DragSource
23663  * @extends Roo.dd.DDProxy
23664  * A simple class that provides the basic implementation needed to make any element draggable.
23665  * @constructor
23666  * @param {String/HTMLElement/Element} el The container element
23667  * @param {Object} config
23668  */
23669 Roo.dd.DragSource = function(el, config){
23670     this.el = Roo.get(el);
23671     this.dragData = {};
23672     
23673     Roo.apply(this, config);
23674     
23675     if(!this.proxy){
23676         this.proxy = new Roo.dd.StatusProxy();
23677     }
23678
23679     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23680           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23681     
23682     this.dragging = false;
23683 };
23684
23685 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23686     /**
23687      * @cfg {String} dropAllowed
23688      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23689      */
23690     dropAllowed : "x-dd-drop-ok",
23691     /**
23692      * @cfg {String} dropNotAllowed
23693      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23694      */
23695     dropNotAllowed : "x-dd-drop-nodrop",
23696
23697     /**
23698      * Returns the data object associated with this drag source
23699      * @return {Object} data An object containing arbitrary data
23700      */
23701     getDragData : function(e){
23702         return this.dragData;
23703     },
23704
23705     // private
23706     onDragEnter : function(e, id){
23707         var target = Roo.dd.DragDropMgr.getDDById(id);
23708         this.cachedTarget = target;
23709         if(this.beforeDragEnter(target, e, id) !== false){
23710             if(target.isNotifyTarget){
23711                 var status = target.notifyEnter(this, e, this.dragData);
23712                 this.proxy.setStatus(status);
23713             }else{
23714                 this.proxy.setStatus(this.dropAllowed);
23715             }
23716             
23717             if(this.afterDragEnter){
23718                 /**
23719                  * An empty function by default, but provided so that you can perform a custom action
23720                  * when the dragged item enters the drop target by providing an implementation.
23721                  * @param {Roo.dd.DragDrop} target The drop target
23722                  * @param {Event} e The event object
23723                  * @param {String} id The id of the dragged element
23724                  * @method afterDragEnter
23725                  */
23726                 this.afterDragEnter(target, e, id);
23727             }
23728         }
23729     },
23730
23731     /**
23732      * An empty function by default, but provided so that you can perform a custom action
23733      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23734      * @param {Roo.dd.DragDrop} target The drop target
23735      * @param {Event} e The event object
23736      * @param {String} id The id of the dragged element
23737      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23738      */
23739     beforeDragEnter : function(target, e, id){
23740         return true;
23741     },
23742
23743     // private
23744     alignElWithMouse: function() {
23745         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23746         this.proxy.sync();
23747     },
23748
23749     // private
23750     onDragOver : function(e, id){
23751         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23752         if(this.beforeDragOver(target, e, id) !== false){
23753             if(target.isNotifyTarget){
23754                 var status = target.notifyOver(this, e, this.dragData);
23755                 this.proxy.setStatus(status);
23756             }
23757
23758             if(this.afterDragOver){
23759                 /**
23760                  * An empty function by default, but provided so that you can perform a custom action
23761                  * while the dragged item is over the drop target by providing an implementation.
23762                  * @param {Roo.dd.DragDrop} target The drop target
23763                  * @param {Event} e The event object
23764                  * @param {String} id The id of the dragged element
23765                  * @method afterDragOver
23766                  */
23767                 this.afterDragOver(target, e, id);
23768             }
23769         }
23770     },
23771
23772     /**
23773      * An empty function by default, but provided so that you can perform a custom action
23774      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23775      * @param {Roo.dd.DragDrop} target The drop target
23776      * @param {Event} e The event object
23777      * @param {String} id The id of the dragged element
23778      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23779      */
23780     beforeDragOver : function(target, e, id){
23781         return true;
23782     },
23783
23784     // private
23785     onDragOut : function(e, id){
23786         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23787         if(this.beforeDragOut(target, e, id) !== false){
23788             if(target.isNotifyTarget){
23789                 target.notifyOut(this, e, this.dragData);
23790             }
23791             this.proxy.reset();
23792             if(this.afterDragOut){
23793                 /**
23794                  * An empty function by default, but provided so that you can perform a custom action
23795                  * after the dragged item is dragged out of the target without dropping.
23796                  * @param {Roo.dd.DragDrop} target The drop target
23797                  * @param {Event} e The event object
23798                  * @param {String} id The id of the dragged element
23799                  * @method afterDragOut
23800                  */
23801                 this.afterDragOut(target, e, id);
23802             }
23803         }
23804         this.cachedTarget = null;
23805     },
23806
23807     /**
23808      * An empty function by default, but provided so that you can perform a custom action before the dragged
23809      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23810      * @param {Roo.dd.DragDrop} target The drop target
23811      * @param {Event} e The event object
23812      * @param {String} id The id of the dragged element
23813      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23814      */
23815     beforeDragOut : function(target, e, id){
23816         return true;
23817     },
23818     
23819     // private
23820     onDragDrop : function(e, id){
23821         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23822         if(this.beforeDragDrop(target, e, id) !== false){
23823             if(target.isNotifyTarget){
23824                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23825                     this.onValidDrop(target, e, id);
23826                 }else{
23827                     this.onInvalidDrop(target, e, id);
23828                 }
23829             }else{
23830                 this.onValidDrop(target, e, id);
23831             }
23832             
23833             if(this.afterDragDrop){
23834                 /**
23835                  * An empty function by default, but provided so that you can perform a custom action
23836                  * after a valid drag drop has occurred by providing an implementation.
23837                  * @param {Roo.dd.DragDrop} target The drop target
23838                  * @param {Event} e The event object
23839                  * @param {String} id The id of the dropped element
23840                  * @method afterDragDrop
23841                  */
23842                 this.afterDragDrop(target, e, id);
23843             }
23844         }
23845         delete this.cachedTarget;
23846     },
23847
23848     /**
23849      * An empty function by default, but provided so that you can perform a custom action before the dragged
23850      * item is dropped onto the target and optionally cancel the onDragDrop.
23851      * @param {Roo.dd.DragDrop} target The drop target
23852      * @param {Event} e The event object
23853      * @param {String} id The id of the dragged element
23854      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23855      */
23856     beforeDragDrop : function(target, e, id){
23857         return true;
23858     },
23859
23860     // private
23861     onValidDrop : function(target, e, id){
23862         this.hideProxy();
23863         if(this.afterValidDrop){
23864             /**
23865              * An empty function by default, but provided so that you can perform a custom action
23866              * after a valid drop has occurred by providing an implementation.
23867              * @param {Object} target The target DD 
23868              * @param {Event} e The event object
23869              * @param {String} id The id of the dropped element
23870              * @method afterInvalidDrop
23871              */
23872             this.afterValidDrop(target, e, id);
23873         }
23874     },
23875
23876     // private
23877     getRepairXY : function(e, data){
23878         return this.el.getXY();  
23879     },
23880
23881     // private
23882     onInvalidDrop : function(target, e, id){
23883         this.beforeInvalidDrop(target, e, id);
23884         if(this.cachedTarget){
23885             if(this.cachedTarget.isNotifyTarget){
23886                 this.cachedTarget.notifyOut(this, e, this.dragData);
23887             }
23888             this.cacheTarget = null;
23889         }
23890         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23891
23892         if(this.afterInvalidDrop){
23893             /**
23894              * An empty function by default, but provided so that you can perform a custom action
23895              * after an invalid drop has occurred by providing an implementation.
23896              * @param {Event} e The event object
23897              * @param {String} id The id of the dropped element
23898              * @method afterInvalidDrop
23899              */
23900             this.afterInvalidDrop(e, id);
23901         }
23902     },
23903
23904     // private
23905     afterRepair : function(){
23906         if(Roo.enableFx){
23907             this.el.highlight(this.hlColor || "c3daf9");
23908         }
23909         this.dragging = false;
23910     },
23911
23912     /**
23913      * An empty function by default, but provided so that you can perform a custom action after an invalid
23914      * drop has occurred.
23915      * @param {Roo.dd.DragDrop} target The drop target
23916      * @param {Event} e The event object
23917      * @param {String} id The id of the dragged element
23918      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23919      */
23920     beforeInvalidDrop : function(target, e, id){
23921         return true;
23922     },
23923
23924     // private
23925     handleMouseDown : function(e){
23926         if(this.dragging) {
23927             return;
23928         }
23929         var data = this.getDragData(e);
23930         if(data && this.onBeforeDrag(data, e) !== false){
23931             this.dragData = data;
23932             this.proxy.stop();
23933             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23934         } 
23935     },
23936
23937     /**
23938      * An empty function by default, but provided so that you can perform a custom action before the initial
23939      * drag event begins and optionally cancel it.
23940      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23941      * @param {Event} e The event object
23942      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23943      */
23944     onBeforeDrag : function(data, e){
23945         return true;
23946     },
23947
23948     /**
23949      * An empty function by default, but provided so that you can perform a custom action once the initial
23950      * drag event has begun.  The drag cannot be canceled from this function.
23951      * @param {Number} x The x position of the click on the dragged object
23952      * @param {Number} y The y position of the click on the dragged object
23953      */
23954     onStartDrag : Roo.emptyFn,
23955
23956     // private - YUI override
23957     startDrag : function(x, y){
23958         this.proxy.reset();
23959         this.dragging = true;
23960         this.proxy.update("");
23961         this.onInitDrag(x, y);
23962         this.proxy.show();
23963     },
23964
23965     // private
23966     onInitDrag : function(x, y){
23967         var clone = this.el.dom.cloneNode(true);
23968         clone.id = Roo.id(); // prevent duplicate ids
23969         this.proxy.update(clone);
23970         this.onStartDrag(x, y);
23971         return true;
23972     },
23973
23974     /**
23975      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23976      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23977      */
23978     getProxy : function(){
23979         return this.proxy;  
23980     },
23981
23982     /**
23983      * Hides the drag source's {@link Roo.dd.StatusProxy}
23984      */
23985     hideProxy : function(){
23986         this.proxy.hide();  
23987         this.proxy.reset(true);
23988         this.dragging = false;
23989     },
23990
23991     // private
23992     triggerCacheRefresh : function(){
23993         Roo.dd.DDM.refreshCache(this.groups);
23994     },
23995
23996     // private - override to prevent hiding
23997     b4EndDrag: function(e) {
23998     },
23999
24000     // private - override to prevent moving
24001     endDrag : function(e){
24002         this.onEndDrag(this.dragData, e);
24003     },
24004
24005     // private
24006     onEndDrag : function(data, e){
24007     },
24008     
24009     // private - pin to cursor
24010     autoOffset : function(x, y) {
24011         this.setDelta(-12, -20);
24012     }    
24013 });/*
24014  * Based on:
24015  * Ext JS Library 1.1.1
24016  * Copyright(c) 2006-2007, Ext JS, LLC.
24017  *
24018  * Originally Released Under LGPL - original licence link has changed is not relivant.
24019  *
24020  * Fork - LGPL
24021  * <script type="text/javascript">
24022  */
24023
24024
24025 /**
24026  * @class Roo.dd.DropTarget
24027  * @extends Roo.dd.DDTarget
24028  * A simple class that provides the basic implementation needed to make any element a drop target that can have
24029  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
24030  * @constructor
24031  * @param {String/HTMLElement/Element} el The container element
24032  * @param {Object} config
24033  */
24034 Roo.dd.DropTarget = function(el, config){
24035     this.el = Roo.get(el);
24036     
24037     var listeners = false; ;
24038     if (config && config.listeners) {
24039         listeners= config.listeners;
24040         delete config.listeners;
24041     }
24042     Roo.apply(this, config);
24043     
24044     if(this.containerScroll){
24045         Roo.dd.ScrollManager.register(this.el);
24046     }
24047     this.addEvents( {
24048          /**
24049          * @scope Roo.dd.DropTarget
24050          */
24051          
24052          /**
24053          * @event enter
24054          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
24055          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
24056          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
24057          * 
24058          * IMPORTANT : it should set  this.valid to true|false
24059          * 
24060          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24061          * @param {Event} e The event
24062          * @param {Object} data An object containing arbitrary data supplied by the drag source
24063          */
24064         "enter" : true,
24065         
24066          /**
24067          * @event over
24068          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
24069          * This method will be called on every mouse movement while the drag source is over the drop target.
24070          * This default implementation simply returns the dropAllowed config value.
24071          * 
24072          * IMPORTANT : it should set  this.valid to true|false
24073          * 
24074          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24075          * @param {Event} e The event
24076          * @param {Object} data An object containing arbitrary data supplied by the drag source
24077          
24078          */
24079         "over" : true,
24080         /**
24081          * @event out
24082          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
24083          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
24084          * overClass (if any) from the drop element.
24085          * 
24086          * 
24087          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24088          * @param {Event} e The event
24089          * @param {Object} data An object containing arbitrary data supplied by the drag source
24090          */
24091          "out" : true,
24092          
24093         /**
24094          * @event drop
24095          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
24096          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
24097          * implementation that does something to process the drop event and returns true so that the drag source's
24098          * repair action does not run.
24099          * 
24100          * IMPORTANT : it should set this.success
24101          * 
24102          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24103          * @param {Event} e The event
24104          * @param {Object} data An object containing arbitrary data supplied by the drag source
24105         */
24106          "drop" : true
24107     });
24108             
24109      
24110     Roo.dd.DropTarget.superclass.constructor.call(  this, 
24111         this.el.dom, 
24112         this.ddGroup || this.group,
24113         {
24114             isTarget: true,
24115             listeners : listeners || {} 
24116            
24117         
24118         }
24119     );
24120
24121 };
24122
24123 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
24124     /**
24125      * @cfg {String} overClass
24126      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
24127      */
24128      /**
24129      * @cfg {String} ddGroup
24130      * The drag drop group to handle drop events for
24131      */
24132      
24133     /**
24134      * @cfg {String} dropAllowed
24135      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
24136      */
24137     dropAllowed : "x-dd-drop-ok",
24138     /**
24139      * @cfg {String} dropNotAllowed
24140      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
24141      */
24142     dropNotAllowed : "x-dd-drop-nodrop",
24143     /**
24144      * @cfg {boolean} success
24145      * set this after drop listener.. 
24146      */
24147     success : false,
24148     /**
24149      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
24150      * if the drop point is valid for over/enter..
24151      */
24152     valid : false,
24153     // private
24154     isTarget : true,
24155
24156     // private
24157     isNotifyTarget : true,
24158     
24159     /**
24160      * @hide
24161      */
24162     notifyEnter : function(dd, e, data)
24163     {
24164         this.valid = true;
24165         this.fireEvent('enter', dd, e, data);
24166         if(this.overClass){
24167             this.el.addClass(this.overClass);
24168         }
24169         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24170             this.valid ? this.dropAllowed : this.dropNotAllowed
24171         );
24172     },
24173
24174     /**
24175      * @hide
24176      */
24177     notifyOver : function(dd, e, data)
24178     {
24179         this.valid = true;
24180         this.fireEvent('over', dd, e, data);
24181         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24182             this.valid ? this.dropAllowed : this.dropNotAllowed
24183         );
24184     },
24185
24186     /**
24187      * @hide
24188      */
24189     notifyOut : function(dd, e, data)
24190     {
24191         this.fireEvent('out', dd, e, data);
24192         if(this.overClass){
24193             this.el.removeClass(this.overClass);
24194         }
24195     },
24196
24197     /**
24198      * @hide
24199      */
24200     notifyDrop : function(dd, e, data)
24201     {
24202         this.success = false;
24203         this.fireEvent('drop', dd, e, data);
24204         return this.success;
24205     }
24206 });/*
24207  * Based on:
24208  * Ext JS Library 1.1.1
24209  * Copyright(c) 2006-2007, Ext JS, LLC.
24210  *
24211  * Originally Released Under LGPL - original licence link has changed is not relivant.
24212  *
24213  * Fork - LGPL
24214  * <script type="text/javascript">
24215  */
24216
24217
24218 /**
24219  * @class Roo.dd.DragZone
24220  * @extends Roo.dd.DragSource
24221  * This class provides a container DD instance that proxies for multiple child node sources.<br />
24222  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24223  * @constructor
24224  * @param {String/HTMLElement/Element} el The container element
24225  * @param {Object} config
24226  */
24227 Roo.dd.DragZone = function(el, config){
24228     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24229     if(this.containerScroll){
24230         Roo.dd.ScrollManager.register(this.el);
24231     }
24232 };
24233
24234 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24235     /**
24236      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24237      * for auto scrolling during drag operations.
24238      */
24239     /**
24240      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24241      * method after a failed drop (defaults to "c3daf9" - light blue)
24242      */
24243
24244     /**
24245      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24246      * for a valid target to drag based on the mouse down. Override this method
24247      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24248      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24249      * @param {EventObject} e The mouse down event
24250      * @return {Object} The dragData
24251      */
24252     getDragData : function(e){
24253         return Roo.dd.Registry.getHandleFromEvent(e);
24254     },
24255     
24256     /**
24257      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24258      * this.dragData.ddel
24259      * @param {Number} x The x position of the click on the dragged object
24260      * @param {Number} y The y position of the click on the dragged object
24261      * @return {Boolean} true to continue the drag, false to cancel
24262      */
24263     onInitDrag : function(x, y){
24264         this.proxy.update(this.dragData.ddel.cloneNode(true));
24265         this.onStartDrag(x, y);
24266         return true;
24267     },
24268     
24269     /**
24270      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
24271      */
24272     afterRepair : function(){
24273         if(Roo.enableFx){
24274             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24275         }
24276         this.dragging = false;
24277     },
24278
24279     /**
24280      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24281      * the XY of this.dragData.ddel
24282      * @param {EventObject} e The mouse up event
24283      * @return {Array} The xy location (e.g. [100, 200])
24284      */
24285     getRepairXY : function(e){
24286         return Roo.Element.fly(this.dragData.ddel).getXY();  
24287     }
24288 });/*
24289  * Based on:
24290  * Ext JS Library 1.1.1
24291  * Copyright(c) 2006-2007, Ext JS, LLC.
24292  *
24293  * Originally Released Under LGPL - original licence link has changed is not relivant.
24294  *
24295  * Fork - LGPL
24296  * <script type="text/javascript">
24297  */
24298 /**
24299  * @class Roo.dd.DropZone
24300  * @extends Roo.dd.DropTarget
24301  * This class provides a container DD instance that proxies for multiple child node targets.<br />
24302  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24303  * @constructor
24304  * @param {String/HTMLElement/Element} el The container element
24305  * @param {Object} config
24306  */
24307 Roo.dd.DropZone = function(el, config){
24308     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24309 };
24310
24311 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24312     /**
24313      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
24314      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24315      * provide your own custom lookup.
24316      * @param {Event} e The event
24317      * @return {Object} data The custom data
24318      */
24319     getTargetFromEvent : function(e){
24320         return Roo.dd.Registry.getTargetFromEvent(e);
24321     },
24322
24323     /**
24324      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24325      * that it has registered.  This method has no default implementation and should be overridden to provide
24326      * node-specific processing if necessary.
24327      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
24328      * {@link #getTargetFromEvent} for this node)
24329      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24330      * @param {Event} e The event
24331      * @param {Object} data An object containing arbitrary data supplied by the drag source
24332      */
24333     onNodeEnter : function(n, dd, e, data){
24334         
24335     },
24336
24337     /**
24338      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24339      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
24340      * overridden to provide the proper feedback.
24341      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24342      * {@link #getTargetFromEvent} for this node)
24343      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24344      * @param {Event} e The event
24345      * @param {Object} data An object containing arbitrary data supplied by the drag source
24346      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24347      * underlying {@link Roo.dd.StatusProxy} can be updated
24348      */
24349     onNodeOver : function(n, dd, e, data){
24350         return this.dropAllowed;
24351     },
24352
24353     /**
24354      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24355      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
24356      * node-specific processing if necessary.
24357      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24358      * {@link #getTargetFromEvent} for this node)
24359      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24360      * @param {Event} e The event
24361      * @param {Object} data An object containing arbitrary data supplied by the drag source
24362      */
24363     onNodeOut : function(n, dd, e, data){
24364         
24365     },
24366
24367     /**
24368      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24369      * the drop node.  The default implementation returns false, so it should be overridden to provide the
24370      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24371      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24372      * {@link #getTargetFromEvent} for this node)
24373      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24374      * @param {Event} e The event
24375      * @param {Object} data An object containing arbitrary data supplied by the drag source
24376      * @return {Boolean} True if the drop was valid, else false
24377      */
24378     onNodeDrop : function(n, dd, e, data){
24379         return false;
24380     },
24381
24382     /**
24383      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24384      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
24385      * it should be overridden to provide the proper feedback if necessary.
24386      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24387      * @param {Event} e The event
24388      * @param {Object} data An object containing arbitrary data supplied by the drag source
24389      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24390      * underlying {@link Roo.dd.StatusProxy} can be updated
24391      */
24392     onContainerOver : function(dd, e, data){
24393         return this.dropNotAllowed;
24394     },
24395
24396     /**
24397      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24398      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
24399      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24400      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
24401      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24402      * @param {Event} e The event
24403      * @param {Object} data An object containing arbitrary data supplied by the drag source
24404      * @return {Boolean} True if the drop was valid, else false
24405      */
24406     onContainerDrop : function(dd, e, data){
24407         return false;
24408     },
24409
24410     /**
24411      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24412      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
24413      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24414      * you should override this method and provide a custom implementation.
24415      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24416      * @param {Event} e The event
24417      * @param {Object} data An object containing arbitrary data supplied by the drag source
24418      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24419      * underlying {@link Roo.dd.StatusProxy} can be updated
24420      */
24421     notifyEnter : function(dd, e, data){
24422         return this.dropNotAllowed;
24423     },
24424
24425     /**
24426      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24427      * This method will be called on every mouse movement while the drag source is over the drop zone.
24428      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24429      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24430      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24431      * registered node, it will call {@link #onContainerOver}.
24432      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24433      * @param {Event} e The event
24434      * @param {Object} data An object containing arbitrary data supplied by the drag source
24435      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24436      * underlying {@link Roo.dd.StatusProxy} can be updated
24437      */
24438     notifyOver : function(dd, e, data){
24439         var n = this.getTargetFromEvent(e);
24440         if(!n){ // not over valid drop target
24441             if(this.lastOverNode){
24442                 this.onNodeOut(this.lastOverNode, dd, e, data);
24443                 this.lastOverNode = null;
24444             }
24445             return this.onContainerOver(dd, e, data);
24446         }
24447         if(this.lastOverNode != n){
24448             if(this.lastOverNode){
24449                 this.onNodeOut(this.lastOverNode, dd, e, data);
24450             }
24451             this.onNodeEnter(n, dd, e, data);
24452             this.lastOverNode = n;
24453         }
24454         return this.onNodeOver(n, dd, e, data);
24455     },
24456
24457     /**
24458      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24459      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
24460      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24461      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24462      * @param {Event} e The event
24463      * @param {Object} data An object containing arbitrary data supplied by the drag zone
24464      */
24465     notifyOut : function(dd, e, data){
24466         if(this.lastOverNode){
24467             this.onNodeOut(this.lastOverNode, dd, e, data);
24468             this.lastOverNode = null;
24469         }
24470     },
24471
24472     /**
24473      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24474      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
24475      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24476      * otherwise it will call {@link #onContainerDrop}.
24477      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24478      * @param {Event} e The event
24479      * @param {Object} data An object containing arbitrary data supplied by the drag source
24480      * @return {Boolean} True if the drop was valid, else false
24481      */
24482     notifyDrop : function(dd, e, data){
24483         if(this.lastOverNode){
24484             this.onNodeOut(this.lastOverNode, dd, e, data);
24485             this.lastOverNode = null;
24486         }
24487         var n = this.getTargetFromEvent(e);
24488         return n ?
24489             this.onNodeDrop(n, dd, e, data) :
24490             this.onContainerDrop(dd, e, data);
24491     },
24492
24493     // private
24494     triggerCacheRefresh : function(){
24495         Roo.dd.DDM.refreshCache(this.groups);
24496     }  
24497 });