add simple interval support to Date.getElapsed()
[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 {Date} date (optional) Defaults to now
1209  @param {String} interval   A valid date interval enum value (eg. Date.DAY)
1210  @return {Number} The diff in milliseconds
1211  @member Date getElapsed
1212  */
1213 Date.prototype.getElapsed = function(date, interval)
1214 {
1215     date = date ||  new Date();
1216     var ret = Math.abs(date.getTime()-this.getTime());
1217     switch (interval) {
1218        
1219         case  Date.SECOND:
1220             return Math.floor(ret / (1000));
1221         case  Date.MINUTE:
1222             return Math.floor(ret / (100*60));
1223         case  Date.HOUR:
1224             return Math.floor(ret / (100*60*60));
1225         case  Date.DAY:
1226             return Math.floor(ret / (100*60*60*24));
1227         case  Date.MONTH: // this does not give exact number...??
1228             return ((date.format("Y") - this.format("Y")) * 12) + (date.format("m") - this.format("m"));
1229         case  Date.YEAR: // this does not give exact number...??
1230             return (date.format("Y") - this.format("Y"));
1231        
1232         case  Date.MILLI:
1233         default:
1234             return ret;
1235     }
1236 };
1237  
1238 // was in date file..
1239
1240
1241 // private
1242 Date.parseFunctions = {count:0};
1243 // private
1244 Date.parseRegexes = [];
1245 // private
1246 Date.formatFunctions = {count:0};
1247
1248 // private
1249 Date.prototype.dateFormat = function(format) {
1250     if (Date.formatFunctions[format] == null) {
1251         Date.createNewFormat(format);
1252     }
1253     var func = Date.formatFunctions[format];
1254     return this[func]();
1255 };
1256
1257
1258 /**
1259  * Formats a date given the supplied format string
1260  * @param {String} format The format string
1261  * @return {String} The formatted date
1262  * @method
1263  */
1264 Date.prototype.format = Date.prototype.dateFormat;
1265
1266 // private
1267 Date.createNewFormat = function(format) {
1268     var funcName = "format" + Date.formatFunctions.count++;
1269     Date.formatFunctions[format] = funcName;
1270     var code = "Date.prototype." + funcName + " = function(){return ";
1271     var special = false;
1272     var ch = '';
1273     for (var i = 0; i < format.length; ++i) {
1274         ch = format.charAt(i);
1275         if (!special && ch == "\\") {
1276             special = true;
1277         }
1278         else if (special) {
1279             special = false;
1280             code += "'" + String.escape(ch) + "' + ";
1281         }
1282         else {
1283             code += Date.getFormatCode(ch);
1284         }
1285     }
1286     /** eval:var:zzzzzzzzzzzzz */
1287     eval(code.substring(0, code.length - 3) + ";}");
1288 };
1289
1290 // private
1291 Date.getFormatCode = function(character) {
1292     switch (character) {
1293     case "d":
1294         return "String.leftPad(this.getDate(), 2, '0') + ";
1295     case "D":
1296         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1297     case "j":
1298         return "this.getDate() + ";
1299     case "l":
1300         return "Date.dayNames[this.getDay()] + ";
1301     case "S":
1302         return "this.getSuffix() + ";
1303     case "w":
1304         return "this.getDay() + ";
1305     case "z":
1306         return "this.getDayOfYear() + ";
1307     case "W":
1308         return "this.getWeekOfYear() + ";
1309     case "F":
1310         return "Date.monthNames[this.getMonth()] + ";
1311     case "m":
1312         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1313     case "M":
1314         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1315     case "n":
1316         return "(this.getMonth() + 1) + ";
1317     case "t":
1318         return "this.getDaysInMonth() + ";
1319     case "L":
1320         return "(this.isLeapYear() ? 1 : 0) + ";
1321     case "Y":
1322         return "this.getFullYear() + ";
1323     case "y":
1324         return "('' + this.getFullYear()).substring(2, 4) + ";
1325     case "a":
1326         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1327     case "A":
1328         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1329     case "g":
1330         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1331     case "G":
1332         return "this.getHours() + ";
1333     case "h":
1334         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1335     case "H":
1336         return "String.leftPad(this.getHours(), 2, '0') + ";
1337     case "i":
1338         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1339     case "s":
1340         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1341     case "O":
1342         return "this.getGMTOffset() + ";
1343     case "P":
1344         return "this.getGMTColonOffset() + ";
1345     case "T":
1346         return "this.getTimezone() + ";
1347     case "Z":
1348         return "(this.getTimezoneOffset() * -60) + ";
1349     default:
1350         return "'" + String.escape(character) + "' + ";
1351     }
1352 };
1353
1354 /**
1355  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1356  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1357  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1358  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1359  * string or the parse operation will fail.
1360  * Example Usage:
1361 <pre><code>
1362 //dt = Fri May 25 2007 (current date)
1363 var dt = new Date();
1364
1365 //dt = Thu May 25 2006 (today's month/day in 2006)
1366 dt = Date.parseDate("2006", "Y");
1367
1368 //dt = Sun Jan 15 2006 (all date parts specified)
1369 dt = Date.parseDate("2006-1-15", "Y-m-d");
1370
1371 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1372 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1373 </code></pre>
1374  * @param {String} input The unparsed date as a string
1375  * @param {String} format The format the date is in
1376  * @return {Date} The parsed date
1377  * @static
1378  */
1379 Date.parseDate = function(input, format) {
1380     if (Date.parseFunctions[format] == null) {
1381         Date.createParser(format);
1382     }
1383     var func = Date.parseFunctions[format];
1384     return Date[func](input);
1385 };
1386 /**
1387  * @private
1388  */
1389
1390 Date.createParser = function(format) {
1391     var funcName = "parse" + Date.parseFunctions.count++;
1392     var regexNum = Date.parseRegexes.length;
1393     var currentGroup = 1;
1394     Date.parseFunctions[format] = funcName;
1395
1396     var code = "Date." + funcName + " = function(input){\n"
1397         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1398         + "var d = new Date();\n"
1399         + "y = d.getFullYear();\n"
1400         + "m = d.getMonth();\n"
1401         + "d = d.getDate();\n"
1402         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1403         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1404         + "if (results && results.length > 0) {";
1405     var regex = "";
1406
1407     var special = false;
1408     var ch = '';
1409     for (var i = 0; i < format.length; ++i) {
1410         ch = format.charAt(i);
1411         if (!special && ch == "\\") {
1412             special = true;
1413         }
1414         else if (special) {
1415             special = false;
1416             regex += String.escape(ch);
1417         }
1418         else {
1419             var obj = Date.formatCodeToRegex(ch, currentGroup);
1420             currentGroup += obj.g;
1421             regex += obj.s;
1422             if (obj.g && obj.c) {
1423                 code += obj.c;
1424             }
1425         }
1426     }
1427
1428     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1429         + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
1430         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1431         + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
1432         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1433         + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
1434         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1435         + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
1436         + "else if (y >= 0 && m >= 0)\n"
1437         + "{v = new Date(y, m); v.setFullYear(y);}\n"
1438         + "else if (y >= 0)\n"
1439         + "{v = new Date(y); v.setFullYear(y);}\n"
1440         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1441         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1442         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1443         + ";}";
1444
1445     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1446     /** eval:var:zzzzzzzzzzzzz */
1447     eval(code);
1448 };
1449
1450 // private
1451 Date.formatCodeToRegex = function(character, currentGroup) {
1452     switch (character) {
1453     case "D":
1454         return {g:0,
1455         c:null,
1456         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1457     case "j":
1458         return {g:1,
1459             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1460             s:"(\\d{1,2})"}; // day of month without leading zeroes
1461     case "d":
1462         return {g:1,
1463             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1464             s:"(\\d{2})"}; // day of month with leading zeroes
1465     case "l":
1466         return {g:0,
1467             c:null,
1468             s:"(?:" + Date.dayNames.join("|") + ")"};
1469     case "S":
1470         return {g:0,
1471             c:null,
1472             s:"(?:st|nd|rd|th)"};
1473     case "w":
1474         return {g:0,
1475             c:null,
1476             s:"\\d"};
1477     case "z":
1478         return {g:0,
1479             c:null,
1480             s:"(?:\\d{1,3})"};
1481     case "W":
1482         return {g:0,
1483             c:null,
1484             s:"(?:\\d{2})"};
1485     case "F":
1486         return {g:1,
1487             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1488             s:"(" + Date.monthNames.join("|") + ")"};
1489     case "M":
1490         return {g:1,
1491             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1492             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1493     case "n":
1494         return {g:1,
1495             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1496             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1497     case "m":
1498         return {g:1,
1499             c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
1500             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1501     case "t":
1502         return {g:0,
1503             c:null,
1504             s:"\\d{1,2}"};
1505     case "L":
1506         return {g:0,
1507             c:null,
1508             s:"(?:1|0)"};
1509     case "Y":
1510         return {g:1,
1511             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1512             s:"(\\d{4})"};
1513     case "y":
1514         return {g:1,
1515             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1516                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1517             s:"(\\d{1,2})"};
1518     case "a":
1519         return {g:1,
1520             c:"if (results[" + currentGroup + "] == 'am') {\n"
1521                 + "if (h == 12) { h = 0; }\n"
1522                 + "} else { if (h < 12) { h += 12; }}",
1523             s:"(am|pm)"};
1524     case "A":
1525         return {g:1,
1526             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1527                 + "if (h == 12) { h = 0; }\n"
1528                 + "} else { if (h < 12) { h += 12; }}",
1529             s:"(AM|PM)"};
1530     case "g":
1531     case "G":
1532         return {g:1,
1533             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1534             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1535     case "h":
1536     case "H":
1537         return {g:1,
1538             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1539             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1540     case "i":
1541         return {g:1,
1542             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1543             s:"(\\d{2})"};
1544     case "s":
1545         return {g:1,
1546             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1547             s:"(\\d{2})"};
1548     case "O":
1549         return {g:1,
1550             c:[
1551                 "o = results[", currentGroup, "];\n",
1552                 "var sn = o.substring(0,1);\n", // get + / - sign
1553                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1554                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1555                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1556                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1557             ].join(""),
1558             s:"([+\-]\\d{2,4})"};
1559     
1560     
1561     case "P":
1562         return {g:1,
1563                 c:[
1564                    "o = results[", currentGroup, "];\n",
1565                    "var sn = o.substring(0,1);\n",
1566                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1567                    "var mn = o.substring(4,6) % 60;\n",
1568                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1569                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1570             ].join(""),
1571             s:"([+\-]\\d{4})"};
1572     case "T":
1573         return {g:0,
1574             c:null,
1575             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1576     case "Z":
1577         return {g:1,
1578             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1579                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1580             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1581     default:
1582         return {g:0,
1583             c:null,
1584             s:String.escape(character)};
1585     }
1586 };
1587
1588 /**
1589  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1590  * @return {String} The abbreviated timezone name (e.g. 'CST')
1591  */
1592 Date.prototype.getTimezone = function() {
1593     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1594 };
1595
1596 /**
1597  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1598  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1599  */
1600 Date.prototype.getGMTOffset = function() {
1601     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1602         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1603         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1604 };
1605
1606 /**
1607  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1608  * @return {String} 2-characters representing hours and 2-characters representing minutes
1609  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1610  */
1611 Date.prototype.getGMTColonOffset = function() {
1612         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1613                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1614                 + ":"
1615                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1616 }
1617
1618 /**
1619  * Get the numeric day number of the year, adjusted for leap year.
1620  * @return {Number} 0 through 364 (365 in leap years)
1621  */
1622 Date.prototype.getDayOfYear = function() {
1623     var num = 0;
1624     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1625     for (var i = 0; i < this.getMonth(); ++i) {
1626         num += Date.daysInMonth[i];
1627     }
1628     return num + this.getDate() - 1;
1629 };
1630
1631 /**
1632  * Get the string representation of the numeric week number of the year
1633  * (equivalent to the format specifier 'W').
1634  * @return {String} '00' through '52'
1635  */
1636 Date.prototype.getWeekOfYear = function() {
1637     // Skip to Thursday of this week
1638     var now = this.getDayOfYear() + (4 - this.getDay());
1639     // Find the first Thursday of the year
1640     var jan1 = new Date(this.getFullYear(), 0, 1);
1641     var then = (7 - jan1.getDay() + 4);
1642     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1643 };
1644
1645 /**
1646  * Whether or not the current date is in a leap year.
1647  * @return {Boolean} True if the current date is in a leap year, else false
1648  */
1649 Date.prototype.isLeapYear = function() {
1650     var year = this.getFullYear();
1651     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1652 };
1653
1654 /**
1655  * Get the first day of the current month, adjusted for leap year.  The returned value
1656  * is the numeric day index within the week (0-6) which can be used in conjunction with
1657  * the {@link #monthNames} array to retrieve the textual day name.
1658  * Example:
1659  *<pre><code>
1660 var dt = new Date('1/10/2007');
1661 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1662 </code></pre>
1663  * @return {Number} The day number (0-6)
1664  */
1665 Date.prototype.getFirstDayOfMonth = function() {
1666     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1667     return (day < 0) ? (day + 7) : day;
1668 };
1669
1670 /**
1671  * Get the last day of the current month, adjusted for leap year.  The returned value
1672  * is the numeric day index within the week (0-6) which can be used in conjunction with
1673  * the {@link #monthNames} array to retrieve the textual day name.
1674  * Example:
1675  *<pre><code>
1676 var dt = new Date('1/10/2007');
1677 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1678 </code></pre>
1679  * @return {Number} The day number (0-6)
1680  */
1681 Date.prototype.getLastDayOfMonth = function() {
1682     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1683     return (day < 0) ? (day + 7) : day;
1684 };
1685
1686
1687 /**
1688  * Get the first date of this date's month
1689  * @return {Date}
1690  */
1691 Date.prototype.getFirstDateOfMonth = function() {
1692     return new Date(this.getFullYear(), this.getMonth(), 1);
1693 };
1694
1695 /**
1696  * Get the last date of this date's month
1697  * @return {Date}
1698  */
1699 Date.prototype.getLastDateOfMonth = function() {
1700     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1701 };
1702 /**
1703  * Get the number of days in the current month, adjusted for leap year.
1704  * @return {Number} The number of days in the month
1705  */
1706 Date.prototype.getDaysInMonth = function() {
1707     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1708     return Date.daysInMonth[this.getMonth()];
1709 };
1710
1711 /**
1712  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1713  * @return {String} 'st, 'nd', 'rd' or 'th'
1714  */
1715 Date.prototype.getSuffix = function() {
1716     switch (this.getDate()) {
1717         case 1:
1718         case 21:
1719         case 31:
1720             return "st";
1721         case 2:
1722         case 22:
1723             return "nd";
1724         case 3:
1725         case 23:
1726             return "rd";
1727         default:
1728             return "th";
1729     }
1730 };
1731
1732 // private
1733 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1734
1735 /**
1736  * An array of textual month names.
1737  * Override these values for international dates, for example...
1738  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1739  * @type Array
1740  * @static
1741  */
1742 Date.monthNames =
1743    ["January",
1744     "February",
1745     "March",
1746     "April",
1747     "May",
1748     "June",
1749     "July",
1750     "August",
1751     "September",
1752     "October",
1753     "November",
1754     "December"];
1755
1756 /**
1757  * An array of textual day names.
1758  * Override these values for international dates, for example...
1759  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1760  * @type Array
1761  * @static
1762  */
1763 Date.dayNames =
1764    ["Sunday",
1765     "Monday",
1766     "Tuesday",
1767     "Wednesday",
1768     "Thursday",
1769     "Friday",
1770     "Saturday"];
1771
1772 // private
1773 Date.y2kYear = 50;
1774 // private
1775 Date.monthNumbers = {
1776     Jan:0,
1777     Feb:1,
1778     Mar:2,
1779     Apr:3,
1780     May:4,
1781     Jun:5,
1782     Jul:6,
1783     Aug:7,
1784     Sep:8,
1785     Oct:9,
1786     Nov:10,
1787     Dec:11};
1788
1789 /**
1790  * Creates and returns a new Date instance with the exact same date value as the called instance.
1791  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1792  * variable will also be changed.  When the intention is to create a new variable that will not
1793  * modify the original instance, you should create a clone.
1794  *
1795  * Example of correctly cloning a date:
1796  * <pre><code>
1797 //wrong way:
1798 var orig = new Date('10/1/2006');
1799 var copy = orig;
1800 copy.setDate(5);
1801 document.write(orig);  //returns 'Thu Oct 05 2006'!
1802
1803 //correct way:
1804 var orig = new Date('10/1/2006');
1805 var copy = orig.clone();
1806 copy.setDate(5);
1807 document.write(orig);  //returns 'Thu Oct 01 2006'
1808 </code></pre>
1809  * @return {Date} The new Date instance
1810  */
1811 Date.prototype.clone = function() {
1812         return new Date(this.getTime());
1813 };
1814
1815 /**
1816  * Clears any time information from this date
1817  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1818  @return {Date} this or the clone
1819  */
1820 Date.prototype.clearTime = function(clone){
1821     if(clone){
1822         return this.clone().clearTime();
1823     }
1824     this.setHours(0);
1825     this.setMinutes(0);
1826     this.setSeconds(0);
1827     this.setMilliseconds(0);
1828     return this;
1829 };
1830
1831 // private
1832 // safari setMonth is broken -- check that this is only donw once...
1833 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1834     Date.brokenSetMonth = Date.prototype.setMonth;
1835         Date.prototype.setMonth = function(num){
1836                 if(num <= -1){
1837                         var n = Math.ceil(-num);
1838                         var back_year = Math.ceil(n/12);
1839                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1840                         this.setFullYear(this.getFullYear() - back_year);
1841                         return Date.brokenSetMonth.call(this, month);
1842                 } else {
1843                         return Date.brokenSetMonth.apply(this, arguments);
1844                 }
1845         };
1846 }
1847
1848 /** Date interval constant 
1849 * @static 
1850 * @type String */
1851 Date.MILLI = "ms";
1852 /** Date interval constant 
1853 * @static 
1854 * @type String */
1855 Date.SECOND = "s";
1856 /** Date interval constant 
1857 * @static 
1858 * @type String */
1859 Date.MINUTE = "mi";
1860 /** Date interval constant 
1861 * @static 
1862 * @type String */
1863 Date.HOUR = "h";
1864 /** Date interval constant 
1865 * @static 
1866 * @type String */
1867 Date.DAY = "d";
1868 /** Date interval constant 
1869 * @static 
1870 * @type String */
1871 Date.MONTH = "mo";
1872 /** Date interval constant 
1873 * @static 
1874 * @type String */
1875 Date.YEAR = "y";
1876
1877 /**
1878  * Provides a convenient method of performing basic date arithmetic.  This method
1879  * does not modify the Date instance being called - it creates and returns
1880  * a new Date instance containing the resulting date value.
1881  *
1882  * Examples:
1883  * <pre><code>
1884 //Basic usage:
1885 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1886 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1887
1888 //Negative values will subtract correctly:
1889 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1890 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1891
1892 //You can even chain several calls together in one line!
1893 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1894 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1895  </code></pre>
1896  *
1897  * @param {String} interval   A valid date interval enum value
1898  * @param {Number} value      The amount to add to the current date
1899  * @return {Date} The new Date instance
1900  */
1901 Date.prototype.add = function(interval, value){
1902   var d = this.clone();
1903   if (!interval || value === 0) { return d; }
1904   switch(interval.toLowerCase()){
1905     case Date.MILLI:
1906       d.setMilliseconds(this.getMilliseconds() + value);
1907       break;
1908     case Date.SECOND:
1909       d.setSeconds(this.getSeconds() + value);
1910       break;
1911     case Date.MINUTE:
1912       d.setMinutes(this.getMinutes() + value);
1913       break;
1914     case Date.HOUR:
1915       d.setHours(this.getHours() + value);
1916       break;
1917     case Date.DAY:
1918       d.setDate(this.getDate() + value);
1919       break;
1920     case Date.MONTH:
1921       var day = this.getDate();
1922       if(day > 28){
1923           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1924       }
1925       d.setDate(day);
1926       d.setMonth(this.getMonth() + value);
1927       break;
1928     case Date.YEAR:
1929       d.setFullYear(this.getFullYear() + value);
1930       break;
1931   }
1932   return d;
1933 };
1934 /**
1935  * @class Roo.lib.Dom
1936  * @licence LGPL
1937  * @static
1938  * 
1939  * Dom utils (from YIU afaik)
1940  *
1941  * 
1942  **/
1943 Roo.lib.Dom = {
1944     /**
1945      * Get the view width
1946      * @param {Boolean} full True will get the full document, otherwise it's the view width
1947      * @return {Number} The width
1948      */
1949      
1950     getViewWidth : function(full) {
1951         return full ? this.getDocumentWidth() : this.getViewportWidth();
1952     },
1953     /**
1954      * Get the view height
1955      * @param {Boolean} full True will get the full document, otherwise it's the view height
1956      * @return {Number} The height
1957      */
1958     getViewHeight : function(full) {
1959         return full ? this.getDocumentHeight() : this.getViewportHeight();
1960     },
1961     /**
1962      * Get the Full Document height 
1963      * @return {Number} The height
1964      */
1965     getDocumentHeight: function() {
1966         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1967         return Math.max(scrollHeight, this.getViewportHeight());
1968     },
1969     /**
1970      * Get the Full Document width
1971      * @return {Number} The width
1972      */
1973     getDocumentWidth: function() {
1974         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1975         return Math.max(scrollWidth, this.getViewportWidth());
1976     },
1977     /**
1978      * Get the Window Viewport height
1979      * @return {Number} The height
1980      */
1981     getViewportHeight: function() {
1982         var height = self.innerHeight;
1983         var mode = document.compatMode;
1984
1985         if ((mode || Roo.isIE) && !Roo.isOpera) {
1986             height = (mode == "CSS1Compat") ?
1987                      document.documentElement.clientHeight :
1988                      document.body.clientHeight;
1989         }
1990
1991         return height;
1992     },
1993     /**
1994      * Get the Window Viewport width
1995      * @return {Number} The width
1996      */
1997     getViewportWidth: function() {
1998         var width = self.innerWidth;
1999         var mode = document.compatMode;
2000
2001         if (mode || Roo.isIE) {
2002             width = (mode == "CSS1Compat") ?
2003                     document.documentElement.clientWidth :
2004                     document.body.clientWidth;
2005         }
2006         return width;
2007     },
2008
2009     isAncestor : function(p, c) {
2010         p = Roo.getDom(p);
2011         c = Roo.getDom(c);
2012         if (!p || !c) {
2013             return false;
2014         }
2015
2016         if (p.contains && !Roo.isSafari) {
2017             return p.contains(c);
2018         } else if (p.compareDocumentPosition) {
2019             return !!(p.compareDocumentPosition(c) & 16);
2020         } else {
2021             var parent = c.parentNode;
2022             while (parent) {
2023                 if (parent == p) {
2024                     return true;
2025                 }
2026                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
2027                     return false;
2028                 }
2029                 parent = parent.parentNode;
2030             }
2031             return false;
2032         }
2033     },
2034
2035     getRegion : function(el) {
2036         return Roo.lib.Region.getRegion(el);
2037     },
2038
2039     getY : function(el) {
2040         return this.getXY(el)[1];
2041     },
2042
2043     getX : function(el) {
2044         return this.getXY(el)[0];
2045     },
2046
2047     getXY : function(el) {
2048         var p, pe, b, scroll, bd = document.body;
2049         el = Roo.getDom(el);
2050         var fly = Roo.lib.AnimBase.fly;
2051         if (el.getBoundingClientRect) {
2052             b = el.getBoundingClientRect();
2053             scroll = fly(document).getScroll();
2054             return [b.left + scroll.left, b.top + scroll.top];
2055         }
2056         var x = 0, y = 0;
2057
2058         p = el;
2059
2060         var hasAbsolute = fly(el).getStyle("position") == "absolute";
2061
2062         while (p) {
2063
2064             x += p.offsetLeft;
2065             y += p.offsetTop;
2066
2067             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2068                 hasAbsolute = true;
2069             }
2070
2071             if (Roo.isGecko) {
2072                 pe = fly(p);
2073
2074                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2075                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2076
2077
2078                 x += bl;
2079                 y += bt;
2080
2081
2082                 if (p != el && pe.getStyle('overflow') != 'visible') {
2083                     x += bl;
2084                     y += bt;
2085                 }
2086             }
2087             p = p.offsetParent;
2088         }
2089
2090         if (Roo.isSafari && hasAbsolute) {
2091             x -= bd.offsetLeft;
2092             y -= bd.offsetTop;
2093         }
2094
2095         if (Roo.isGecko && !hasAbsolute) {
2096             var dbd = fly(bd);
2097             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2098             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2099         }
2100
2101         p = el.parentNode;
2102         while (p && p != bd) {
2103             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2104                 x -= p.scrollLeft;
2105                 y -= p.scrollTop;
2106             }
2107             p = p.parentNode;
2108         }
2109         return [x, y];
2110     },
2111  
2112   
2113
2114
2115     setXY : function(el, xy) {
2116         el = Roo.fly(el, '_setXY');
2117         el.position();
2118         var pts = el.translatePoints(xy);
2119         if (xy[0] !== false) {
2120             el.dom.style.left = pts.left + "px";
2121         }
2122         if (xy[1] !== false) {
2123             el.dom.style.top = pts.top + "px";
2124         }
2125     },
2126
2127     setX : function(el, x) {
2128         this.setXY(el, [x, false]);
2129     },
2130
2131     setY : function(el, y) {
2132         this.setXY(el, [false, y]);
2133     }
2134 };
2135 /*
2136  * Portions of this file are based on pieces of Yahoo User Interface Library
2137  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2138  * YUI licensed under the BSD License:
2139  * http://developer.yahoo.net/yui/license.txt
2140  * <script type="text/javascript">
2141  *
2142  */
2143
2144 Roo.lib.Event = function() {
2145     var loadComplete = false;
2146     var listeners = [];
2147     var unloadListeners = [];
2148     var retryCount = 0;
2149     var onAvailStack = [];
2150     var counter = 0;
2151     var lastError = null;
2152
2153     return {
2154         POLL_RETRYS: 200,
2155         POLL_INTERVAL: 20,
2156         EL: 0,
2157         TYPE: 1,
2158         FN: 2,
2159         WFN: 3,
2160         OBJ: 3,
2161         ADJ_SCOPE: 4,
2162         _interval: null,
2163
2164         startInterval: function() {
2165             if (!this._interval) {
2166                 var self = this;
2167                 var callback = function() {
2168                     self._tryPreloadAttach();
2169                 };
2170                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2171
2172             }
2173         },
2174
2175         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2176             onAvailStack.push({ id:         p_id,
2177                 fn:         p_fn,
2178                 obj:        p_obj,
2179                 override:   p_override,
2180                 checkReady: false    });
2181
2182             retryCount = this.POLL_RETRYS;
2183             this.startInterval();
2184         },
2185
2186
2187         addListener: function(el, eventName, fn) {
2188             el = Roo.getDom(el);
2189             if (!el || !fn) {
2190                 return false;
2191             }
2192
2193             if ("unload" == eventName) {
2194                 unloadListeners[unloadListeners.length] =
2195                 [el, eventName, fn];
2196                 return true;
2197             }
2198
2199             var wrappedFn = function(e) {
2200                 return fn(Roo.lib.Event.getEvent(e));
2201             };
2202
2203             var li = [el, eventName, fn, wrappedFn];
2204
2205             var index = listeners.length;
2206             listeners[index] = li;
2207
2208             this.doAdd(el, eventName, wrappedFn, false);
2209             return true;
2210
2211         },
2212
2213
2214         removeListener: function(el, eventName, fn) {
2215             var i, len;
2216
2217             el = Roo.getDom(el);
2218
2219             if(!fn) {
2220                 return this.purgeElement(el, false, eventName);
2221             }
2222
2223
2224             if ("unload" == eventName) {
2225
2226                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2227                     var li = unloadListeners[i];
2228                     if (li &&
2229                         li[0] == el &&
2230                         li[1] == eventName &&
2231                         li[2] == fn) {
2232                         unloadListeners.splice(i, 1);
2233                         return true;
2234                     }
2235                 }
2236
2237                 return false;
2238             }
2239
2240             var cacheItem = null;
2241
2242
2243             var index = arguments[3];
2244
2245             if ("undefined" == typeof index) {
2246                 index = this._getCacheIndex(el, eventName, fn);
2247             }
2248
2249             if (index >= 0) {
2250                 cacheItem = listeners[index];
2251             }
2252
2253             if (!el || !cacheItem) {
2254                 return false;
2255             }
2256
2257             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2258
2259             delete listeners[index][this.WFN];
2260             delete listeners[index][this.FN];
2261             listeners.splice(index, 1);
2262
2263             return true;
2264
2265         },
2266
2267
2268         getTarget: function(ev, resolveTextNode) {
2269             ev = ev.browserEvent || ev;
2270             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2271             var t = ev.target || ev.srcElement;
2272             return this.resolveTextNode(t);
2273         },
2274
2275
2276         resolveTextNode: function(node) {
2277             if (Roo.isSafari && node && 3 == node.nodeType) {
2278                 return node.parentNode;
2279             } else {
2280                 return node;
2281             }
2282         },
2283
2284
2285         getPageX: function(ev) {
2286             ev = ev.browserEvent || ev;
2287             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2288             var x = ev.pageX;
2289             if (!x && 0 !== x) {
2290                 x = ev.clientX || 0;
2291
2292                 if (Roo.isIE) {
2293                     x += this.getScroll()[1];
2294                 }
2295             }
2296
2297             return x;
2298         },
2299
2300
2301         getPageY: function(ev) {
2302             ev = ev.browserEvent || ev;
2303             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2304             var y = ev.pageY;
2305             if (!y && 0 !== y) {
2306                 y = ev.clientY || 0;
2307
2308                 if (Roo.isIE) {
2309                     y += this.getScroll()[0];
2310                 }
2311             }
2312
2313
2314             return y;
2315         },
2316
2317
2318         getXY: function(ev) {
2319             ev = ev.browserEvent || ev;
2320             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2321             return [this.getPageX(ev), this.getPageY(ev)];
2322         },
2323
2324
2325         getRelatedTarget: function(ev) {
2326             ev = ev.browserEvent || ev;
2327             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2328             var t = ev.relatedTarget;
2329             if (!t) {
2330                 if (ev.type == "mouseout") {
2331                     t = ev.toElement;
2332                 } else if (ev.type == "mouseover") {
2333                     t = ev.fromElement;
2334                 }
2335             }
2336
2337             return this.resolveTextNode(t);
2338         },
2339
2340
2341         getTime: function(ev) {
2342             ev = ev.browserEvent || ev;
2343             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2344             if (!ev.time) {
2345                 var t = new Date().getTime();
2346                 try {
2347                     ev.time = t;
2348                 } catch(ex) {
2349                     this.lastError = ex;
2350                     return t;
2351                 }
2352             }
2353
2354             return ev.time;
2355         },
2356
2357
2358         stopEvent: function(ev) {
2359             this.stopPropagation(ev);
2360             this.preventDefault(ev);
2361         },
2362
2363
2364         stopPropagation: function(ev) {
2365             ev = ev.browserEvent || ev;
2366             if (ev.stopPropagation) {
2367                 ev.stopPropagation();
2368             } else {
2369                 ev.cancelBubble = true;
2370             }
2371         },
2372
2373
2374         preventDefault: function(ev) {
2375             ev = ev.browserEvent || ev;
2376             if(ev.preventDefault) {
2377                 ev.preventDefault();
2378             } else {
2379                 ev.returnValue = false;
2380             }
2381         },
2382
2383
2384         getEvent: function(e) {
2385             var ev = e || window.event;
2386             if (!ev) {
2387                 var c = this.getEvent.caller;
2388                 while (c) {
2389                     ev = c.arguments[0];
2390                     if (ev && Event == ev.constructor) {
2391                         break;
2392                     }
2393                     c = c.caller;
2394                 }
2395             }
2396             return ev;
2397         },
2398
2399
2400         getCharCode: function(ev) {
2401             ev = ev.browserEvent || ev;
2402             return ev.charCode || ev.keyCode || 0;
2403         },
2404
2405
2406         _getCacheIndex: function(el, eventName, fn) {
2407             for (var i = 0,len = listeners.length; i < len; ++i) {
2408                 var li = listeners[i];
2409                 if (li &&
2410                     li[this.FN] == fn &&
2411                     li[this.EL] == el &&
2412                     li[this.TYPE] == eventName) {
2413                     return i;
2414                 }
2415             }
2416
2417             return -1;
2418         },
2419
2420
2421         elCache: {},
2422
2423
2424         getEl: function(id) {
2425             return document.getElementById(id);
2426         },
2427
2428
2429         clearCache: function() {
2430         },
2431
2432
2433         _load: function(e) {
2434             loadComplete = true;
2435             var EU = Roo.lib.Event;
2436
2437
2438             if (Roo.isIE) {
2439                 EU.doRemove(window, "load", EU._load);
2440             }
2441         },
2442
2443
2444         _tryPreloadAttach: function() {
2445
2446             if (this.locked) {
2447                 return false;
2448             }
2449
2450             this.locked = true;
2451
2452
2453             var tryAgain = !loadComplete;
2454             if (!tryAgain) {
2455                 tryAgain = (retryCount > 0);
2456             }
2457
2458
2459             var notAvail = [];
2460             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2461                 var item = onAvailStack[i];
2462                 if (item) {
2463                     var el = this.getEl(item.id);
2464
2465                     if (el) {
2466                         if (!item.checkReady ||
2467                             loadComplete ||
2468                             el.nextSibling ||
2469                             (document && document.body)) {
2470
2471                             var scope = el;
2472                             if (item.override) {
2473                                 if (item.override === true) {
2474                                     scope = item.obj;
2475                                 } else {
2476                                     scope = item.override;
2477                                 }
2478                             }
2479                             item.fn.call(scope, item.obj);
2480                             onAvailStack[i] = null;
2481                         }
2482                     } else {
2483                         notAvail.push(item);
2484                     }
2485                 }
2486             }
2487
2488             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2489
2490             if (tryAgain) {
2491
2492                 this.startInterval();
2493             } else {
2494                 clearInterval(this._interval);
2495                 this._interval = null;
2496             }
2497
2498             this.locked = false;
2499
2500             return true;
2501
2502         },
2503
2504
2505         purgeElement: function(el, recurse, eventName) {
2506             var elListeners = this.getListeners(el, eventName);
2507             if (elListeners) {
2508                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2509                     var l = elListeners[i];
2510                     this.removeListener(el, l.type, l.fn);
2511                 }
2512             }
2513
2514             if (recurse && el && el.childNodes) {
2515                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2516                     this.purgeElement(el.childNodes[i], recurse, eventName);
2517                 }
2518             }
2519         },
2520
2521
2522         getListeners: function(el, eventName) {
2523             var results = [], searchLists;
2524             if (!eventName) {
2525                 searchLists = [listeners, unloadListeners];
2526             } else if (eventName == "unload") {
2527                 searchLists = [unloadListeners];
2528             } else {
2529                 searchLists = [listeners];
2530             }
2531
2532             for (var j = 0; j < searchLists.length; ++j) {
2533                 var searchList = searchLists[j];
2534                 if (searchList && searchList.length > 0) {
2535                     for (var i = 0,len = searchList.length; i < len; ++i) {
2536                         var l = searchList[i];
2537                         if (l && l[this.EL] === el &&
2538                             (!eventName || eventName === l[this.TYPE])) {
2539                             results.push({
2540                                 type:   l[this.TYPE],
2541                                 fn:     l[this.FN],
2542                                 obj:    l[this.OBJ],
2543                                 adjust: l[this.ADJ_SCOPE],
2544                                 index:  i
2545                             });
2546                         }
2547                     }
2548                 }
2549             }
2550
2551             return (results.length) ? results : null;
2552         },
2553
2554
2555         _unload: function(e) {
2556
2557             var EU = Roo.lib.Event, i, j, l, len, index;
2558
2559             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2560                 l = unloadListeners[i];
2561                 if (l) {
2562                     var scope = window;
2563                     if (l[EU.ADJ_SCOPE]) {
2564                         if (l[EU.ADJ_SCOPE] === true) {
2565                             scope = l[EU.OBJ];
2566                         } else {
2567                             scope = l[EU.ADJ_SCOPE];
2568                         }
2569                     }
2570                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2571                     unloadListeners[i] = null;
2572                     l = null;
2573                     scope = null;
2574                 }
2575             }
2576
2577             unloadListeners = null;
2578
2579             if (listeners && listeners.length > 0) {
2580                 j = listeners.length;
2581                 while (j) {
2582                     index = j - 1;
2583                     l = listeners[index];
2584                     if (l) {
2585                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2586                                 l[EU.FN], index);
2587                     }
2588                     j = j - 1;
2589                 }
2590                 l = null;
2591
2592                 EU.clearCache();
2593             }
2594
2595             EU.doRemove(window, "unload", EU._unload);
2596
2597         },
2598
2599
2600         getScroll: function() {
2601             var dd = document.documentElement, db = document.body;
2602             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2603                 return [dd.scrollTop, dd.scrollLeft];
2604             } else if (db) {
2605                 return [db.scrollTop, db.scrollLeft];
2606             } else {
2607                 return [0, 0];
2608             }
2609         },
2610
2611
2612         doAdd: function () {
2613             if (window.addEventListener) {
2614                 return function(el, eventName, fn, capture) {
2615                     el.addEventListener(eventName, fn, (capture));
2616                 };
2617             } else if (window.attachEvent) {
2618                 return function(el, eventName, fn, capture) {
2619                     el.attachEvent("on" + eventName, fn);
2620                 };
2621             } else {
2622                 return function() {
2623                 };
2624             }
2625         }(),
2626
2627
2628         doRemove: function() {
2629             if (window.removeEventListener) {
2630                 return function (el, eventName, fn, capture) {
2631                     el.removeEventListener(eventName, fn, (capture));
2632                 };
2633             } else if (window.detachEvent) {
2634                 return function (el, eventName, fn) {
2635                     el.detachEvent("on" + eventName, fn);
2636                 };
2637             } else {
2638                 return function() {
2639                 };
2640             }
2641         }()
2642     };
2643     
2644 }();
2645 (function() {     
2646    
2647     var E = Roo.lib.Event;
2648     E.on = E.addListener;
2649     E.un = E.removeListener;
2650
2651     if (document && document.body) {
2652         E._load();
2653     } else {
2654         E.doAdd(window, "load", E._load);
2655     }
2656     E.doAdd(window, "unload", E._unload);
2657     E._tryPreloadAttach();
2658 })();
2659
2660  
2661
2662 (function() {
2663     /**
2664      * @class Roo.lib.Ajax
2665      *
2666      * provide a simple Ajax request utility functions
2667      * 
2668      * Portions of this file are based on pieces of Yahoo User Interface Library
2669     * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2670     * YUI licensed under the BSD License:
2671     * http://developer.yahoo.net/yui/license.txt
2672     * <script type="text/javascript">
2673     *
2674      *
2675      */
2676     Roo.lib.Ajax = {
2677         /**
2678          * @static 
2679          */
2680         request : function(method, uri, cb, data, options) {
2681             if(options){
2682                 var hs = options.headers;
2683                 if(hs){
2684                     for(var h in hs){
2685                         if(hs.hasOwnProperty(h)){
2686                             this.initHeader(h, hs[h], false);
2687                         }
2688                     }
2689                 }
2690                 if(options.xmlData){
2691                     this.initHeader('Content-Type', 'text/xml', false);
2692                     method = 'POST';
2693                     data = options.xmlData;
2694                 }
2695             }
2696
2697             return this.asyncRequest(method, uri, cb, data);
2698         },
2699         /**
2700          * serialize a form
2701          *
2702          * @static
2703          * @param {DomForm} form element
2704          * @return {String} urlencode form output.
2705          */
2706         serializeForm : function(form) {
2707             if(typeof form == 'string') {
2708                 form = (document.getElementById(form) || document.forms[form]);
2709             }
2710
2711             var el, name, val, disabled, data = '', hasSubmit = false;
2712             for (var i = 0; i < form.elements.length; i++) {
2713                 el = form.elements[i];
2714                 disabled = form.elements[i].disabled;
2715                 name = form.elements[i].name;
2716                 val = form.elements[i].value;
2717
2718                 if (!disabled && name){
2719                     switch (el.type)
2720                             {
2721                         case 'select-one':
2722                         case 'select-multiple':
2723                             for (var j = 0; j < el.options.length; j++) {
2724                                 if (el.options[j].selected) {
2725                                     if (Roo.isIE) {
2726                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2727                                     }
2728                                     else {
2729                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2730                                     }
2731                                 }
2732                             }
2733                             break;
2734                         case 'radio':
2735                         case 'checkbox':
2736                             if (el.checked) {
2737                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2738                             }
2739                             break;
2740                         case 'file':
2741
2742                         case undefined:
2743
2744                         case 'reset':
2745
2746                         case 'button':
2747
2748                             break;
2749                         case 'submit':
2750                             if(hasSubmit == false) {
2751                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2752                                 hasSubmit = true;
2753                             }
2754                             break;
2755                         default:
2756                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2757                             break;
2758                     }
2759                 }
2760             }
2761             data = data.substr(0, data.length - 1);
2762             return data;
2763         },
2764
2765         headers:{},
2766
2767         hasHeaders:false,
2768
2769         useDefaultHeader:true,
2770
2771         defaultPostHeader:'application/x-www-form-urlencoded',
2772
2773         useDefaultXhrHeader:true,
2774
2775         defaultXhrHeader:'XMLHttpRequest',
2776
2777         hasDefaultHeaders:true,
2778
2779         defaultHeaders:{},
2780
2781         poll:{},
2782
2783         timeout:{},
2784
2785         pollInterval:50,
2786
2787         transactionId:0,
2788
2789         setProgId:function(id)
2790         {
2791             this.activeX.unshift(id);
2792         },
2793
2794         setDefaultPostHeader:function(b)
2795         {
2796             this.useDefaultHeader = b;
2797         },
2798
2799         setDefaultXhrHeader:function(b)
2800         {
2801             this.useDefaultXhrHeader = b;
2802         },
2803
2804         setPollingInterval:function(i)
2805         {
2806             if (typeof i == 'number' && isFinite(i)) {
2807                 this.pollInterval = i;
2808             }
2809         },
2810
2811         createXhrObject:function(transactionId)
2812         {
2813             var obj,http;
2814             try
2815             {
2816
2817                 http = new XMLHttpRequest();
2818
2819                 obj = { conn:http, tId:transactionId };
2820             }
2821             catch(e)
2822             {
2823                 for (var i = 0; i < this.activeX.length; ++i) {
2824                     try
2825                     {
2826
2827                         http = new ActiveXObject(this.activeX[i]);
2828
2829                         obj = { conn:http, tId:transactionId };
2830                         break;
2831                     }
2832                     catch(e) {
2833                     }
2834                 }
2835             }
2836             finally
2837             {
2838                 return obj;
2839             }
2840         },
2841
2842         getConnectionObject:function()
2843         {
2844             var o;
2845             var tId = this.transactionId;
2846
2847             try
2848             {
2849                 o = this.createXhrObject(tId);
2850                 if (o) {
2851                     this.transactionId++;
2852                 }
2853             }
2854             catch(e) {
2855             }
2856             finally
2857             {
2858                 return o;
2859             }
2860         },
2861
2862         asyncRequest:function(method, uri, callback, postData)
2863         {
2864             var o = this.getConnectionObject();
2865
2866             if (!o) {
2867                 return null;
2868             }
2869             else {
2870                 o.conn.open(method, uri, true);
2871
2872                 if (this.useDefaultXhrHeader) {
2873                     if (!this.defaultHeaders['X-Requested-With']) {
2874                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2875                     }
2876                 }
2877
2878                 if(postData && this.useDefaultHeader){
2879                     this.initHeader('Content-Type', this.defaultPostHeader);
2880                 }
2881
2882                  if (this.hasDefaultHeaders || this.hasHeaders) {
2883                     this.setHeader(o);
2884                 }
2885
2886                 this.handleReadyState(o, callback);
2887                 o.conn.send(postData || null);
2888
2889                 return o;
2890             }
2891         },
2892
2893         handleReadyState:function(o, callback)
2894         {
2895             var oConn = this;
2896
2897             if (callback && callback.timeout) {
2898                 
2899                 this.timeout[o.tId] = window.setTimeout(function() {
2900                     oConn.abort(o, callback, true);
2901                 }, callback.timeout);
2902             }
2903
2904             this.poll[o.tId] = window.setInterval(
2905                     function() {
2906                         if (o.conn && o.conn.readyState == 4) {
2907                             window.clearInterval(oConn.poll[o.tId]);
2908                             delete oConn.poll[o.tId];
2909
2910                             if(callback && callback.timeout) {
2911                                 window.clearTimeout(oConn.timeout[o.tId]);
2912                                 delete oConn.timeout[o.tId];
2913                             }
2914
2915                             oConn.handleTransactionResponse(o, callback);
2916                         }
2917                     }
2918                     , this.pollInterval);
2919         },
2920
2921         handleTransactionResponse:function(o, callback, isAbort)
2922         {
2923
2924             if (!callback) {
2925                 this.releaseObject(o);
2926                 return;
2927             }
2928
2929             var httpStatus, responseObject;
2930
2931             try
2932             {
2933                 if (o.conn.status !== undefined && o.conn.status != 0) {
2934                     httpStatus = o.conn.status;
2935                 }
2936                 else {
2937                     httpStatus = 13030;
2938                 }
2939             }
2940             catch(e) {
2941
2942
2943                 httpStatus = 13030;
2944             }
2945
2946             if (httpStatus >= 200 && httpStatus < 300) {
2947                 responseObject = this.createResponseObject(o, callback.argument);
2948                 if (callback.success) {
2949                     if (!callback.scope) {
2950                         callback.success(responseObject);
2951                     }
2952                     else {
2953
2954
2955                         callback.success.apply(callback.scope, [responseObject]);
2956                     }
2957                 }
2958             }
2959             else {
2960                 switch (httpStatus) {
2961
2962                     case 12002:
2963                     case 12029:
2964                     case 12030:
2965                     case 12031:
2966                     case 12152:
2967                     case 13030:
2968                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2969                         if (callback.failure) {
2970                             if (!callback.scope) {
2971                                 callback.failure(responseObject);
2972                             }
2973                             else {
2974                                 callback.failure.apply(callback.scope, [responseObject]);
2975                             }
2976                         }
2977                         break;
2978                     default:
2979                         responseObject = this.createResponseObject(o, callback.argument);
2980                         if (callback.failure) {
2981                             if (!callback.scope) {
2982                                 callback.failure(responseObject);
2983                             }
2984                             else {
2985                                 callback.failure.apply(callback.scope, [responseObject]);
2986                             }
2987                         }
2988                 }
2989             }
2990
2991             this.releaseObject(o);
2992             responseObject = null;
2993         },
2994
2995         createResponseObject:function(o, callbackArg)
2996         {
2997             var obj = {};
2998             var headerObj = {};
2999
3000             try
3001             {
3002                 var headerStr = o.conn.getAllResponseHeaders();
3003                 var header = headerStr.split('\n');
3004                 for (var i = 0; i < header.length; i++) {
3005                     var delimitPos = header[i].indexOf(':');
3006                     if (delimitPos != -1) {
3007                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
3008                     }
3009                 }
3010             }
3011             catch(e) {
3012             }
3013
3014             obj.tId = o.tId;
3015             obj.status = o.conn.status;
3016             obj.statusText = o.conn.statusText;
3017             obj.getResponseHeader = headerObj;
3018             obj.getAllResponseHeaders = headerStr;
3019             obj.responseText = o.conn.responseText;
3020             obj.responseXML = o.conn.responseXML;
3021
3022             if (typeof callbackArg !== undefined) {
3023                 obj.argument = callbackArg;
3024             }
3025
3026             return obj;
3027         },
3028
3029         createExceptionObject:function(tId, callbackArg, isAbort)
3030         {
3031             var COMM_CODE = 0;
3032             var COMM_ERROR = 'communication failure';
3033             var ABORT_CODE = -1;
3034             var ABORT_ERROR = 'transaction aborted';
3035
3036             var obj = {};
3037
3038             obj.tId = tId;
3039             if (isAbort) {
3040                 obj.status = ABORT_CODE;
3041                 obj.statusText = ABORT_ERROR;
3042             }
3043             else {
3044                 obj.status = COMM_CODE;
3045                 obj.statusText = COMM_ERROR;
3046             }
3047
3048             if (callbackArg) {
3049                 obj.argument = callbackArg;
3050             }
3051
3052             return obj;
3053         },
3054
3055         initHeader:function(label, value, isDefault)
3056         {
3057             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3058
3059             if (headerObj[label] === undefined) {
3060                 headerObj[label] = value;
3061             }
3062             else {
3063
3064
3065                 headerObj[label] = value + "," + headerObj[label];
3066             }
3067
3068             if (isDefault) {
3069                 this.hasDefaultHeaders = true;
3070             }
3071             else {
3072                 this.hasHeaders = true;
3073             }
3074         },
3075
3076
3077         setHeader:function(o)
3078         {
3079             if (this.hasDefaultHeaders) {
3080                 for (var prop in this.defaultHeaders) {
3081                     if (this.defaultHeaders.hasOwnProperty(prop)) {
3082                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3083                     }
3084                 }
3085             }
3086
3087             if (this.hasHeaders) {
3088                 for (var prop in this.headers) {
3089                     if (this.headers.hasOwnProperty(prop)) {
3090                         o.conn.setRequestHeader(prop, this.headers[prop]);
3091                     }
3092                 }
3093                 this.headers = {};
3094                 this.hasHeaders = false;
3095             }
3096         },
3097
3098         resetDefaultHeaders:function() {
3099             delete this.defaultHeaders;
3100             this.defaultHeaders = {};
3101             this.hasDefaultHeaders = false;
3102         },
3103
3104         abort:function(o, callback, isTimeout)
3105         {
3106             if(this.isCallInProgress(o)) {
3107                 o.conn.abort();
3108                 window.clearInterval(this.poll[o.tId]);
3109                 delete this.poll[o.tId];
3110                 if (isTimeout) {
3111                     delete this.timeout[o.tId];
3112                 }
3113
3114                 this.handleTransactionResponse(o, callback, true);
3115
3116                 return true;
3117             }
3118             else {
3119                 return false;
3120             }
3121         },
3122
3123
3124         isCallInProgress:function(o)
3125         {
3126             if (o && o.conn) {
3127                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3128             }
3129             else {
3130
3131                 return false;
3132             }
3133         },
3134
3135
3136         releaseObject:function(o)
3137         {
3138
3139             o.conn = null;
3140
3141             o = null;
3142         },
3143
3144         activeX:[
3145         'MSXML2.XMLHTTP.3.0',
3146         'MSXML2.XMLHTTP',
3147         'Microsoft.XMLHTTP'
3148         ]
3149
3150
3151     };
3152 })();/*
3153  * Portions of this file are based on pieces of Yahoo User Interface Library
3154  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3155  * YUI licensed under the BSD License:
3156  * http://developer.yahoo.net/yui/license.txt
3157  * <script type="text/javascript">
3158  *
3159  */
3160
3161 Roo.lib.Region = function(t, r, b, l) {
3162     this.top = t;
3163     this[1] = t;
3164     this.right = r;
3165     this.bottom = b;
3166     this.left = l;
3167     this[0] = l;
3168 };
3169
3170
3171 Roo.lib.Region.prototype = {
3172     contains : function(region) {
3173         return ( region.left >= this.left &&
3174                  region.right <= this.right &&
3175                  region.top >= this.top &&
3176                  region.bottom <= this.bottom    );
3177
3178     },
3179
3180     getArea : function() {
3181         return ( (this.bottom - this.top) * (this.right - this.left) );
3182     },
3183
3184     intersect : function(region) {
3185         var t = Math.max(this.top, region.top);
3186         var r = Math.min(this.right, region.right);
3187         var b = Math.min(this.bottom, region.bottom);
3188         var l = Math.max(this.left, region.left);
3189
3190         if (b >= t && r >= l) {
3191             return new Roo.lib.Region(t, r, b, l);
3192         } else {
3193             return null;
3194         }
3195     },
3196     union : function(region) {
3197         var t = Math.min(this.top, region.top);
3198         var r = Math.max(this.right, region.right);
3199         var b = Math.max(this.bottom, region.bottom);
3200         var l = Math.min(this.left, region.left);
3201
3202         return new Roo.lib.Region(t, r, b, l);
3203     },
3204
3205     adjust : function(t, l, b, r) {
3206         this.top += t;
3207         this.left += l;
3208         this.right += r;
3209         this.bottom += b;
3210         return this;
3211     }
3212 };
3213
3214 Roo.lib.Region.getRegion = function(el) {
3215     var p = Roo.lib.Dom.getXY(el);
3216
3217     var t = p[1];
3218     var r = p[0] + el.offsetWidth;
3219     var b = p[1] + el.offsetHeight;
3220     var l = p[0];
3221
3222     return new Roo.lib.Region(t, r, b, l);
3223 };
3224 /*
3225  * Portions of this file are based on pieces of Yahoo User Interface Library
3226  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3227  * YUI licensed under the BSD License:
3228  * http://developer.yahoo.net/yui/license.txt
3229  * <script type="text/javascript">
3230  *
3231  */
3232 //@@dep Roo.lib.Region
3233
3234
3235 Roo.lib.Point = function(x, y) {
3236     if (x instanceof Array) {
3237         y = x[1];
3238         x = x[0];
3239     }
3240     this.x = this.right = this.left = this[0] = x;
3241     this.y = this.top = this.bottom = this[1] = y;
3242 };
3243
3244 Roo.lib.Point.prototype = new Roo.lib.Region();
3245 /*
3246  * Portions of this file are based on pieces of Yahoo User Interface Library
3247  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3248  * YUI licensed under the BSD License:
3249  * http://developer.yahoo.net/yui/license.txt
3250  * <script type="text/javascript">
3251  *
3252  */
3253  
3254 (function() {   
3255
3256     Roo.lib.Anim = {
3257         scroll : function(el, args, duration, easing, cb, scope) {
3258             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3259         },
3260
3261         motion : function(el, args, duration, easing, cb, scope) {
3262             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3263         },
3264
3265         color : function(el, args, duration, easing, cb, scope) {
3266             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3267         },
3268
3269         run : function(el, args, duration, easing, cb, scope, type) {
3270             type = type || Roo.lib.AnimBase;
3271             if (typeof easing == "string") {
3272                 easing = Roo.lib.Easing[easing];
3273             }
3274             var anim = new type(el, args, duration, easing);
3275             anim.animateX(function() {
3276                 Roo.callback(cb, scope);
3277             });
3278             return anim;
3279         }
3280     };
3281 })();/*
3282  * Portions of this file are based on pieces of Yahoo User Interface Library
3283  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3284  * YUI licensed under the BSD License:
3285  * http://developer.yahoo.net/yui/license.txt
3286  * <script type="text/javascript">
3287  *
3288  */
3289
3290 (function() {    
3291     var libFlyweight;
3292     
3293     function fly(el) {
3294         if (!libFlyweight) {
3295             libFlyweight = new Roo.Element.Flyweight();
3296         }
3297         libFlyweight.dom = el;
3298         return libFlyweight;
3299     }
3300
3301     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3302     
3303    
3304     
3305     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3306         if (el) {
3307             this.init(el, attributes, duration, method);
3308         }
3309     };
3310
3311     Roo.lib.AnimBase.fly = fly;
3312     
3313     
3314     
3315     Roo.lib.AnimBase.prototype = {
3316
3317         toString: function() {
3318             var el = this.getEl();
3319             var id = el.id || el.tagName;
3320             return ("Anim " + id);
3321         },
3322
3323         patterns: {
3324             noNegatives:        /width|height|opacity|padding/i,
3325             offsetAttribute:  /^((width|height)|(top|left))$/,
3326             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3327             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3328         },
3329
3330
3331         doMethod: function(attr, start, end) {
3332             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3333         },
3334
3335
3336         setAttribute: function(attr, val, unit) {
3337             if (this.patterns.noNegatives.test(attr)) {
3338                 val = (val > 0) ? val : 0;
3339             }
3340
3341             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3342         },
3343
3344
3345         getAttribute: function(attr) {
3346             var el = this.getEl();
3347             var val = fly(el).getStyle(attr);
3348
3349             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3350                 return parseFloat(val);
3351             }
3352
3353             var a = this.patterns.offsetAttribute.exec(attr) || [];
3354             var pos = !!( a[3] );
3355             var box = !!( a[2] );
3356
3357
3358             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3359                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3360             } else {
3361                 val = 0;
3362             }
3363
3364             return val;
3365         },
3366
3367
3368         getDefaultUnit: function(attr) {
3369             if (this.patterns.defaultUnit.test(attr)) {
3370                 return 'px';
3371             }
3372
3373             return '';
3374         },
3375
3376         animateX : function(callback, scope) {
3377             var f = function() {
3378                 this.onComplete.removeListener(f);
3379                 if (typeof callback == "function") {
3380                     callback.call(scope || this, this);
3381                 }
3382             };
3383             this.onComplete.addListener(f, this);
3384             this.animate();
3385         },
3386
3387
3388         setRuntimeAttribute: function(attr) {
3389             var start;
3390             var end;
3391             var attributes = this.attributes;
3392
3393             this.runtimeAttributes[attr] = {};
3394
3395             var isset = function(prop) {
3396                 return (typeof prop !== 'undefined');
3397             };
3398
3399             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3400                 return false;
3401             }
3402
3403             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3404
3405
3406             if (isset(attributes[attr]['to'])) {
3407                 end = attributes[attr]['to'];
3408             } else if (isset(attributes[attr]['by'])) {
3409                 if (start.constructor == Array) {
3410                     end = [];
3411                     for (var i = 0, len = start.length; i < len; ++i) {
3412                         end[i] = start[i] + attributes[attr]['by'][i];
3413                     }
3414                 } else {
3415                     end = start + attributes[attr]['by'];
3416                 }
3417             }
3418
3419             this.runtimeAttributes[attr].start = start;
3420             this.runtimeAttributes[attr].end = end;
3421
3422
3423             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3424         },
3425
3426
3427         init: function(el, attributes, duration, method) {
3428
3429             var isAnimated = false;
3430
3431
3432             var startTime = null;
3433
3434
3435             var actualFrames = 0;
3436
3437
3438             el = Roo.getDom(el);
3439
3440
3441             this.attributes = attributes || {};
3442
3443
3444             this.duration = duration || 1;
3445
3446
3447             this.method = method || Roo.lib.Easing.easeNone;
3448
3449
3450             this.useSeconds = true;
3451
3452
3453             this.currentFrame = 0;
3454
3455
3456             this.totalFrames = Roo.lib.AnimMgr.fps;
3457
3458
3459             this.getEl = function() {
3460                 return el;
3461             };
3462
3463
3464             this.isAnimated = function() {
3465                 return isAnimated;
3466             };
3467
3468
3469             this.getStartTime = function() {
3470                 return startTime;
3471             };
3472
3473             this.runtimeAttributes = {};
3474
3475
3476             this.animate = function() {
3477                 if (this.isAnimated()) {
3478                     return false;
3479                 }
3480
3481                 this.currentFrame = 0;
3482
3483                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3484
3485                 Roo.lib.AnimMgr.registerElement(this);
3486             };
3487
3488
3489             this.stop = function(finish) {
3490                 if (finish) {
3491                     this.currentFrame = this.totalFrames;
3492                     this._onTween.fire();
3493                 }
3494                 Roo.lib.AnimMgr.stop(this);
3495             };
3496
3497             var onStart = function() {
3498                 this.onStart.fire();
3499
3500                 this.runtimeAttributes = {};
3501                 for (var attr in this.attributes) {
3502                     this.setRuntimeAttribute(attr);
3503                 }
3504
3505                 isAnimated = true;
3506                 actualFrames = 0;
3507                 startTime = new Date();
3508             };
3509
3510
3511             var onTween = function() {
3512                 var data = {
3513                     duration: new Date() - this.getStartTime(),
3514                     currentFrame: this.currentFrame
3515                 };
3516
3517                 data.toString = function() {
3518                     return (
3519                             'duration: ' + data.duration +
3520                             ', currentFrame: ' + data.currentFrame
3521                             );
3522                 };
3523
3524                 this.onTween.fire(data);
3525
3526                 var runtimeAttributes = this.runtimeAttributes;
3527
3528                 for (var attr in runtimeAttributes) {
3529                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3530                 }
3531
3532                 actualFrames += 1;
3533             };
3534
3535             var onComplete = function() {
3536                 var actual_duration = (new Date() - startTime) / 1000 ;
3537
3538                 var data = {
3539                     duration: actual_duration,
3540                     frames: actualFrames,
3541                     fps: actualFrames / actual_duration
3542                 };
3543
3544                 data.toString = function() {
3545                     return (
3546                             'duration: ' + data.duration +
3547                             ', frames: ' + data.frames +
3548                             ', fps: ' + data.fps
3549                             );
3550                 };
3551
3552                 isAnimated = false;
3553                 actualFrames = 0;
3554                 this.onComplete.fire(data);
3555             };
3556
3557
3558             this._onStart = new Roo.util.Event(this);
3559             this.onStart = new Roo.util.Event(this);
3560             this.onTween = new Roo.util.Event(this);
3561             this._onTween = new Roo.util.Event(this);
3562             this.onComplete = new Roo.util.Event(this);
3563             this._onComplete = new Roo.util.Event(this);
3564             this._onStart.addListener(onStart);
3565             this._onTween.addListener(onTween);
3566             this._onComplete.addListener(onComplete);
3567         }
3568     };
3569 })();
3570 /*
3571  * Portions of this file are based on pieces of Yahoo User Interface Library
3572  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3573  * YUI licensed under the BSD License:
3574  * http://developer.yahoo.net/yui/license.txt
3575  * <script type="text/javascript">
3576  *
3577  */
3578
3579 Roo.lib.AnimMgr = new function() {
3580
3581     var thread = null;
3582
3583
3584     var queue = [];
3585
3586
3587     var tweenCount = 0;
3588
3589
3590     this.fps = 1000;
3591
3592
3593     this.delay = 1;
3594
3595
3596     this.registerElement = function(tween) {
3597         queue[queue.length] = tween;
3598         tweenCount += 1;
3599         tween._onStart.fire();
3600         this.start();
3601     };
3602
3603
3604     this.unRegister = function(tween, index) {
3605         tween._onComplete.fire();
3606         index = index || getIndex(tween);
3607         if (index != -1) {
3608             queue.splice(index, 1);
3609         }
3610
3611         tweenCount -= 1;
3612         if (tweenCount <= 0) {
3613             this.stop();
3614         }
3615     };
3616
3617
3618     this.start = function() {
3619         if (thread === null) {
3620             thread = setInterval(this.run, this.delay);
3621         }
3622     };
3623
3624
3625     this.stop = function(tween) {
3626         if (!tween) {
3627             clearInterval(thread);
3628
3629             for (var i = 0, len = queue.length; i < len; ++i) {
3630                 if (queue[0].isAnimated()) {
3631                     this.unRegister(queue[0], 0);
3632                 }
3633             }
3634
3635             queue = [];
3636             thread = null;
3637             tweenCount = 0;
3638         }
3639         else {
3640             this.unRegister(tween);
3641         }
3642     };
3643
3644
3645     this.run = function() {
3646         for (var i = 0, len = queue.length; i < len; ++i) {
3647             var tween = queue[i];
3648             if (!tween || !tween.isAnimated()) {
3649                 continue;
3650             }
3651
3652             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3653             {
3654                 tween.currentFrame += 1;
3655
3656                 if (tween.useSeconds) {
3657                     correctFrame(tween);
3658                 }
3659                 tween._onTween.fire();
3660             }
3661             else {
3662                 Roo.lib.AnimMgr.stop(tween, i);
3663             }
3664         }
3665     };
3666
3667     var getIndex = function(anim) {
3668         for (var i = 0, len = queue.length; i < len; ++i) {
3669             if (queue[i] == anim) {
3670                 return i;
3671             }
3672         }
3673         return -1;
3674     };
3675
3676
3677     var correctFrame = function(tween) {
3678         var frames = tween.totalFrames;
3679         var frame = tween.currentFrame;
3680         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3681         var elapsed = (new Date() - tween.getStartTime());
3682         var tweak = 0;
3683
3684         if (elapsed < tween.duration * 1000) {
3685             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3686         } else {
3687             tweak = frames - (frame + 1);
3688         }
3689         if (tweak > 0 && isFinite(tweak)) {
3690             if (tween.currentFrame + tweak >= frames) {
3691                 tweak = frames - (frame + 1);
3692             }
3693
3694             tween.currentFrame += tweak;
3695         }
3696     };
3697 };
3698
3699     /*
3700  * Portions of this file are based on pieces of Yahoo User Interface Library
3701  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3702  * YUI licensed under the BSD License:
3703  * http://developer.yahoo.net/yui/license.txt
3704  * <script type="text/javascript">
3705  *
3706  */
3707 Roo.lib.Bezier = new function() {
3708
3709         this.getPosition = function(points, t) {
3710             var n = points.length;
3711             var tmp = [];
3712
3713             for (var i = 0; i < n; ++i) {
3714                 tmp[i] = [points[i][0], points[i][1]];
3715             }
3716
3717             for (var j = 1; j < n; ++j) {
3718                 for (i = 0; i < n - j; ++i) {
3719                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3720                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3721                 }
3722             }
3723
3724             return [ tmp[0][0], tmp[0][1] ];
3725
3726         };
3727     }; 
3728
3729 /**
3730  * @class Roo.lib.Color
3731  * @constructor
3732  * An abstract Color implementation. Concrete Color implementations should use
3733  * an instance of this function as their prototype, and implement the getRGB and
3734  * getHSL functions. getRGB should return an object representing the RGB
3735  * components of this Color, with the red, green, and blue components in the
3736  * range [0,255] and the alpha component in the range [0,100]. getHSL should
3737  * return an object representing the HSL components of this Color, with the hue
3738  * component in the range [0,360), the saturation and lightness components in
3739  * the range [0,100], and the alpha component in the range [0,1].
3740  *
3741  *
3742  * Color.js
3743  *
3744  * Functions for Color handling and processing.
3745  *
3746  * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3747  *
3748  * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3749  * rights to this program, with the intention of it becoming part of the public
3750  * domain. Because this program is released into the public domain, it comes with
3751  * no warranty either expressed or implied, to the extent permitted by law.
3752  * 
3753  * For more free and public domain JavaScript code by the same author, visit:
3754  * http://www.safalra.com/web-design/javascript/
3755  * 
3756  */
3757 Roo.lib.Color = function() { }
3758
3759
3760 Roo.apply(Roo.lib.Color.prototype, {
3761   
3762   rgb : null,
3763   hsv : null,
3764   hsl : null,
3765   
3766   /**
3767    * getIntegerRGB
3768    * @return {Object} an object representing the RGBA components of this Color. The red,
3769    * green, and blue components are converted to integers in the range [0,255].
3770    * The alpha is a value in the range [0,1].
3771    */
3772   getIntegerRGB : function(){
3773
3774     // get the RGB components of this Color
3775     var rgb = this.getRGB();
3776
3777     // return the integer components
3778     return {
3779       'r' : Math.round(rgb.r),
3780       'g' : Math.round(rgb.g),
3781       'b' : Math.round(rgb.b),
3782       'a' : rgb.a
3783     };
3784
3785   },
3786
3787   /**
3788    * getPercentageRGB
3789    * @return {Object} an object representing the RGBA components of this Color. The red,
3790    * green, and blue components are converted to numbers in the range [0,100].
3791    * The alpha is a value in the range [0,1].
3792    */
3793   getPercentageRGB : function(){
3794
3795     // get the RGB components of this Color
3796     var rgb = this.getRGB();
3797
3798     // return the percentage components
3799     return {
3800       'r' : 100 * rgb.r / 255,
3801       'g' : 100 * rgb.g / 255,
3802       'b' : 100 * rgb.b / 255,
3803       'a' : rgb.a
3804     };
3805
3806   },
3807
3808   /**
3809    * getCSSHexadecimalRGB
3810    * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3811    * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3812    * are two-digit hexadecimal numbers.
3813    */
3814   getCSSHexadecimalRGB : function()
3815   {
3816
3817     // get the integer RGB components
3818     var rgb = this.getIntegerRGB();
3819
3820     // determine the hexadecimal equivalents
3821     var r16 = rgb.r.toString(16);
3822     var g16 = rgb.g.toString(16);
3823     var b16 = rgb.b.toString(16);
3824
3825     // return the CSS RGB Color value
3826     return '#'
3827         + (r16.length == 2 ? r16 : '0' + r16)
3828         + (g16.length == 2 ? g16 : '0' + g16)
3829         + (b16.length == 2 ? b16 : '0' + b16);
3830
3831   },
3832
3833   /**
3834    * getCSSIntegerRGB
3835    * @return {String} a string representing this Color as a CSS integer RGB Color
3836    * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3837    * are integers in the range [0,255].
3838    */
3839   getCSSIntegerRGB : function(){
3840
3841     // get the integer RGB components
3842     var rgb = this.getIntegerRGB();
3843
3844     // return the CSS RGB Color value
3845     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3846
3847   },
3848
3849   /**
3850    * getCSSIntegerRGBA
3851    * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3852    * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3853    * b are integers in the range [0,255] and a is in the range [0,1].
3854    */
3855   getCSSIntegerRGBA : function(){
3856
3857     // get the integer RGB components
3858     var rgb = this.getIntegerRGB();
3859
3860     // return the CSS integer RGBA Color value
3861     return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3862
3863   },
3864
3865   /**
3866    * getCSSPercentageRGB
3867    * @return {String} a string representing this Color as a CSS percentage RGB Color
3868    * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3869    * b are in the range [0,100].
3870    */
3871   getCSSPercentageRGB : function(){
3872
3873     // get the percentage RGB components
3874     var rgb = this.getPercentageRGB();
3875
3876     // return the CSS RGB Color value
3877     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3878
3879   },
3880
3881   /**
3882    * getCSSPercentageRGBA
3883    * @return {String} a string representing this Color as a CSS percentage RGBA Color
3884    * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3885    * and b are in the range [0,100] and a is in the range [0,1].
3886    */
3887   getCSSPercentageRGBA : function(){
3888
3889     // get the percentage RGB components
3890     var rgb = this.getPercentageRGB();
3891
3892     // return the CSS percentage RGBA Color value
3893     return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3894
3895   },
3896
3897   /**
3898    * getCSSHSL
3899    * @return {String} a string representing this Color as a CSS HSL Color value - that
3900    * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3901    * s and l are in the range [0,100].
3902    */
3903   getCSSHSL : function(){
3904
3905     // get the HSL components
3906     var hsl = this.getHSL();
3907
3908     // return the CSS HSL Color value
3909     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3910
3911   },
3912
3913   /**
3914    * getCSSHSLA
3915    * @return {String} a string representing this Color as a CSS HSLA Color value - that
3916    * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3917    * s and l are in the range [0,100], and a is in the range [0,1].
3918    */
3919   getCSSHSLA : function(){
3920
3921     // get the HSL components
3922     var hsl = this.getHSL();
3923
3924     // return the CSS HSL Color value
3925     return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3926
3927   },
3928
3929   /**
3930    * Sets the Color of the specified node to this Color. This functions sets
3931    * the CSS 'color' property for the node. The parameter is:
3932    * 
3933    * @param {DomElement} node - the node whose Color should be set
3934    */
3935   setNodeColor : function(node){
3936
3937     // set the Color of the node
3938     node.style.color = this.getCSSHexadecimalRGB();
3939
3940   },
3941
3942   /**
3943    * Sets the background Color of the specified node to this Color. This
3944    * functions sets the CSS 'background-color' property for the node. The
3945    * parameter is:
3946    *
3947    * @param {DomElement} node - the node whose background Color should be set
3948    */
3949   setNodeBackgroundColor : function(node){
3950
3951     // set the background Color of the node
3952     node.style.backgroundColor = this.getCSSHexadecimalRGB();
3953
3954   },
3955   // convert between formats..
3956   toRGB: function()
3957   {
3958     var r = this.getIntegerRGB();
3959     return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3960     
3961   },
3962   toHSL : function()
3963   {
3964      var hsl = this.getHSL();
3965   // return the CSS HSL Color value
3966     return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
3967     
3968   },
3969   
3970   toHSV : function()
3971   {
3972     var rgb = this.toRGB();
3973     var hsv = rgb.getHSV();
3974    // return the CSS HSL Color value
3975     return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
3976     
3977   },
3978   
3979   // modify  v = 0 ... 1 (eg. 0.5)
3980   saturate : function(v)
3981   {
3982       var rgb = this.toRGB();
3983       var hsv = rgb.getHSV();
3984       return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
3985       
3986   
3987   },
3988   
3989    
3990   /**
3991    * getRGB
3992    * @return {Object} the RGB and alpha components of this Color as an object with r,
3993    * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3994    * the range [0,1].
3995    */
3996   getRGB: function(){
3997    
3998     // return the RGB components
3999     return {
4000       'r' : this.rgb.r,
4001       'g' : this.rgb.g,
4002       'b' : this.rgb.b,
4003       'a' : this.alpha
4004     };
4005
4006   },
4007
4008   /**
4009    * getHSV
4010    * @return {Object} the HSV and alpha components of this Color as an object with h,
4011    * s, v, and a properties. h is in the range [0,360), s and v are in the range
4012    * [0,100], and a is in the range [0,1].
4013    */
4014   getHSV : function()
4015   {
4016     
4017     // calculate the HSV components if necessary
4018     if (this.hsv == null) {
4019       this.calculateHSV();
4020     }
4021
4022     // return the HSV components
4023     return {
4024       'h' : this.hsv.h,
4025       's' : this.hsv.s,
4026       'v' : this.hsv.v,
4027       'a' : this.alpha
4028     };
4029
4030   },
4031
4032   /**
4033    * getHSL
4034    * @return {Object} the HSL and alpha components of this Color as an object with h,
4035    * s, l, and a properties. h is in the range [0,360), s and l are in the range
4036    * [0,100], and a is in the range [0,1].
4037    */
4038   getHSL : function(){
4039     
4040      
4041     // calculate the HSV components if necessary
4042     if (this.hsl == null) { this.calculateHSL(); }
4043
4044     // return the HSL components
4045     return {
4046       'h' : this.hsl.h,
4047       's' : this.hsl.s,
4048       'l' : this.hsl.l,
4049       'a' : this.alpha
4050     };
4051
4052   }
4053   
4054
4055 });
4056
4057
4058 /**
4059  * @class Roo.lib.RGBColor
4060  * @extends Roo.lib.Color
4061  * Creates a Color specified in the RGB Color space, with an optional alpha
4062  * component. The parameters are:
4063  * @constructor
4064  * 
4065
4066  * @param {Number} r - the red component, clipped to the range [0,255]
4067  * @param {Number} g - the green component, clipped to the range [0,255]
4068  * @param {Number} b - the blue component, clipped to the range [0,255]
4069  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4070  *     optional and defaults to 1
4071  */
4072 Roo.lib.RGBColor = function (r, g, b, a){
4073
4074   // store the alpha component after clipping it if necessary
4075   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4076
4077   // store the RGB components after clipping them if necessary
4078   this.rgb =
4079       {
4080         'r' : Math.max(0, Math.min(255, r)),
4081         'g' : Math.max(0, Math.min(255, g)),
4082         'b' : Math.max(0, Math.min(255, b))
4083       };
4084
4085   // initialise the HSV and HSL components to null
4086   
4087
4088   /* 
4089    * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4090    * range [0,360). The parameters are:
4091    *
4092    * maximum - the maximum of the RGB component values
4093    * range   - the range of the RGB component values
4094    */
4095    
4096
4097 }
4098 // this does an 'exteds'
4099 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4100
4101   
4102     getHue  : function(maximum, range)
4103     {
4104       var rgb = this.rgb;
4105        
4106       // check whether the range is zero
4107       if (range == 0){
4108   
4109         // set the hue to zero (any hue is acceptable as the Color is grey)
4110         var hue = 0;
4111   
4112       }else{
4113   
4114         // determine which of the components has the highest value and set the hue
4115         switch (maximum){
4116   
4117           // red has the highest value
4118           case rgb.r:
4119             var hue = (rgb.g - rgb.b) / range * 60;
4120             if (hue < 0) { hue += 360; }
4121             break;
4122   
4123           // green has the highest value
4124           case rgb.g:
4125             var hue = (rgb.b - rgb.r) / range * 60 + 120;
4126             break;
4127   
4128           // blue has the highest value
4129           case rgb.b:
4130             var hue = (rgb.r - rgb.g) / range * 60 + 240;
4131             break;
4132   
4133         }
4134   
4135       }
4136   
4137       // return the hue
4138       return hue;
4139   
4140     },
4141
4142   /* //private Calculates and stores the HSV components of this RGBColor so that they can
4143    * be returned be the getHSV function.
4144    */
4145    calculateHSV : function(){
4146     var rgb = this.rgb;
4147     // get the maximum and range of the RGB component values
4148     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4149     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4150
4151     // store the HSV components
4152     this.hsv =
4153         {
4154           'h' : this.getHue(maximum, range),
4155           's' : (maximum == 0 ? 0 : 100 * range / maximum),
4156           'v' : maximum / 2.55
4157         };
4158
4159   },
4160
4161   /* //private Calculates and stores the HSL components of this RGBColor so that they can
4162    * be returned be the getHSL function.
4163    */
4164    calculateHSL : function(){
4165     var rgb = this.rgb;
4166     // get the maximum and range of the RGB component values
4167     var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4168     var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4169
4170     // determine the lightness in the range [0,1]
4171     var l = maximum / 255 - range / 510;
4172
4173     // store the HSL components
4174     this.hsl =
4175         {
4176           'h' : this.getHue(maximum, range),
4177           's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4178           'l' : 100 * l
4179         };
4180
4181   }
4182
4183 });
4184
4185 /**
4186  * @class Roo.lib.HSVColor
4187  * @extends Roo.lib.Color
4188  * Creates a Color specified in the HSV Color space, with an optional alpha
4189  * component. The parameters are:
4190  * @constructor
4191  *
4192  * @param {Number} h - the hue component, wrapped to the range [0,360)
4193  * @param {Number} s - the saturation component, clipped to the range [0,100]
4194  * @param {Number} v - the value component, clipped to the range [0,100]
4195  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4196  *     optional and defaults to 1
4197  */
4198 Roo.lib.HSVColor = function (h, s, v, a){
4199
4200   // store the alpha component after clipping it if necessary
4201   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4202
4203   // store the HSV components after clipping or wrapping them if necessary
4204   this.hsv =
4205       {
4206         'h' : (h % 360 + 360) % 360,
4207         's' : Math.max(0, Math.min(100, s)),
4208         'v' : Math.max(0, Math.min(100, v))
4209       };
4210
4211   // initialise the RGB and HSL components to null
4212   this.rgb = null;
4213   this.hsl = null;
4214 }
4215
4216 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4217   /* Calculates and stores the RGB components of this HSVColor so that they can
4218    * be returned be the getRGB function.
4219    */
4220   calculateRGB: function ()
4221   {
4222     var hsv = this.hsv;
4223     // check whether the saturation is zero
4224     if (hsv.s == 0){
4225
4226       // set the Color to the appropriate shade of grey
4227       var r = hsv.v;
4228       var g = hsv.v;
4229       var b = hsv.v;
4230
4231     }else{
4232
4233       // set some temporary values
4234       var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
4235       var p  = hsv.v * (1 - hsv.s / 100);
4236       var q  = hsv.v * (1 - hsv.s / 100 * f);
4237       var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
4238
4239       // set the RGB Color components to their temporary values
4240       switch (Math.floor(hsv.h / 60)){
4241         case 0: var r = hsv.v; var g = t; var b = p; break;
4242         case 1: var r = q; var g = hsv.v; var b = p; break;
4243         case 2: var r = p; var g = hsv.v; var b = t; break;
4244         case 3: var r = p; var g = q; var b = hsv.v; break;
4245         case 4: var r = t; var g = p; var b = hsv.v; break;
4246         case 5: var r = hsv.v; var g = p; var b = q; break;
4247       }
4248
4249     }
4250
4251     // store the RGB components
4252     this.rgb =
4253         {
4254           'r' : r * 2.55,
4255           'g' : g * 2.55,
4256           'b' : b * 2.55
4257         };
4258
4259   },
4260
4261   /* Calculates and stores the HSL components of this HSVColor so that they can
4262    * be returned be the getHSL function.
4263    */
4264   calculateHSL : function (){
4265
4266     var hsv = this.hsv;
4267     // determine the lightness in the range [0,100]
4268     var l = (2 - hsv.s / 100) * hsv.v / 2;
4269
4270     // store the HSL components
4271     this.hsl =
4272         {
4273           'h' : hsv.h,
4274           's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4275           'l' : l
4276         };
4277
4278     // correct a division-by-zero error
4279     if (isNaN(hsl.s)) { hsl.s = 0; }
4280
4281   } 
4282  
4283
4284 });
4285  
4286
4287 /**
4288  * @class Roo.lib.HSLColor
4289  * @extends Roo.lib.Color
4290  *
4291  * @constructor
4292  * Creates a Color specified in the HSL Color space, with an optional alpha
4293  * component. The parameters are:
4294  *
4295  * @param {Number} h - the hue component, wrapped to the range [0,360)
4296  * @param {Number} s - the saturation component, clipped to the range [0,100]
4297  * @param {Number} l - the lightness component, clipped to the range [0,100]
4298  * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4299  *     optional and defaults to 1
4300  */
4301
4302 Roo.lib.HSLColor = function(h, s, l, a){
4303
4304   // store the alpha component after clipping it if necessary
4305   this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4306
4307   // store the HSL components after clipping or wrapping them if necessary
4308   this.hsl =
4309       {
4310         'h' : (h % 360 + 360) % 360,
4311         's' : Math.max(0, Math.min(100, s)),
4312         'l' : Math.max(0, Math.min(100, l))
4313       };
4314
4315   // initialise the RGB and HSV components to null
4316 }
4317
4318 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4319
4320   /* Calculates and stores the RGB components of this HSLColor so that they can
4321    * be returned be the getRGB function.
4322    */
4323   calculateRGB: function (){
4324
4325     // check whether the saturation is zero
4326     if (this.hsl.s == 0){
4327
4328       // store the RGB components representing the appropriate shade of grey
4329       this.rgb =
4330           {
4331             'r' : this.hsl.l * 2.55,
4332             'g' : this.hsl.l * 2.55,
4333             'b' : this.hsl.l * 2.55
4334           };
4335
4336     }else{
4337
4338       // set some temporary values
4339       var p = this.hsl.l < 50
4340             ? this.hsl.l * (1 + hsl.s / 100)
4341             : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4342       var q = 2 * hsl.l - p;
4343
4344       // initialise the RGB components
4345       this.rgb =
4346           {
4347             'r' : (h + 120) / 60 % 6,
4348             'g' : h / 60,
4349             'b' : (h + 240) / 60 % 6
4350           };
4351
4352       // loop over the RGB components
4353       for (var key in this.rgb){
4354
4355         // ensure that the property is not inherited from the root object
4356         if (this.rgb.hasOwnProperty(key)){
4357
4358           // set the component to its value in the range [0,100]
4359           if (this.rgb[key] < 1){
4360             this.rgb[key] = q + (p - q) * this.rgb[key];
4361           }else if (this.rgb[key] < 3){
4362             this.rgb[key] = p;
4363           }else if (this.rgb[key] < 4){
4364             this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4365           }else{
4366             this.rgb[key] = q;
4367           }
4368
4369           // set the component to its value in the range [0,255]
4370           this.rgb[key] *= 2.55;
4371
4372         }
4373
4374       }
4375
4376     }
4377
4378   },
4379
4380   /* Calculates and stores the HSV components of this HSLColor so that they can
4381    * be returned be the getHSL function.
4382    */
4383    calculateHSV : function(){
4384
4385     // set a temporary value
4386     var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4387
4388     // store the HSV components
4389     this.hsv =
4390         {
4391           'h' : this.hsl.h,
4392           's' : 200 * t / (this.hsl.l + t),
4393           'v' : t + this.hsl.l
4394         };
4395
4396     // correct a division-by-zero error
4397     if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4398
4399   }
4400  
4401
4402 });
4403 /*
4404  * Portions of this file are based on pieces of Yahoo User Interface Library
4405  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4406  * YUI licensed under the BSD License:
4407  * http://developer.yahoo.net/yui/license.txt
4408  * <script type="text/javascript">
4409  *
4410  */
4411 (function() {
4412
4413     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4414         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4415     };
4416
4417     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4418
4419     var fly = Roo.lib.AnimBase.fly;
4420     var Y = Roo.lib;
4421     var superclass = Y.ColorAnim.superclass;
4422     var proto = Y.ColorAnim.prototype;
4423
4424     proto.toString = function() {
4425         var el = this.getEl();
4426         var id = el.id || el.tagName;
4427         return ("ColorAnim " + id);
4428     };
4429
4430     proto.patterns.color = /color$/i;
4431     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4432     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4433     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4434     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4435
4436
4437     proto.parseColor = function(s) {
4438         if (s.length == 3) {
4439             return s;
4440         }
4441
4442         var c = this.patterns.hex.exec(s);
4443         if (c && c.length == 4) {
4444             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4445         }
4446
4447         c = this.patterns.rgb.exec(s);
4448         if (c && c.length == 4) {
4449             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4450         }
4451
4452         c = this.patterns.hex3.exec(s);
4453         if (c && c.length == 4) {
4454             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4455         }
4456
4457         return null;
4458     };
4459     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4460     proto.getAttribute = function(attr) {
4461         var el = this.getEl();
4462         if (this.patterns.color.test(attr)) {
4463             var val = fly(el).getStyle(attr);
4464
4465             if (this.patterns.transparent.test(val)) {
4466                 var parent = el.parentNode;
4467                 val = fly(parent).getStyle(attr);
4468
4469                 while (parent && this.patterns.transparent.test(val)) {
4470                     parent = parent.parentNode;
4471                     val = fly(parent).getStyle(attr);
4472                     if (parent.tagName.toUpperCase() == 'HTML') {
4473                         val = '#fff';
4474                     }
4475                 }
4476             }
4477         } else {
4478             val = superclass.getAttribute.call(this, attr);
4479         }
4480
4481         return val;
4482     };
4483     proto.getAttribute = function(attr) {
4484         var el = this.getEl();
4485         if (this.patterns.color.test(attr)) {
4486             var val = fly(el).getStyle(attr);
4487
4488             if (this.patterns.transparent.test(val)) {
4489                 var parent = el.parentNode;
4490                 val = fly(parent).getStyle(attr);
4491
4492                 while (parent && this.patterns.transparent.test(val)) {
4493                     parent = parent.parentNode;
4494                     val = fly(parent).getStyle(attr);
4495                     if (parent.tagName.toUpperCase() == 'HTML') {
4496                         val = '#fff';
4497                     }
4498                 }
4499             }
4500         } else {
4501             val = superclass.getAttribute.call(this, attr);
4502         }
4503
4504         return val;
4505     };
4506
4507     proto.doMethod = function(attr, start, end) {
4508         var val;
4509
4510         if (this.patterns.color.test(attr)) {
4511             val = [];
4512             for (var i = 0, len = start.length; i < len; ++i) {
4513                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4514             }
4515
4516             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4517         }
4518         else {
4519             val = superclass.doMethod.call(this, attr, start, end);
4520         }
4521
4522         return val;
4523     };
4524
4525     proto.setRuntimeAttribute = function(attr) {
4526         superclass.setRuntimeAttribute.call(this, attr);
4527
4528         if (this.patterns.color.test(attr)) {
4529             var attributes = this.attributes;
4530             var start = this.parseColor(this.runtimeAttributes[attr].start);
4531             var end = this.parseColor(this.runtimeAttributes[attr].end);
4532
4533             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4534                 end = this.parseColor(attributes[attr].by);
4535
4536                 for (var i = 0, len = start.length; i < len; ++i) {
4537                     end[i] = start[i] + end[i];
4538                 }
4539             }
4540
4541             this.runtimeAttributes[attr].start = start;
4542             this.runtimeAttributes[attr].end = end;
4543         }
4544     };
4545 })();
4546
4547 /*
4548  * Portions of this file are based on pieces of Yahoo User Interface Library
4549  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4550  * YUI licensed under the BSD License:
4551  * http://developer.yahoo.net/yui/license.txt
4552  * <script type="text/javascript">
4553  *
4554  */
4555 Roo.lib.Easing = {
4556
4557
4558     easeNone: function (t, b, c, d) {
4559         return c * t / d + b;
4560     },
4561
4562
4563     easeIn: function (t, b, c, d) {
4564         return c * (t /= d) * t + b;
4565     },
4566
4567
4568     easeOut: function (t, b, c, d) {
4569         return -c * (t /= d) * (t - 2) + b;
4570     },
4571
4572
4573     easeBoth: function (t, b, c, d) {
4574         if ((t /= d / 2) < 1) {
4575             return c / 2 * t * t + b;
4576         }
4577
4578         return -c / 2 * ((--t) * (t - 2) - 1) + b;
4579     },
4580
4581
4582     easeInStrong: function (t, b, c, d) {
4583         return c * (t /= d) * t * t * t + b;
4584     },
4585
4586
4587     easeOutStrong: function (t, b, c, d) {
4588         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4589     },
4590
4591
4592     easeBothStrong: function (t, b, c, d) {
4593         if ((t /= d / 2) < 1) {
4594             return c / 2 * t * t * t * t + b;
4595         }
4596
4597         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4598     },
4599
4600
4601
4602     elasticIn: function (t, b, c, d, a, p) {
4603         if (t == 0) {
4604             return b;
4605         }
4606         if ((t /= d) == 1) {
4607             return b + c;
4608         }
4609         if (!p) {
4610             p = d * .3;
4611         }
4612
4613         if (!a || a < Math.abs(c)) {
4614             a = c;
4615             var s = p / 4;
4616         }
4617         else {
4618             var s = p / (2 * Math.PI) * Math.asin(c / a);
4619         }
4620
4621         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4622     },
4623
4624
4625     elasticOut: function (t, b, c, d, a, p) {
4626         if (t == 0) {
4627             return b;
4628         }
4629         if ((t /= d) == 1) {
4630             return b + c;
4631         }
4632         if (!p) {
4633             p = d * .3;
4634         }
4635
4636         if (!a || a < Math.abs(c)) {
4637             a = c;
4638             var s = p / 4;
4639         }
4640         else {
4641             var s = p / (2 * Math.PI) * Math.asin(c / a);
4642         }
4643
4644         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4645     },
4646
4647
4648     elasticBoth: function (t, b, c, d, a, p) {
4649         if (t == 0) {
4650             return b;
4651         }
4652
4653         if ((t /= d / 2) == 2) {
4654             return b + c;
4655         }
4656
4657         if (!p) {
4658             p = d * (.3 * 1.5);
4659         }
4660
4661         if (!a || a < Math.abs(c)) {
4662             a = c;
4663             var s = p / 4;
4664         }
4665         else {
4666             var s = p / (2 * Math.PI) * Math.asin(c / a);
4667         }
4668
4669         if (t < 1) {
4670             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4671                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4672         }
4673         return a * Math.pow(2, -10 * (t -= 1)) *
4674                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4675     },
4676
4677
4678
4679     backIn: function (t, b, c, d, s) {
4680         if (typeof s == 'undefined') {
4681             s = 1.70158;
4682         }
4683         return c * (t /= d) * t * ((s + 1) * t - s) + b;
4684     },
4685
4686
4687     backOut: function (t, b, c, d, s) {
4688         if (typeof s == 'undefined') {
4689             s = 1.70158;
4690         }
4691         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4692     },
4693
4694
4695     backBoth: function (t, b, c, d, s) {
4696         if (typeof s == 'undefined') {
4697             s = 1.70158;
4698         }
4699
4700         if ((t /= d / 2 ) < 1) {
4701             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4702         }
4703         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4704     },
4705
4706
4707     bounceIn: function (t, b, c, d) {
4708         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4709     },
4710
4711
4712     bounceOut: function (t, b, c, d) {
4713         if ((t /= d) < (1 / 2.75)) {
4714             return c * (7.5625 * t * t) + b;
4715         } else if (t < (2 / 2.75)) {
4716             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4717         } else if (t < (2.5 / 2.75)) {
4718             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4719         }
4720         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4721     },
4722
4723
4724     bounceBoth: function (t, b, c, d) {
4725         if (t < d / 2) {
4726             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4727         }
4728         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4729     }
4730 };/*
4731  * Portions of this file are based on pieces of Yahoo User Interface Library
4732  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4733  * YUI licensed under the BSD License:
4734  * http://developer.yahoo.net/yui/license.txt
4735  * <script type="text/javascript">
4736  *
4737  */
4738     (function() {
4739         Roo.lib.Motion = function(el, attributes, duration, method) {
4740             if (el) {
4741                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4742             }
4743         };
4744
4745         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4746
4747
4748         var Y = Roo.lib;
4749         var superclass = Y.Motion.superclass;
4750         var proto = Y.Motion.prototype;
4751
4752         proto.toString = function() {
4753             var el = this.getEl();
4754             var id = el.id || el.tagName;
4755             return ("Motion " + id);
4756         };
4757
4758         proto.patterns.points = /^points$/i;
4759
4760         proto.setAttribute = function(attr, val, unit) {
4761             if (this.patterns.points.test(attr)) {
4762                 unit = unit || 'px';
4763                 superclass.setAttribute.call(this, 'left', val[0], unit);
4764                 superclass.setAttribute.call(this, 'top', val[1], unit);
4765             } else {
4766                 superclass.setAttribute.call(this, attr, val, unit);
4767             }
4768         };
4769
4770         proto.getAttribute = function(attr) {
4771             if (this.patterns.points.test(attr)) {
4772                 var val = [
4773                         superclass.getAttribute.call(this, 'left'),
4774                         superclass.getAttribute.call(this, 'top')
4775                         ];
4776             } else {
4777                 val = superclass.getAttribute.call(this, attr);
4778             }
4779
4780             return val;
4781         };
4782
4783         proto.doMethod = function(attr, start, end) {
4784             var val = null;
4785
4786             if (this.patterns.points.test(attr)) {
4787                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4788                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4789             } else {
4790                 val = superclass.doMethod.call(this, attr, start, end);
4791             }
4792             return val;
4793         };
4794
4795         proto.setRuntimeAttribute = function(attr) {
4796             if (this.patterns.points.test(attr)) {
4797                 var el = this.getEl();
4798                 var attributes = this.attributes;
4799                 var start;
4800                 var control = attributes['points']['control'] || [];
4801                 var end;
4802                 var i, len;
4803
4804                 if (control.length > 0 && !(control[0] instanceof Array)) {
4805                     control = [control];
4806                 } else {
4807                     var tmp = [];
4808                     for (i = 0,len = control.length; i < len; ++i) {
4809                         tmp[i] = control[i];
4810                     }
4811                     control = tmp;
4812                 }
4813
4814                 Roo.fly(el).position();
4815
4816                 if (isset(attributes['points']['from'])) {
4817                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4818                 }
4819                 else {
4820                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4821                 }
4822
4823                 start = this.getAttribute('points');
4824
4825
4826                 if (isset(attributes['points']['to'])) {
4827                     end = translateValues.call(this, attributes['points']['to'], start);
4828
4829                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4830                     for (i = 0,len = control.length; i < len; ++i) {
4831                         control[i] = translateValues.call(this, control[i], start);
4832                     }
4833
4834
4835                 } else if (isset(attributes['points']['by'])) {
4836                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4837
4838                     for (i = 0,len = control.length; i < len; ++i) {
4839                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4840                     }
4841                 }
4842
4843                 this.runtimeAttributes[attr] = [start];
4844
4845                 if (control.length > 0) {
4846                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4847                 }
4848
4849                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4850             }
4851             else {
4852                 superclass.setRuntimeAttribute.call(this, attr);
4853             }
4854         };
4855
4856         var translateValues = function(val, start) {
4857             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4858             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4859
4860             return val;
4861         };
4862
4863         var isset = function(prop) {
4864             return (typeof prop !== 'undefined');
4865         };
4866     })();
4867 /*
4868  * Portions of this file are based on pieces of Yahoo User Interface Library
4869  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4870  * YUI licensed under the BSD License:
4871  * http://developer.yahoo.net/yui/license.txt
4872  * <script type="text/javascript">
4873  *
4874  */
4875     (function() {
4876         Roo.lib.Scroll = function(el, attributes, duration, method) {
4877             if (el) {
4878                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4879             }
4880         };
4881
4882         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4883
4884
4885         var Y = Roo.lib;
4886         var superclass = Y.Scroll.superclass;
4887         var proto = Y.Scroll.prototype;
4888
4889         proto.toString = function() {
4890             var el = this.getEl();
4891             var id = el.id || el.tagName;
4892             return ("Scroll " + id);
4893         };
4894
4895         proto.doMethod = function(attr, start, end) {
4896             var val = null;
4897
4898             if (attr == 'scroll') {
4899                 val = [
4900                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4901                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4902                         ];
4903
4904             } else {
4905                 val = superclass.doMethod.call(this, attr, start, end);
4906             }
4907             return val;
4908         };
4909
4910         proto.getAttribute = function(attr) {
4911             var val = null;
4912             var el = this.getEl();
4913
4914             if (attr == 'scroll') {
4915                 val = [ el.scrollLeft, el.scrollTop ];
4916             } else {
4917                 val = superclass.getAttribute.call(this, attr);
4918             }
4919
4920             return val;
4921         };
4922
4923         proto.setAttribute = function(attr, val, unit) {
4924             var el = this.getEl();
4925
4926             if (attr == 'scroll') {
4927                 el.scrollLeft = val[0];
4928                 el.scrollTop = val[1];
4929             } else {
4930                 superclass.setAttribute.call(this, attr, val, unit);
4931             }
4932         };
4933     })();
4934 /**
4935  * Originally based of this code... - refactored for Roo...
4936  * https://github.com/aaalsaleh/undo-manager
4937  
4938  * undo-manager.js
4939  * @author  Abdulrahman Alsaleh 
4940  * @copyright 2015 Abdulrahman Alsaleh 
4941  * @license  MIT License (c) 
4942  *
4943  * Hackily modifyed by alan@roojs.com
4944  *
4945  *
4946  *  
4947  *
4948  *  TOTALLY UNTESTED...
4949  *
4950  *  Documentation to be done....
4951  */
4952  
4953
4954 /**
4955 * @class Roo.lib.UndoManager
4956 * An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
4957 * Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
4958
4959  * Usage:
4960  * <pre><code>
4961
4962
4963 editor.undoManager = new Roo.lib.UndoManager(1000, editor);
4964  
4965 </code></pre>
4966
4967 * For more information see this blog post with examples:
4968 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4969      - Create Elements using DOM, HTML fragments and Templates</a>. 
4970 * @constructor
4971 * @param {Number} limit how far back to go ... use 1000?
4972 * @param {Object} scope usually use document..
4973 */
4974
4975 Roo.lib.UndoManager = function (limit, undoScopeHost)
4976 {
4977     this.stack = [];
4978     this.limit = limit;
4979     this.scope = undoScopeHost;
4980     this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
4981     if (this.fireEvent) {
4982         this.bindEvents();
4983     }
4984     this.reset();
4985     
4986 };
4987         
4988 Roo.lib.UndoManager.prototype = {
4989     
4990     limit : false,
4991     stack : false,
4992     scope :  false,
4993     fireEvent : false,
4994     position : 0,
4995     length : 0,
4996     
4997     
4998      /**
4999      * To push and execute a transaction, the method undoManager.transact
5000      * must be called by passing a transaction object as the first argument, and a merge
5001      * flag as the second argument. A transaction object has the following properties:
5002      *
5003      * Usage:
5004 <pre><code>
5005 undoManager.transact({
5006     label: 'Typing',
5007     execute: function() { ... },
5008     undo: function() { ... },
5009     // redo same as execute
5010     redo: function() { this.execute(); }
5011 }, false);
5012
5013 // merge transaction
5014 undoManager.transact({
5015     label: 'Typing',
5016     execute: function() { ... },  // this will be run...
5017     undo: function() { ... }, // what to do when undo is run.
5018     // redo same as execute
5019     redo: function() { this.execute(); }
5020 }, true); 
5021 </code></pre> 
5022      *
5023      * 
5024      * @param {Object} transaction The transaction to add to the stack.
5025      * @return {String} The HTML fragment
5026      */
5027     
5028     
5029     transact : function (transaction, merge)
5030     {
5031         if (arguments.length < 2) {
5032             throw new TypeError('Not enough arguments to UndoManager.transact.');
5033         }
5034
5035         transaction.execute();
5036
5037         this.stack.splice(0, this.position);
5038         if (merge && this.length) {
5039             this.stack[0].push(transaction);
5040         } else {
5041             this.stack.unshift([transaction]);
5042         }
5043     
5044         this.position = 0;
5045
5046         if (this.limit && this.stack.length > this.limit) {
5047             this.length = this.stack.length = this.limit;
5048         } else {
5049             this.length = this.stack.length;
5050         }
5051
5052         if (this.fireEvent) {
5053             this.scope.dispatchEvent(
5054                 new CustomEvent('DOMTransaction', {
5055                     detail: {
5056                         transactions: this.stack[0].slice()
5057                     },
5058                     bubbles: true,
5059                     cancelable: false
5060                 })
5061             );
5062         }
5063         
5064         //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5065       
5066         
5067     },
5068
5069     undo : function ()
5070     {
5071         //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
5072         
5073         if (this.position < this.length) {
5074             for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
5075                 this.stack[this.position][i].undo();
5076             }
5077             this.position++;
5078
5079             if (this.fireEvent) {
5080                 this.scope.dispatchEvent(
5081                     new CustomEvent('undo', {
5082                         detail: {
5083                             transactions: this.stack[this.position - 1].slice()
5084                         },
5085                         bubbles: true,
5086                         cancelable: false
5087                     })
5088                 );
5089             }
5090         }
5091     },
5092
5093     redo : function ()
5094     {
5095         if (this.position > 0) {
5096             for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
5097                 this.stack[this.position - 1][i].redo();
5098             }
5099             this.position--;
5100
5101             if (this.fireEvent) {
5102                 this.scope.dispatchEvent(
5103                     new CustomEvent('redo', {
5104                         detail: {
5105                             transactions: this.stack[this.position].slice()
5106                         },
5107                         bubbles: true,
5108                         cancelable: false
5109                     })
5110                 );
5111             }
5112         }
5113     },
5114
5115     item : function (index)
5116     {
5117         if (index >= 0 && index < this.length) {
5118             return this.stack[index].slice();
5119         }
5120         return null;
5121     },
5122
5123     clearUndo : function () {
5124         this.stack.length = this.length = this.position;
5125     },
5126
5127     clearRedo : function () {
5128         this.stack.splice(0, this.position);
5129         this.position = 0;
5130         this.length = this.stack.length;
5131     },
5132     /**
5133      * Reset the undo - probaly done on load to clear all history.
5134      */
5135     reset : function()
5136     {
5137         this.stack = [];
5138         this.position = 0;
5139         this.length = 0;
5140         this.current_html = this.scope.innerHTML;
5141         if (this.timer !== false) {
5142             clearTimeout(this.timer);
5143         }
5144         this.timer = false;
5145         this.merge = false;
5146         this.addEvent();
5147         
5148     },
5149     current_html : '',
5150     timer : false,
5151     merge : false,
5152     
5153     
5154     // this will handle the undo/redo on the element.?
5155     bindEvents : function()
5156     {
5157         var el  = this.scope;
5158         el.undoManager = this;
5159         
5160         
5161         this.scope.addEventListener('keydown', function(e) {
5162             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5163                 if (e.shiftKey) {
5164                     el.undoManager.redo(); // Ctrl/Command + Shift + Z
5165                 } else {
5166                     el.undoManager.undo(); // Ctrl/Command + Z
5167                 }
5168         
5169                 e.preventDefault();
5170             }
5171         });
5172         /// ignore keyup..
5173         this.scope.addEventListener('keyup', function(e) {
5174             if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
5175                 e.preventDefault();
5176             }
5177         });
5178         
5179         
5180         
5181         var t = this;
5182         
5183         el.addEventListener('input', function(e) {
5184             if(el.innerHTML == t.current_html) {
5185                 return;
5186             }
5187             // only record events every second.
5188             if (t.timer !== false) {
5189                clearTimeout(t.timer);
5190                t.timer = false;
5191             }
5192             t.timer = setTimeout(function() { t.merge = false; }, 1000);
5193             
5194             t.addEvent(t.merge);
5195             t.merge = true; // ignore changes happening every second..
5196         });
5197         },
5198     /**
5199      * Manually add an event.
5200      * Normall called without arguements - and it will just get added to the stack.
5201      * 
5202      */
5203     
5204     addEvent : function(merge)
5205     {
5206         //Roo.log("undomanager +" + (merge ? 'Y':'n'));
5207         // not sure if this should clear the timer 
5208         merge = typeof(merge) == 'undefined' ? false : merge; 
5209         
5210         this.scope.undoManager.transact({
5211             scope : this.scope,
5212             oldHTML: this.current_html,
5213             newHTML: this.scope.innerHTML,
5214             // nothing to execute (content already changed when input is fired)
5215             execute: function() { },
5216             undo: function() {
5217                 this.scope.innerHTML = this.current_html = this.oldHTML;
5218             },
5219             redo: function() {
5220                 this.scope.innerHTML = this.current_html = this.newHTML;
5221             }
5222         }, false); //merge);
5223         
5224         this.merge = merge;
5225         
5226         this.current_html = this.scope.innerHTML;
5227     }
5228     
5229     
5230      
5231     
5232     
5233     
5234 };
5235 /**
5236  * @class Roo.lib.Range
5237  * @constructor
5238  * This is a toolkit, normally used to copy features into a Dom Range element
5239  * Roo.lib.Range.wrap(x);
5240  *
5241  *
5242  *
5243  */
5244 Roo.lib.Range = function() { };
5245
5246 /**
5247  * Wrap a Dom Range object, to give it new features...
5248  * @static
5249  * @param {Range} the range to wrap
5250  */
5251 Roo.lib.Range.wrap = function(r) {
5252     return Roo.apply(r, Roo.lib.Range.prototype);
5253 };
5254 /**
5255  * find a parent node eg. LI / OL
5256  * @param {string|Array} node name or array of nodenames
5257  * @return {DomElement|false}
5258  */
5259 Roo.apply(Roo.lib.Range.prototype,
5260 {
5261     
5262     closest : function(str)
5263     {
5264         if (typeof(str) != 'string') {
5265             // assume it's a array.
5266             for(var i = 0;i < str.length;i++) {
5267                 var r = this.closest(str[i]);
5268                 if (r !== false) {
5269                     return r;
5270                 }
5271                 
5272             }
5273             return false;
5274         }
5275         str = str.toLowerCase();
5276         var n = this.commonAncestorContainer; // might not be a node
5277         while (n.nodeType != 1) {
5278             n = n.parentNode;
5279         }
5280         
5281         if (n.nodeName.toLowerCase() == str ) {
5282             return n;
5283         }
5284         if (n.nodeName.toLowerCase() == 'body') {
5285             return false;
5286         }
5287             
5288         return n.closest(str) || false;
5289         
5290     },
5291     cloneRange : function()
5292     {
5293         return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
5294     }
5295 });/**
5296  * @class Roo.lib.Selection
5297  * @constructor
5298  * This is a toolkit, normally used to copy features into a Dom Selection element
5299  * Roo.lib.Selection.wrap(x);
5300  *
5301  *
5302  *
5303  */
5304 Roo.lib.Selection = function() { };
5305
5306 /**
5307  * Wrap a Dom Range object, to give it new features...
5308  * @static
5309  * @param {Range} the range to wrap
5310  */
5311 Roo.lib.Selection.wrap = function(r, doc) {
5312     Roo.apply(r, Roo.lib.Selection.prototype);
5313     r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
5314     return r;
5315 };
5316 /**
5317  * find a parent node eg. LI / OL
5318  * @param {string|Array} node name or array of nodenames
5319  * @return {DomElement|false}
5320  */
5321 Roo.apply(Roo.lib.Selection.prototype,
5322 {
5323     /**
5324      * the owner document
5325      */
5326     ownerDocument : false,
5327     
5328     getRangeAt : function(n)
5329     {
5330         return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
5331     },
5332     
5333     /**
5334      * insert node at selection 
5335      * @param {DomElement|string} node
5336      * @param {string} cursor (after|in|none) where to place the cursor after inserting.
5337      */
5338     insertNode: function(node, cursor)
5339     {
5340         if (typeof(node) == 'string') {
5341             node = this.ownerDocument.createElement(node);
5342             if (cursor == 'in') {
5343                 node.innerHTML = '&nbsp;';
5344             }
5345         }
5346         
5347         var range = this.getRangeAt(0);
5348         
5349         if (this.type != 'Caret') {
5350             range.deleteContents();
5351         }
5352         var sn = node.childNodes[0]; // select the contents.
5353
5354         
5355         
5356         range.insertNode(node);
5357         if (cursor == 'after') {
5358             node.insertAdjacentHTML('afterend', '&nbsp;');
5359             sn = node.nextSibling;
5360         }
5361         
5362         if (cursor == 'none') {
5363             return;
5364         }
5365         
5366         this.cursorText(sn);
5367     },
5368     
5369     cursorText : function(n)
5370     {
5371        
5372         //var range = this.getRangeAt(0);
5373         range = Roo.lib.Range.wrap(new Range());
5374         //range.selectNode(n);
5375         
5376         var ix = Array.from(n.parentNode.childNodes).indexOf(n);
5377         range.setStart(n.parentNode,ix);
5378         range.setEnd(n.parentNode,ix+1);
5379         //range.collapse(false);
5380          
5381         this.removeAllRanges();
5382         this.addRange(range);
5383         
5384         Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
5385     },
5386     cursorAfter : function(n)
5387     {
5388         if (!n.nextSibling || n.nextSibling.nodeValue != '&nbsp;') {
5389             n.insertAdjacentHTML('afterend', '&nbsp;');
5390         }
5391         this.cursorText (n.nextSibling);
5392     }
5393         
5394     
5395 });/*
5396  * Based on:
5397  * Ext JS Library 1.1.1
5398  * Copyright(c) 2006-2007, Ext JS, LLC.
5399  *
5400  * Originally Released Under LGPL - original licence link has changed is not relivant.
5401  *
5402  * Fork - LGPL
5403  * <script type="text/javascript">
5404  */
5405
5406
5407 // nasty IE9 hack - what a pile of crap that is..
5408
5409  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
5410     Range.prototype.createContextualFragment = function (html) {
5411         var doc = window.document;
5412         var container = doc.createElement("div");
5413         container.innerHTML = html;
5414         var frag = doc.createDocumentFragment(), n;
5415         while ((n = container.firstChild)) {
5416             frag.appendChild(n);
5417         }
5418         return frag;
5419     };
5420 }
5421
5422 /**
5423  * @class Roo.DomHelper
5424  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
5425  * 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>.
5426  * @static
5427  */
5428 Roo.DomHelper = function(){
5429     var tempTableEl = null;
5430     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
5431     var tableRe = /^table|tbody|tr|td$/i;
5432     var xmlns = {};
5433     // build as innerHTML where available
5434     /** @ignore */
5435     var createHtml = function(o){
5436         if(typeof o == 'string'){
5437             return o;
5438         }
5439         var b = "";
5440         if(!o.tag){
5441             o.tag = "div";
5442         }
5443         b += "<" + o.tag;
5444         for(var attr in o){
5445             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
5446             if(attr == "style"){
5447                 var s = o["style"];
5448                 if(typeof s == "function"){
5449                     s = s.call();
5450                 }
5451                 if(typeof s == "string"){
5452                     b += ' style="' + s + '"';
5453                 }else if(typeof s == "object"){
5454                     b += ' style="';
5455                     for(var key in s){
5456                         if(typeof s[key] != "function"){
5457                             b += key + ":" + s[key] + ";";
5458                         }
5459                     }
5460                     b += '"';
5461                 }
5462             }else{
5463                 if(attr == "cls"){
5464                     b += ' class="' + o["cls"] + '"';
5465                 }else if(attr == "htmlFor"){
5466                     b += ' for="' + o["htmlFor"] + '"';
5467                 }else{
5468                     b += " " + attr + '="' + o[attr] + '"';
5469                 }
5470             }
5471         }
5472         if(emptyTags.test(o.tag)){
5473             b += "/>";
5474         }else{
5475             b += ">";
5476             var cn = o.children || o.cn;
5477             if(cn){
5478                 //http://bugs.kde.org/show_bug.cgi?id=71506
5479                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5480                     for(var i = 0, len = cn.length; i < len; i++) {
5481                         b += createHtml(cn[i], b);
5482                     }
5483                 }else{
5484                     b += createHtml(cn, b);
5485                 }
5486             }
5487             if(o.html){
5488                 b += o.html;
5489             }
5490             b += "</" + o.tag + ">";
5491         }
5492         return b;
5493     };
5494
5495     // build as dom
5496     /** @ignore */
5497     var createDom = function(o, parentNode){
5498          
5499         // defininition craeted..
5500         var ns = false;
5501         if (o.ns && o.ns != 'html') {
5502                
5503             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5504                 xmlns[o.ns] = o.xmlns;
5505                 ns = o.xmlns;
5506             }
5507             if (typeof(xmlns[o.ns]) == 'undefined') {
5508                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5509             }
5510             ns = xmlns[o.ns];
5511         }
5512         
5513         
5514         if (typeof(o) == 'string') {
5515             return parentNode.appendChild(document.createTextNode(o));
5516         }
5517         o.tag = o.tag || div;
5518         if (o.ns && Roo.isIE) {
5519             ns = false;
5520             o.tag = o.ns + ':' + o.tag;
5521             
5522         }
5523         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
5524         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5525         for(var attr in o){
5526             
5527             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
5528                     attr == "style" || typeof o[attr] == "function") { continue; }
5529                     
5530             if(attr=="cls" && Roo.isIE){
5531                 el.className = o["cls"];
5532             }else{
5533                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5534                 else { 
5535                     el[attr] = o[attr];
5536                 }
5537             }
5538         }
5539         Roo.DomHelper.applyStyles(el, o.style);
5540         var cn = o.children || o.cn;
5541         if(cn){
5542             //http://bugs.kde.org/show_bug.cgi?id=71506
5543              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5544                 for(var i = 0, len = cn.length; i < len; i++) {
5545                     createDom(cn[i], el);
5546                 }
5547             }else{
5548                 createDom(cn, el);
5549             }
5550         }
5551         if(o.html){
5552             el.innerHTML = o.html;
5553         }
5554         if(parentNode){
5555            parentNode.appendChild(el);
5556         }
5557         return el;
5558     };
5559
5560     var ieTable = function(depth, s, h, e){
5561         tempTableEl.innerHTML = [s, h, e].join('');
5562         var i = -1, el = tempTableEl;
5563         while(++i < depth && el.firstChild){
5564             el = el.firstChild;
5565         }
5566         return el;
5567     };
5568
5569     // kill repeat to save bytes
5570     var ts = '<table>',
5571         te = '</table>',
5572         tbs = ts+'<tbody>',
5573         tbe = '</tbody>'+te,
5574         trs = tbs + '<tr>',
5575         tre = '</tr>'+tbe;
5576
5577     /**
5578      * @ignore
5579      * Nasty code for IE's broken table implementation
5580      */
5581     var insertIntoTable = function(tag, where, el, html){
5582         if(!tempTableEl){
5583             tempTableEl = document.createElement('div');
5584         }
5585         var node;
5586         var before = null;
5587         if(tag == 'td'){
5588             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5589                 return;
5590             }
5591             if(where == 'beforebegin'){
5592                 before = el;
5593                 el = el.parentNode;
5594             } else{
5595                 before = el.nextSibling;
5596                 el = el.parentNode;
5597             }
5598             node = ieTable(4, trs, html, tre);
5599         }
5600         else if(tag == 'tr'){
5601             if(where == 'beforebegin'){
5602                 before = el;
5603                 el = el.parentNode;
5604                 node = ieTable(3, tbs, html, tbe);
5605             } else if(where == 'afterend'){
5606                 before = el.nextSibling;
5607                 el = el.parentNode;
5608                 node = ieTable(3, tbs, html, tbe);
5609             } else{ // INTO a TR
5610                 if(where == 'afterbegin'){
5611                     before = el.firstChild;
5612                 }
5613                 node = ieTable(4, trs, html, tre);
5614             }
5615         } else if(tag == 'tbody'){
5616             if(where == 'beforebegin'){
5617                 before = el;
5618                 el = el.parentNode;
5619                 node = ieTable(2, ts, html, te);
5620             } else if(where == 'afterend'){
5621                 before = el.nextSibling;
5622                 el = el.parentNode;
5623                 node = ieTable(2, ts, html, te);
5624             } else{
5625                 if(where == 'afterbegin'){
5626                     before = el.firstChild;
5627                 }
5628                 node = ieTable(3, tbs, html, tbe);
5629             }
5630         } else{ // TABLE
5631             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5632                 return;
5633             }
5634             if(where == 'afterbegin'){
5635                 before = el.firstChild;
5636             }
5637             node = ieTable(2, ts, html, te);
5638         }
5639         el.insertBefore(node, before);
5640         return node;
5641     };
5642     
5643     // this is a bit like the react update code...
5644     // 
5645     
5646     var updateNode = function(from, to)
5647     {
5648         // should we handle non-standard elements?
5649         Roo.log(["UpdateNode" , from, to]);
5650         if (from.nodeType != to.nodeType) {
5651             Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
5652             from.parentNode.replaceChild(to, from);
5653         }
5654         
5655         if (from.nodeType == 3) {
5656             // assume it's text?!
5657             if (from.data == to.data) {
5658                 return;
5659             }
5660             from.data = to.data;
5661             return;
5662         }
5663         if (!from.parentNode) {
5664             // not sure why this is happening?
5665             return;
5666         }
5667         // assume 'to' doesnt have '1/3 nodetypes!
5668         // not sure why, by from, parent node might not exist?
5669         if (from.nodeType !=1 || from.tagName != to.tagName) {
5670             Roo.log(["ReplaceChild" , from, to ]);
5671             
5672             from.parentNode.replaceChild(to, from);
5673             return;
5674         }
5675         // compare attributes
5676         var ar = Array.from(from.attributes);
5677         for(var i = 0; i< ar.length;i++) {
5678             if (to.hasAttribute(ar[i].name)) {
5679                 continue;
5680             }
5681             if (ar[i].name == 'id') { // always keep ids?
5682                continue;
5683             }
5684             //if (ar[i].name == 'style') {
5685             //   throw "style removed?";
5686             //}
5687             Roo.log("removeAttribute" + ar[i].name);
5688             from.removeAttribute(ar[i].name);
5689         }
5690         ar = to.attributes;
5691         for(var i = 0; i< ar.length;i++) {
5692             if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5693                 Roo.log("skipAttribute " + ar[i].name  + '=' + to.getAttribute(ar[i].name));
5694                 continue;
5695             }
5696             Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
5697             from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5698         }
5699         // children
5700         var far = Array.from(from.childNodes);
5701         var tar = Array.from(to.childNodes);
5702         // if the lengths are different.. then it's probably a editable content change, rather than
5703         // a change of the block definition..
5704         
5705         // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
5706          /*if (from.innerHTML == to.innerHTML) {
5707             return;
5708         }
5709         if (far.length != tar.length) {
5710             from.innerHTML = to.innerHTML;
5711             return;
5712         }
5713         */
5714         
5715         for(var i = 0; i < Math.max(tar.length, far.length); i++) {
5716             if (i >= far.length) {
5717                 from.appendChild(tar[i]);
5718                 Roo.log(["add", tar[i]]);
5719                 
5720             } else if ( i  >= tar.length) {
5721                 from.removeChild(far[i]);
5722                 Roo.log(["remove", far[i]]);
5723             } else {
5724                 
5725                 updateNode(far[i], tar[i]);
5726             }    
5727         }
5728         
5729         
5730         
5731         
5732     };
5733     
5734     
5735
5736     return {
5737         /** True to force the use of DOM instead of html fragments @type Boolean */
5738         useDom : false,
5739     
5740         /**
5741          * Returns the markup for the passed Element(s) config
5742          * @param {Object} o The Dom object spec (and children)
5743          * @return {String}
5744          */
5745         markup : function(o){
5746             return createHtml(o);
5747         },
5748     
5749         /**
5750          * Applies a style specification to an element
5751          * @param {String/HTMLElement} el The element to apply styles to
5752          * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5753          * a function which returns such a specification.
5754          */
5755         applyStyles : function(el, styles){
5756             if(styles){
5757                el = Roo.fly(el);
5758                if(typeof styles == "string"){
5759                    var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5760                    var matches;
5761                    while ((matches = re.exec(styles)) != null){
5762                        el.setStyle(matches[1], matches[2]);
5763                    }
5764                }else if (typeof styles == "object"){
5765                    for (var style in styles){
5766                       el.setStyle(style, styles[style]);
5767                    }
5768                }else if (typeof styles == "function"){
5769                     Roo.DomHelper.applyStyles(el, styles.call());
5770                }
5771             }
5772         },
5773     
5774         /**
5775          * Inserts an HTML fragment into the Dom
5776          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5777          * @param {HTMLElement} el The context element
5778          * @param {String} html The HTML fragmenet
5779          * @return {HTMLElement} The new node
5780          */
5781         insertHtml : function(where, el, html){
5782             where = where.toLowerCase();
5783             if(el.insertAdjacentHTML){
5784                 if(tableRe.test(el.tagName)){
5785                     var rs;
5786                     if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5787                         return rs;
5788                     }
5789                 }
5790                 switch(where){
5791                     case "beforebegin":
5792                         el.insertAdjacentHTML('BeforeBegin', html);
5793                         return el.previousSibling;
5794                     case "afterbegin":
5795                         el.insertAdjacentHTML('AfterBegin', html);
5796                         return el.firstChild;
5797                     case "beforeend":
5798                         el.insertAdjacentHTML('BeforeEnd', html);
5799                         return el.lastChild;
5800                     case "afterend":
5801                         el.insertAdjacentHTML('AfterEnd', html);
5802                         return el.nextSibling;
5803                 }
5804                 throw 'Illegal insertion point -> "' + where + '"';
5805             }
5806             var range = el.ownerDocument.createRange();
5807             var frag;
5808             switch(where){
5809                  case "beforebegin":
5810                     range.setStartBefore(el);
5811                     frag = range.createContextualFragment(html);
5812                     el.parentNode.insertBefore(frag, el);
5813                     return el.previousSibling;
5814                  case "afterbegin":
5815                     if(el.firstChild){
5816                         range.setStartBefore(el.firstChild);
5817                         frag = range.createContextualFragment(html);
5818                         el.insertBefore(frag, el.firstChild);
5819                         return el.firstChild;
5820                     }else{
5821                         el.innerHTML = html;
5822                         return el.firstChild;
5823                     }
5824                 case "beforeend":
5825                     if(el.lastChild){
5826                         range.setStartAfter(el.lastChild);
5827                         frag = range.createContextualFragment(html);
5828                         el.appendChild(frag);
5829                         return el.lastChild;
5830                     }else{
5831                         el.innerHTML = html;
5832                         return el.lastChild;
5833                     }
5834                 case "afterend":
5835                     range.setStartAfter(el);
5836                     frag = range.createContextualFragment(html);
5837                     el.parentNode.insertBefore(frag, el.nextSibling);
5838                     return el.nextSibling;
5839                 }
5840                 throw 'Illegal insertion point -> "' + where + '"';
5841         },
5842     
5843         /**
5844          * Creates new Dom element(s) and inserts them before el
5845          * @param {String/HTMLElement/Element} el The context element
5846          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5847          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5848          * @return {HTMLElement/Roo.Element} The new node
5849          */
5850         insertBefore : function(el, o, returnElement){
5851             return this.doInsert(el, o, returnElement, "beforeBegin");
5852         },
5853     
5854         /**
5855          * Creates new Dom element(s) and inserts them after el
5856          * @param {String/HTMLElement/Element} el The context element
5857          * @param {Object} o The Dom object spec (and children)
5858          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5859          * @return {HTMLElement/Roo.Element} The new node
5860          */
5861         insertAfter : function(el, o, returnElement){
5862             return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5863         },
5864     
5865         /**
5866          * Creates new Dom element(s) and inserts them as the first child of el
5867          * @param {String/HTMLElement/Element} el The context element
5868          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5869          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5870          * @return {HTMLElement/Roo.Element} The new node
5871          */
5872         insertFirst : function(el, o, returnElement){
5873             return this.doInsert(el, o, returnElement, "afterBegin");
5874         },
5875     
5876         // private
5877         doInsert : function(el, o, returnElement, pos, sibling){
5878             el = Roo.getDom(el);
5879             var newNode;
5880             if(this.useDom || o.ns){
5881                 newNode = createDom(o, null);
5882                 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5883             }else{
5884                 var html = createHtml(o);
5885                 newNode = this.insertHtml(pos, el, html);
5886             }
5887             return returnElement ? Roo.get(newNode, true) : newNode;
5888         },
5889     
5890         /**
5891          * Creates new Dom element(s) and appends them to el
5892          * @param {String/HTMLElement/Element} el The context element
5893          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5894          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5895          * @return {HTMLElement/Roo.Element} The new node
5896          */
5897         append : function(el, o, returnElement){
5898             el = Roo.getDom(el);
5899             var newNode;
5900             if(this.useDom || o.ns){
5901                 newNode = createDom(o, null);
5902                 el.appendChild(newNode);
5903             }else{
5904                 var html = createHtml(o);
5905                 newNode = this.insertHtml("beforeEnd", el, html);
5906             }
5907             return returnElement ? Roo.get(newNode, true) : newNode;
5908         },
5909     
5910         /**
5911          * Creates new Dom element(s) and overwrites the contents of el with them
5912          * @param {String/HTMLElement/Element} el The context element
5913          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5914          * @param {Boolean} returnElement (optional) true to return a Roo.Element
5915          * @return {HTMLElement/Roo.Element} The new node
5916          */
5917         overwrite : function(el, o, returnElement)
5918         {
5919             el = Roo.getDom(el);
5920             if (o.ns) {
5921               
5922                 while (el.childNodes.length) {
5923                     el.removeChild(el.firstChild);
5924                 }
5925                 createDom(o, el);
5926             } else {
5927                 el.innerHTML = createHtml(o);   
5928             }
5929             
5930             return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5931         },
5932     
5933         /**
5934          * Creates a new Roo.DomHelper.Template from the Dom object spec
5935          * @param {Object} o The Dom object spec (and children)
5936          * @return {Roo.DomHelper.Template} The new template
5937          */
5938         createTemplate : function(o){
5939             var html = createHtml(o);
5940             return new Roo.Template(html);
5941         },
5942          /**
5943          * Updates the first element with the spec from the o (replacing if necessary)
5944          * This iterates through the children, and updates attributes / children etc..
5945          * @param {String/HTMLElement/Element} el The context element
5946          * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5947          */
5948         
5949         update : function(el, o)
5950         {
5951             updateNode(Roo.getDom(el), createDom(o));
5952             
5953         }
5954         
5955         
5956     };
5957 }();
5958 /*
5959  * Based on:
5960  * Ext JS Library 1.1.1
5961  * Copyright(c) 2006-2007, Ext JS, LLC.
5962  *
5963  * Originally Released Under LGPL - original licence link has changed is not relivant.
5964  *
5965  * Fork - LGPL
5966  * <script type="text/javascript">
5967  */
5968  
5969 /**
5970 * @class Roo.Template
5971 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5972 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5973 * Usage:
5974 <pre><code>
5975 var t = new Roo.Template({
5976     html :  '&lt;div name="{id}"&gt;' + 
5977         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
5978         '&lt;/div&gt;',
5979     myformat: function (value, allValues) {
5980         return 'XX' + value;
5981     }
5982 });
5983 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5984 </code></pre>
5985 * For more information see this blog post with examples:
5986 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5987      - Create Elements using DOM, HTML fragments and Templates</a>. 
5988 * @constructor
5989 * @param {Object} cfg - Configuration object.
5990 */
5991 Roo.Template = function(cfg){
5992     // BC!
5993     if(cfg instanceof Array){
5994         cfg = cfg.join("");
5995     }else if(arguments.length > 1){
5996         cfg = Array.prototype.join.call(arguments, "");
5997     }
5998     
5999     
6000     if (typeof(cfg) == 'object') {
6001         Roo.apply(this,cfg)
6002     } else {
6003         // bc
6004         this.html = cfg;
6005     }
6006     if (this.url) {
6007         this.load();
6008     }
6009     
6010 };
6011 Roo.Template.prototype = {
6012     
6013     /**
6014      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
6015      */
6016     onLoad : false,
6017     
6018     
6019     /**
6020      * @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..
6021      *                    it should be fixed so that template is observable...
6022      */
6023     url : false,
6024     /**
6025      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
6026      */
6027     html : '',
6028     
6029     
6030     compiled : false,
6031     loaded : false,
6032     /**
6033      * Returns an HTML fragment of this template with the specified values applied.
6034      * @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'})
6035      * @return {String} The HTML fragment
6036      */
6037     
6038    
6039     
6040     applyTemplate : function(values){
6041         //Roo.log(["applyTemplate", values]);
6042         try {
6043            
6044             if(this.compiled){
6045                 return this.compiled(values);
6046             }
6047             var useF = this.disableFormats !== true;
6048             var fm = Roo.util.Format, tpl = this;
6049             var fn = function(m, name, format, args){
6050                 if(format && useF){
6051                     if(format.substr(0, 5) == "this."){
6052                         return tpl.call(format.substr(5), values[name], values);
6053                     }else{
6054                         if(args){
6055                             // quoted values are required for strings in compiled templates, 
6056                             // but for non compiled we need to strip them
6057                             // quoted reversed for jsmin
6058                             var re = /^\s*['"](.*)["']\s*$/;
6059                             args = args.split(',');
6060                             for(var i = 0, len = args.length; i < len; i++){
6061                                 args[i] = args[i].replace(re, "$1");
6062                             }
6063                             args = [values[name]].concat(args);
6064                         }else{
6065                             args = [values[name]];
6066                         }
6067                         return fm[format].apply(fm, args);
6068                     }
6069                 }else{
6070                     return values[name] !== undefined ? values[name] : "";
6071                 }
6072             };
6073             return this.html.replace(this.re, fn);
6074         } catch (e) {
6075             Roo.log(e);
6076             throw e;
6077         }
6078          
6079     },
6080     
6081     loading : false,
6082       
6083     load : function ()
6084     {
6085          
6086         if (this.loading) {
6087             return;
6088         }
6089         var _t = this;
6090         
6091         this.loading = true;
6092         this.compiled = false;
6093         
6094         var cx = new Roo.data.Connection();
6095         cx.request({
6096             url : this.url,
6097             method : 'GET',
6098             success : function (response) {
6099                 _t.loading = false;
6100                 _t.url = false;
6101                 
6102                 _t.set(response.responseText,true);
6103                 _t.loaded = true;
6104                 if (_t.onLoad) {
6105                     _t.onLoad();
6106                 }
6107              },
6108             failure : function(response) {
6109                 Roo.log("Template failed to load from " + _t.url);
6110                 _t.loading = false;
6111             }
6112         });
6113     },
6114
6115     /**
6116      * Sets the HTML used as the template and optionally compiles it.
6117      * @param {String} html
6118      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
6119      * @return {Roo.Template} this
6120      */
6121     set : function(html, compile){
6122         this.html = html;
6123         this.compiled = false;
6124         if(compile){
6125             this.compile();
6126         }
6127         return this;
6128     },
6129     
6130     /**
6131      * True to disable format functions (defaults to false)
6132      * @type Boolean
6133      */
6134     disableFormats : false,
6135     
6136     /**
6137     * The regular expression used to match template variables 
6138     * @type RegExp
6139     * @property 
6140     */
6141     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
6142     
6143     /**
6144      * Compiles the template into an internal function, eliminating the RegEx overhead.
6145      * @return {Roo.Template} this
6146      */
6147     compile : function(){
6148         var fm = Roo.util.Format;
6149         var useF = this.disableFormats !== true;
6150         var sep = Roo.isGecko ? "+" : ",";
6151         var fn = function(m, name, format, args){
6152             if(format && useF){
6153                 args = args ? ',' + args : "";
6154                 if(format.substr(0, 5) != "this."){
6155                     format = "fm." + format + '(';
6156                 }else{
6157                     format = 'this.call("'+ format.substr(5) + '", ';
6158                     args = ", values";
6159                 }
6160             }else{
6161                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
6162             }
6163             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
6164         };
6165         var body;
6166         // branched to use + in gecko and [].join() in others
6167         if(Roo.isGecko){
6168             body = "this.compiled = function(values){ return '" +
6169                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
6170                     "';};";
6171         }else{
6172             body = ["this.compiled = function(values){ return ['"];
6173             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
6174             body.push("'].join('');};");
6175             body = body.join('');
6176         }
6177         /**
6178          * eval:var:values
6179          * eval:var:fm
6180          */
6181         eval(body);
6182         return this;
6183     },
6184     
6185     // private function used to call members
6186     call : function(fnName, value, allValues){
6187         return this[fnName](value, allValues);
6188     },
6189     
6190     /**
6191      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
6192      * @param {String/HTMLElement/Roo.Element} el The context element
6193      * @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'})
6194      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6195      * @return {HTMLElement/Roo.Element} The new node or Element
6196      */
6197     insertFirst: function(el, values, returnElement){
6198         return this.doInsert('afterBegin', el, values, returnElement);
6199     },
6200
6201     /**
6202      * Applies the supplied values to the template and inserts the new node(s) before el.
6203      * @param {String/HTMLElement/Roo.Element} el The context element
6204      * @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'})
6205      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6206      * @return {HTMLElement/Roo.Element} The new node or Element
6207      */
6208     insertBefore: function(el, values, returnElement){
6209         return this.doInsert('beforeBegin', el, values, returnElement);
6210     },
6211
6212     /**
6213      * Applies the supplied values to the template and inserts the new node(s) after el.
6214      * @param {String/HTMLElement/Roo.Element} el The context element
6215      * @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'})
6216      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6217      * @return {HTMLElement/Roo.Element} The new node or Element
6218      */
6219     insertAfter : function(el, values, returnElement){
6220         return this.doInsert('afterEnd', el, values, returnElement);
6221     },
6222     
6223     /**
6224      * Applies the supplied values to the template and appends the new node(s) to el.
6225      * @param {String/HTMLElement/Roo.Element} el The context element
6226      * @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'})
6227      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6228      * @return {HTMLElement/Roo.Element} The new node or Element
6229      */
6230     append : function(el, values, returnElement){
6231         return this.doInsert('beforeEnd', el, values, returnElement);
6232     },
6233
6234     doInsert : function(where, el, values, returnEl){
6235         el = Roo.getDom(el);
6236         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
6237         return returnEl ? Roo.get(newNode, true) : newNode;
6238     },
6239
6240     /**
6241      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
6242      * @param {String/HTMLElement/Roo.Element} el The context element
6243      * @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'})
6244      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
6245      * @return {HTMLElement/Roo.Element} The new node or Element
6246      */
6247     overwrite : function(el, values, returnElement){
6248         el = Roo.getDom(el);
6249         el.innerHTML = this.applyTemplate(values);
6250         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
6251     }
6252 };
6253 /**
6254  * Alias for {@link #applyTemplate}
6255  * @method
6256  */
6257 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
6258
6259 // backwards compat
6260 Roo.DomHelper.Template = Roo.Template;
6261
6262 /**
6263  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
6264  * @param {String/HTMLElement} el A DOM element or its id
6265  * @returns {Roo.Template} The created template
6266  * @static
6267  */
6268 Roo.Template.from = function(el){
6269     el = Roo.getDom(el);
6270     return new Roo.Template(el.value || el.innerHTML);
6271 };/*
6272  * Based on:
6273  * Ext JS Library 1.1.1
6274  * Copyright(c) 2006-2007, Ext JS, LLC.
6275  *
6276  * Originally Released Under LGPL - original licence link has changed is not relivant.
6277  *
6278  * Fork - LGPL
6279  * <script type="text/javascript">
6280  */
6281  
6282
6283 /*
6284  * This is code is also distributed under MIT license for use
6285  * with jQuery and prototype JavaScript libraries.
6286  */
6287 /**
6288  * @class Roo.DomQuery
6289 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).
6290 <p>
6291 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>
6292
6293 <p>
6294 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.
6295 </p>
6296 <h4>Element Selectors:</h4>
6297 <ul class="list">
6298     <li> <b>*</b> any element</li>
6299     <li> <b>E</b> an element with the tag E</li>
6300     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
6301     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
6302     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
6303     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
6304 </ul>
6305 <h4>Attribute Selectors:</h4>
6306 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
6307 <ul class="list">
6308     <li> <b>E[foo]</b> has an attribute "foo"</li>
6309     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
6310     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
6311     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
6312     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
6313     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
6314     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
6315 </ul>
6316 <h4>Pseudo Classes:</h4>
6317 <ul class="list">
6318     <li> <b>E:first-child</b> E is the first child of its parent</li>
6319     <li> <b>E:last-child</b> E is the last child of its parent</li>
6320     <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>
6321     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
6322     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
6323     <li> <b>E:only-child</b> E is the only child of its parent</li>
6324     <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>
6325     <li> <b>E:first</b> the first E in the resultset</li>
6326     <li> <b>E:last</b> the last E in the resultset</li>
6327     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
6328     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
6329     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
6330     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
6331     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
6332     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
6333     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
6334     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
6335     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
6336 </ul>
6337 <h4>CSS Value Selectors:</h4>
6338 <ul class="list">
6339     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
6340     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
6341     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
6342     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
6343     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
6344     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
6345 </ul>
6346  * @static
6347  */
6348 Roo.DomQuery = function(){
6349     var cache = {}, simpleCache = {}, valueCache = {};
6350     var nonSpace = /\S/;
6351     var trimRe = /^\s+|\s+$/g;
6352     var tplRe = /\{(\d+)\}/g;
6353     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
6354     var tagTokenRe = /^(#)?([\w-\*]+)/;
6355     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
6356
6357     function child(p, index){
6358         var i = 0;
6359         var n = p.firstChild;
6360         while(n){
6361             if(n.nodeType == 1){
6362                if(++i == index){
6363                    return n;
6364                }
6365             }
6366             n = n.nextSibling;
6367         }
6368         return null;
6369     };
6370
6371     function next(n){
6372         while((n = n.nextSibling) && n.nodeType != 1);
6373         return n;
6374     };
6375
6376     function prev(n){
6377         while((n = n.previousSibling) && n.nodeType != 1);
6378         return n;
6379     };
6380
6381     function children(d){
6382         var n = d.firstChild, ni = -1;
6383             while(n){
6384                 var nx = n.nextSibling;
6385                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
6386                     d.removeChild(n);
6387                 }else{
6388                     n.nodeIndex = ++ni;
6389                 }
6390                 n = nx;
6391             }
6392             return this;
6393         };
6394
6395     function byClassName(c, a, v){
6396         if(!v){
6397             return c;
6398         }
6399         var r = [], ri = -1, cn;
6400         for(var i = 0, ci; ci = c[i]; i++){
6401             
6402             
6403             if((' '+
6404                 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
6405                  +' ').indexOf(v) != -1){
6406                 r[++ri] = ci;
6407             }
6408         }
6409         return r;
6410     };
6411
6412     function attrValue(n, attr){
6413         if(!n.tagName && typeof n.length != "undefined"){
6414             n = n[0];
6415         }
6416         if(!n){
6417             return null;
6418         }
6419         if(attr == "for"){
6420             return n.htmlFor;
6421         }
6422         if(attr == "class" || attr == "className"){
6423             return (n instanceof SVGElement) ? n.className.baseVal : n.className;
6424         }
6425         return n.getAttribute(attr) || n[attr];
6426
6427     };
6428
6429     function getNodes(ns, mode, tagName){
6430         var result = [], ri = -1, cs;
6431         if(!ns){
6432             return result;
6433         }
6434         tagName = tagName || "*";
6435         if(typeof ns.getElementsByTagName != "undefined"){
6436             ns = [ns];
6437         }
6438         if(!mode){
6439             for(var i = 0, ni; ni = ns[i]; i++){
6440                 cs = ni.getElementsByTagName(tagName);
6441                 for(var j = 0, ci; ci = cs[j]; j++){
6442                     result[++ri] = ci;
6443                 }
6444             }
6445         }else if(mode == "/" || mode == ">"){
6446             var utag = tagName.toUpperCase();
6447             for(var i = 0, ni, cn; ni = ns[i]; i++){
6448                 cn = ni.children || ni.childNodes;
6449                 for(var j = 0, cj; cj = cn[j]; j++){
6450                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
6451                         result[++ri] = cj;
6452                     }
6453                 }
6454             }
6455         }else if(mode == "+"){
6456             var utag = tagName.toUpperCase();
6457             for(var i = 0, n; n = ns[i]; i++){
6458                 while((n = n.nextSibling) && n.nodeType != 1);
6459                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
6460                     result[++ri] = n;
6461                 }
6462             }
6463         }else if(mode == "~"){
6464             for(var i = 0, n; n = ns[i]; i++){
6465                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
6466                 if(n){
6467                     result[++ri] = n;
6468                 }
6469             }
6470         }
6471         return result;
6472     };
6473
6474     function concat(a, b){
6475         if(b.slice){
6476             return a.concat(b);
6477         }
6478         for(var i = 0, l = b.length; i < l; i++){
6479             a[a.length] = b[i];
6480         }
6481         return a;
6482     }
6483
6484     function byTag(cs, tagName){
6485         if(cs.tagName || cs == document){
6486             cs = [cs];
6487         }
6488         if(!tagName){
6489             return cs;
6490         }
6491         var r = [], ri = -1;
6492         tagName = tagName.toLowerCase();
6493         for(var i = 0, ci; ci = cs[i]; i++){
6494             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
6495                 r[++ri] = ci;
6496             }
6497         }
6498         return r;
6499     };
6500
6501     function byId(cs, attr, id){
6502         if(cs.tagName || cs == document){
6503             cs = [cs];
6504         }
6505         if(!id){
6506             return cs;
6507         }
6508         var r = [], ri = -1;
6509         for(var i = 0,ci; ci = cs[i]; i++){
6510             if(ci && ci.id == id){
6511                 r[++ri] = ci;
6512                 return r;
6513             }
6514         }
6515         return r;
6516     };
6517
6518     function byAttribute(cs, attr, value, op, custom){
6519         var r = [], ri = -1, st = custom=="{";
6520         var f = Roo.DomQuery.operators[op];
6521         for(var i = 0, ci; ci = cs[i]; i++){
6522             var a;
6523             if(st){
6524                 a = Roo.DomQuery.getStyle(ci, attr);
6525             }
6526             else if(attr == "class" || attr == "className"){
6527                 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6528             }else if(attr == "for"){
6529                 a = ci.htmlFor;
6530             }else if(attr == "href"){
6531                 a = ci.getAttribute("href", 2);
6532             }else{
6533                 a = ci.getAttribute(attr);
6534             }
6535             if((f && f(a, value)) || (!f && a)){
6536                 r[++ri] = ci;
6537             }
6538         }
6539         return r;
6540     };
6541
6542     function byPseudo(cs, name, value){
6543         return Roo.DomQuery.pseudos[name](cs, value);
6544     };
6545
6546     // This is for IE MSXML which does not support expandos.
6547     // IE runs the same speed using setAttribute, however FF slows way down
6548     // and Safari completely fails so they need to continue to use expandos.
6549     var isIE = window.ActiveXObject ? true : false;
6550
6551     // this eval is stop the compressor from
6552     // renaming the variable to something shorter
6553     
6554     /** eval:var:batch */
6555     var batch = 30803; 
6556
6557     var key = 30803;
6558
6559     function nodupIEXml(cs){
6560         var d = ++key;
6561         cs[0].setAttribute("_nodup", d);
6562         var r = [cs[0]];
6563         for(var i = 1, len = cs.length; i < len; i++){
6564             var c = cs[i];
6565             if(!c.getAttribute("_nodup") != d){
6566                 c.setAttribute("_nodup", d);
6567                 r[r.length] = c;
6568             }
6569         }
6570         for(var i = 0, len = cs.length; i < len; i++){
6571             cs[i].removeAttribute("_nodup");
6572         }
6573         return r;
6574     }
6575
6576     function nodup(cs){
6577         if(!cs){
6578             return [];
6579         }
6580         var len = cs.length, c, i, r = cs, cj, ri = -1;
6581         if(!len || typeof cs.nodeType != "undefined" || len == 1){
6582             return cs;
6583         }
6584         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6585             return nodupIEXml(cs);
6586         }
6587         var d = ++key;
6588         cs[0]._nodup = d;
6589         for(i = 1; c = cs[i]; i++){
6590             if(c._nodup != d){
6591                 c._nodup = d;
6592             }else{
6593                 r = [];
6594                 for(var j = 0; j < i; j++){
6595                     r[++ri] = cs[j];
6596                 }
6597                 for(j = i+1; cj = cs[j]; j++){
6598                     if(cj._nodup != d){
6599                         cj._nodup = d;
6600                         r[++ri] = cj;
6601                     }
6602                 }
6603                 return r;
6604             }
6605         }
6606         return r;
6607     }
6608
6609     function quickDiffIEXml(c1, c2){
6610         var d = ++key;
6611         for(var i = 0, len = c1.length; i < len; i++){
6612             c1[i].setAttribute("_qdiff", d);
6613         }
6614         var r = [];
6615         for(var i = 0, len = c2.length; i < len; i++){
6616             if(c2[i].getAttribute("_qdiff") != d){
6617                 r[r.length] = c2[i];
6618             }
6619         }
6620         for(var i = 0, len = c1.length; i < len; i++){
6621            c1[i].removeAttribute("_qdiff");
6622         }
6623         return r;
6624     }
6625
6626     function quickDiff(c1, c2){
6627         var len1 = c1.length;
6628         if(!len1){
6629             return c2;
6630         }
6631         if(isIE && c1[0].selectSingleNode){
6632             return quickDiffIEXml(c1, c2);
6633         }
6634         var d = ++key;
6635         for(var i = 0; i < len1; i++){
6636             c1[i]._qdiff = d;
6637         }
6638         var r = [];
6639         for(var i = 0, len = c2.length; i < len; i++){
6640             if(c2[i]._qdiff != d){
6641                 r[r.length] = c2[i];
6642             }
6643         }
6644         return r;
6645     }
6646
6647     function quickId(ns, mode, root, id){
6648         if(ns == root){
6649            var d = root.ownerDocument || root;
6650            return d.getElementById(id);
6651         }
6652         ns = getNodes(ns, mode, "*");
6653         return byId(ns, null, id);
6654     }
6655
6656     return {
6657         getStyle : function(el, name){
6658             return Roo.fly(el).getStyle(name);
6659         },
6660         /**
6661          * Compiles a selector/xpath query into a reusable function. The returned function
6662          * takes one parameter "root" (optional), which is the context node from where the query should start.
6663          * @param {String} selector The selector/xpath query
6664          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6665          * @return {Function}
6666          */
6667         compile : function(path, type){
6668             type = type || "select";
6669             
6670             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6671             var q = path, mode, lq;
6672             var tk = Roo.DomQuery.matchers;
6673             var tklen = tk.length;
6674             var mm;
6675
6676             // accept leading mode switch
6677             var lmode = q.match(modeRe);
6678             if(lmode && lmode[1]){
6679                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6680                 q = q.replace(lmode[1], "");
6681             }
6682             // strip leading slashes
6683             while(path.substr(0, 1)=="/"){
6684                 path = path.substr(1);
6685             }
6686
6687             while(q && lq != q){
6688                 lq = q;
6689                 var tm = q.match(tagTokenRe);
6690                 if(type == "select"){
6691                     if(tm){
6692                         if(tm[1] == "#"){
6693                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6694                         }else{
6695                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6696                         }
6697                         q = q.replace(tm[0], "");
6698                     }else if(q.substr(0, 1) != '@'){
6699                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
6700                     }
6701                 }else{
6702                     if(tm){
6703                         if(tm[1] == "#"){
6704                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6705                         }else{
6706                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6707                         }
6708                         q = q.replace(tm[0], "");
6709                     }
6710                 }
6711                 while(!(mm = q.match(modeRe))){
6712                     var matched = false;
6713                     for(var j = 0; j < tklen; j++){
6714                         var t = tk[j];
6715                         var m = q.match(t.re);
6716                         if(m){
6717                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
6718                                                     return m[i];
6719                                                 });
6720                             q = q.replace(m[0], "");
6721                             matched = true;
6722                             break;
6723                         }
6724                     }
6725                     // prevent infinite loop on bad selector
6726                     if(!matched){
6727                         throw 'Error parsing selector, parsing failed at "' + q + '"';
6728                     }
6729                 }
6730                 if(mm[1]){
6731                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6732                     q = q.replace(mm[1], "");
6733                 }
6734             }
6735             fn[fn.length] = "return nodup(n);\n}";
6736             
6737              /** 
6738               * list of variables that need from compression as they are used by eval.
6739              *  eval:var:batch 
6740              *  eval:var:nodup
6741              *  eval:var:byTag
6742              *  eval:var:ById
6743              *  eval:var:getNodes
6744              *  eval:var:quickId
6745              *  eval:var:mode
6746              *  eval:var:root
6747              *  eval:var:n
6748              *  eval:var:byClassName
6749              *  eval:var:byPseudo
6750              *  eval:var:byAttribute
6751              *  eval:var:attrValue
6752              * 
6753              **/ 
6754             eval(fn.join(""));
6755             return f;
6756         },
6757
6758         /**
6759          * Selects a group of elements.
6760          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6761          * @param {Node} root (optional) The start of the query (defaults to document).
6762          * @return {Array}
6763          */
6764         select : function(path, root, type){
6765             if(!root || root == document){
6766                 root = document;
6767             }
6768             if(typeof root == "string"){
6769                 root = document.getElementById(root);
6770             }
6771             var paths = path.split(",");
6772             var results = [];
6773             for(var i = 0, len = paths.length; i < len; i++){
6774                 var p = paths[i].replace(trimRe, "");
6775                 if(!cache[p]){
6776                     cache[p] = Roo.DomQuery.compile(p);
6777                     if(!cache[p]){
6778                         throw p + " is not a valid selector";
6779                     }
6780                 }
6781                 var result = cache[p](root);
6782                 if(result && result != document){
6783                     results = results.concat(result);
6784                 }
6785             }
6786             if(paths.length > 1){
6787                 return nodup(results);
6788             }
6789             return results;
6790         },
6791
6792         /**
6793          * Selects a single element.
6794          * @param {String} selector The selector/xpath query
6795          * @param {Node} root (optional) The start of the query (defaults to document).
6796          * @return {Element}
6797          */
6798         selectNode : function(path, root){
6799             return Roo.DomQuery.select(path, root)[0];
6800         },
6801
6802         /**
6803          * Selects the value of a node, optionally replacing null with the defaultValue.
6804          * @param {String} selector The selector/xpath query
6805          * @param {Node} root (optional) The start of the query (defaults to document).
6806          * @param {String} defaultValue
6807          */
6808         selectValue : function(path, root, defaultValue){
6809             path = path.replace(trimRe, "");
6810             if(!valueCache[path]){
6811                 valueCache[path] = Roo.DomQuery.compile(path, "select");
6812             }
6813             var n = valueCache[path](root);
6814             n = n[0] ? n[0] : n;
6815             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6816             return ((v === null||v === undefined||v==='') ? defaultValue : v);
6817         },
6818
6819         /**
6820          * Selects the value of a node, parsing integers and floats.
6821          * @param {String} selector The selector/xpath query
6822          * @param {Node} root (optional) The start of the query (defaults to document).
6823          * @param {Number} defaultValue
6824          * @return {Number}
6825          */
6826         selectNumber : function(path, root, defaultValue){
6827             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6828             return parseFloat(v);
6829         },
6830
6831         /**
6832          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6833          * @param {String/HTMLElement/Array} el An element id, element or array of elements
6834          * @param {String} selector The simple selector to test
6835          * @return {Boolean}
6836          */
6837         is : function(el, ss){
6838             if(typeof el == "string"){
6839                 el = document.getElementById(el);
6840             }
6841             var isArray = (el instanceof Array);
6842             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6843             return isArray ? (result.length == el.length) : (result.length > 0);
6844         },
6845
6846         /**
6847          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6848          * @param {Array} el An array of elements to filter
6849          * @param {String} selector The simple selector to test
6850          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6851          * the selector instead of the ones that match
6852          * @return {Array}
6853          */
6854         filter : function(els, ss, nonMatches){
6855             ss = ss.replace(trimRe, "");
6856             if(!simpleCache[ss]){
6857                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6858             }
6859             var result = simpleCache[ss](els);
6860             return nonMatches ? quickDiff(result, els) : result;
6861         },
6862
6863         /**
6864          * Collection of matching regular expressions and code snippets.
6865          */
6866         matchers : [{
6867                 re: /^\.([\w-]+)/,
6868                 select: 'n = byClassName(n, null, " {1} ");'
6869             }, {
6870                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6871                 select: 'n = byPseudo(n, "{1}", "{2}");'
6872             },{
6873                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6874                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6875             }, {
6876                 re: /^#([\w-]+)/,
6877                 select: 'n = byId(n, null, "{1}");'
6878             },{
6879                 re: /^@([\w-]+)/,
6880                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6881             }
6882         ],
6883
6884         /**
6885          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6886          * 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;.
6887          */
6888         operators : {
6889             "=" : function(a, v){
6890                 return a == v;
6891             },
6892             "!=" : function(a, v){
6893                 return a != v;
6894             },
6895             "^=" : function(a, v){
6896                 return a && a.substr(0, v.length) == v;
6897             },
6898             "$=" : function(a, v){
6899                 return a && a.substr(a.length-v.length) == v;
6900             },
6901             "*=" : function(a, v){
6902                 return a && a.indexOf(v) !== -1;
6903             },
6904             "%=" : function(a, v){
6905                 return (a % v) == 0;
6906             },
6907             "|=" : function(a, v){
6908                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6909             },
6910             "~=" : function(a, v){
6911                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6912             }
6913         },
6914
6915         /**
6916          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6917          * and the argument (if any) supplied in the selector.
6918          */
6919         pseudos : {
6920             "first-child" : function(c){
6921                 var r = [], ri = -1, n;
6922                 for(var i = 0, ci; ci = n = c[i]; i++){
6923                     while((n = n.previousSibling) && n.nodeType != 1);
6924                     if(!n){
6925                         r[++ri] = ci;
6926                     }
6927                 }
6928                 return r;
6929             },
6930
6931             "last-child" : function(c){
6932                 var r = [], ri = -1, n;
6933                 for(var i = 0, ci; ci = n = c[i]; i++){
6934                     while((n = n.nextSibling) && n.nodeType != 1);
6935                     if(!n){
6936                         r[++ri] = ci;
6937                     }
6938                 }
6939                 return r;
6940             },
6941
6942             "nth-child" : function(c, a) {
6943                 var r = [], ri = -1;
6944                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6945                 var f = (m[1] || 1) - 0, l = m[2] - 0;
6946                 for(var i = 0, n; n = c[i]; i++){
6947                     var pn = n.parentNode;
6948                     if (batch != pn._batch) {
6949                         var j = 0;
6950                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6951                             if(cn.nodeType == 1){
6952                                cn.nodeIndex = ++j;
6953                             }
6954                         }
6955                         pn._batch = batch;
6956                     }
6957                     if (f == 1) {
6958                         if (l == 0 || n.nodeIndex == l){
6959                             r[++ri] = n;
6960                         }
6961                     } else if ((n.nodeIndex + l) % f == 0){
6962                         r[++ri] = n;
6963                     }
6964                 }
6965
6966                 return r;
6967             },
6968
6969             "only-child" : function(c){
6970                 var r = [], ri = -1;;
6971                 for(var i = 0, ci; ci = c[i]; i++){
6972                     if(!prev(ci) && !next(ci)){
6973                         r[++ri] = ci;
6974                     }
6975                 }
6976                 return r;
6977             },
6978
6979             "empty" : function(c){
6980                 var r = [], ri = -1;
6981                 for(var i = 0, ci; ci = c[i]; i++){
6982                     var cns = ci.childNodes, j = 0, cn, empty = true;
6983                     while(cn = cns[j]){
6984                         ++j;
6985                         if(cn.nodeType == 1 || cn.nodeType == 3){
6986                             empty = false;
6987                             break;
6988                         }
6989                     }
6990                     if(empty){
6991                         r[++ri] = ci;
6992                     }
6993                 }
6994                 return r;
6995             },
6996
6997             "contains" : function(c, v){
6998                 var r = [], ri = -1;
6999                 for(var i = 0, ci; ci = c[i]; i++){
7000                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
7001                         r[++ri] = ci;
7002                     }
7003                 }
7004                 return r;
7005             },
7006
7007             "nodeValue" : function(c, v){
7008                 var r = [], ri = -1;
7009                 for(var i = 0, ci; ci = c[i]; i++){
7010                     if(ci.firstChild && ci.firstChild.nodeValue == v){
7011                         r[++ri] = ci;
7012                     }
7013                 }
7014                 return r;
7015             },
7016
7017             "checked" : function(c){
7018                 var r = [], ri = -1;
7019                 for(var i = 0, ci; ci = c[i]; i++){
7020                     if(ci.checked == true){
7021                         r[++ri] = ci;
7022                     }
7023                 }
7024                 return r;
7025             },
7026
7027             "not" : function(c, ss){
7028                 return Roo.DomQuery.filter(c, ss, true);
7029             },
7030
7031             "odd" : function(c){
7032                 return this["nth-child"](c, "odd");
7033             },
7034
7035             "even" : function(c){
7036                 return this["nth-child"](c, "even");
7037             },
7038
7039             "nth" : function(c, a){
7040                 return c[a-1] || [];
7041             },
7042
7043             "first" : function(c){
7044                 return c[0] || [];
7045             },
7046
7047             "last" : function(c){
7048                 return c[c.length-1] || [];
7049             },
7050
7051             "has" : function(c, ss){
7052                 var s = Roo.DomQuery.select;
7053                 var r = [], ri = -1;
7054                 for(var i = 0, ci; ci = c[i]; i++){
7055                     if(s(ss, ci).length > 0){
7056                         r[++ri] = ci;
7057                     }
7058                 }
7059                 return r;
7060             },
7061
7062             "next" : function(c, ss){
7063                 var is = Roo.DomQuery.is;
7064                 var r = [], ri = -1;
7065                 for(var i = 0, ci; ci = c[i]; i++){
7066                     var n = next(ci);
7067                     if(n && is(n, ss)){
7068                         r[++ri] = ci;
7069                     }
7070                 }
7071                 return r;
7072             },
7073
7074             "prev" : function(c, ss){
7075                 var is = Roo.DomQuery.is;
7076                 var r = [], ri = -1;
7077                 for(var i = 0, ci; ci = c[i]; i++){
7078                     var n = prev(ci);
7079                     if(n && is(n, ss)){
7080                         r[++ri] = ci;
7081                     }
7082                 }
7083                 return r;
7084             }
7085         }
7086     };
7087 }();
7088
7089 /**
7090  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
7091  * @param {String} path The selector/xpath query
7092  * @param {Node} root (optional) The start of the query (defaults to document).
7093  * @return {Array}
7094  * @member Roo
7095  * @method query
7096  */
7097 Roo.query = Roo.DomQuery.select;
7098 /*
7099  * Based on:
7100  * Ext JS Library 1.1.1
7101  * Copyright(c) 2006-2007, Ext JS, LLC.
7102  *
7103  * Originally Released Under LGPL - original licence link has changed is not relivant.
7104  *
7105  * Fork - LGPL
7106  * <script type="text/javascript">
7107  */
7108
7109 /**
7110  * @class Roo.util.Observable
7111  * Base class that provides a common interface for publishing events. Subclasses are expected to
7112  * to have a property "events" with all the events defined.<br>
7113  * For example:
7114  * <pre><code>
7115  Employee = function(name){
7116     this.name = name;
7117     this.addEvents({
7118         "fired" : true,
7119         "quit" : true
7120     });
7121  }
7122  Roo.extend(Employee, Roo.util.Observable);
7123 </code></pre>
7124  * @param {Object} config properties to use (incuding events / listeners)
7125  */
7126
7127 Roo.util.Observable = function(cfg){
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     config = config || {};
16870     if(config.tagName || config.dom || typeof config == "string"){ // element object
16871         config = {el: config, id: config.id || config};
16872     }
16873     this.initialConfig = config;
16874
16875     Roo.apply(this, config);
16876     this.addEvents({
16877         /**
16878          * @event disable
16879          * Fires after the component is disabled.
16880              * @param {Roo.Component} this
16881              */
16882         disable : true,
16883         /**
16884          * @event enable
16885          * Fires after the component is enabled.
16886              * @param {Roo.Component} this
16887              */
16888         enable : true,
16889         /**
16890          * @event beforeshow
16891          * Fires before the component is shown.  Return false to stop the show.
16892              * @param {Roo.Component} this
16893              */
16894         beforeshow : true,
16895         /**
16896          * @event show
16897          * Fires after the component is shown.
16898              * @param {Roo.Component} this
16899              */
16900         show : true,
16901         /**
16902          * @event beforehide
16903          * Fires before the component is hidden. Return false to stop the hide.
16904              * @param {Roo.Component} this
16905              */
16906         beforehide : true,
16907         /**
16908          * @event hide
16909          * Fires after the component is hidden.
16910              * @param {Roo.Component} this
16911              */
16912         hide : true,
16913         /**
16914          * @event beforerender
16915          * Fires before the component is rendered. Return false to stop the render.
16916              * @param {Roo.Component} this
16917              */
16918         beforerender : true,
16919         /**
16920          * @event render
16921          * Fires after the component is rendered.
16922              * @param {Roo.Component} this
16923              */
16924         render : true,
16925         /**
16926          * @event beforedestroy
16927          * Fires before the component is destroyed. Return false to stop the destroy.
16928              * @param {Roo.Component} this
16929              */
16930         beforedestroy : true,
16931         /**
16932          * @event destroy
16933          * Fires after the component is destroyed.
16934              * @param {Roo.Component} this
16935              */
16936         destroy : true
16937     });
16938     if(!this.id){
16939         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16940     }
16941     Roo.ComponentMgr.register(this);
16942     Roo.Component.superclass.constructor.call(this);
16943     this.initComponent();
16944     if(this.renderTo){ // not supported by all components yet. use at your own risk!
16945         this.render(this.renderTo);
16946         delete this.renderTo;
16947     }
16948 };
16949
16950 /** @private */
16951 Roo.Component.AUTO_ID = 1000;
16952
16953 Roo.extend(Roo.Component, Roo.util.Observable, {
16954     /**
16955      * @scope Roo.Component.prototype
16956      * @type {Boolean}
16957      * true if this component is hidden. Read-only.
16958      */
16959     hidden : false,
16960     /**
16961      * @type {Boolean}
16962      * true if this component is disabled. Read-only.
16963      */
16964     disabled : false,
16965     /**
16966      * @type {Boolean}
16967      * true if this component has been rendered. Read-only.
16968      */
16969     rendered : false,
16970     
16971     /** @cfg {String} disableClass
16972      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16973      */
16974     disabledClass : "x-item-disabled",
16975         /** @cfg {Boolean} allowDomMove
16976          * Whether the component can move the Dom node when rendering (defaults to true).
16977          */
16978     allowDomMove : true,
16979     /** @cfg {String} hideMode (display|visibility)
16980      * How this component should hidden. Supported values are
16981      * "visibility" (css visibility), "offsets" (negative offset position) and
16982      * "display" (css display) - defaults to "display".
16983      */
16984     hideMode: 'display',
16985
16986     /** @private */
16987     ctype : "Roo.Component",
16988
16989     /**
16990      * @cfg {String} actionMode 
16991      * which property holds the element that used for  hide() / show() / disable() / enable()
16992      * default is 'el' for forms you probably want to set this to fieldEl 
16993      */
16994     actionMode : "el",
16995
16996     /** @private */
16997     getActionEl : function(){
16998         return this[this.actionMode];
16999     },
17000
17001     initComponent : Roo.emptyFn,
17002     /**
17003      * If this is a lazy rendering component, render it to its container element.
17004      * @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.
17005      */
17006     render : function(container, position){
17007         
17008         if(this.rendered){
17009             return this;
17010         }
17011         
17012         if(this.fireEvent("beforerender", this) === false){
17013             return false;
17014         }
17015         
17016         if(!container && this.el){
17017             this.el = Roo.get(this.el);
17018             container = this.el.dom.parentNode;
17019             this.allowDomMove = false;
17020         }
17021         this.container = Roo.get(container);
17022         this.rendered = true;
17023         if(position !== undefined){
17024             if(typeof position == 'number'){
17025                 position = this.container.dom.childNodes[position];
17026             }else{
17027                 position = Roo.getDom(position);
17028             }
17029         }
17030         this.onRender(this.container, position || null);
17031         if(this.cls){
17032             this.el.addClass(this.cls);
17033             delete this.cls;
17034         }
17035         if(this.style){
17036             this.el.applyStyles(this.style);
17037             delete this.style;
17038         }
17039         this.fireEvent("render", this);
17040         this.afterRender(this.container);
17041         if(this.hidden){
17042             this.hide();
17043         }
17044         if(this.disabled){
17045             this.disable();
17046         }
17047
17048         return this;
17049         
17050     },
17051
17052     /** @private */
17053     // default function is not really useful
17054     onRender : function(ct, position){
17055         if(this.el){
17056             this.el = Roo.get(this.el);
17057             if(this.allowDomMove !== false){
17058                 ct.dom.insertBefore(this.el.dom, position);
17059             }
17060         }
17061     },
17062
17063     /** @private */
17064     getAutoCreate : function(){
17065         var cfg = typeof this.autoCreate == "object" ?
17066                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
17067         if(this.id && !cfg.id){
17068             cfg.id = this.id;
17069         }
17070         return cfg;
17071     },
17072
17073     /** @private */
17074     afterRender : Roo.emptyFn,
17075
17076     /**
17077      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
17078      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
17079      */
17080     destroy : function(){
17081         if(this.fireEvent("beforedestroy", this) !== false){
17082             this.purgeListeners();
17083             this.beforeDestroy();
17084             if(this.rendered){
17085                 this.el.removeAllListeners();
17086                 this.el.remove();
17087                 if(this.actionMode == "container"){
17088                     this.container.remove();
17089                 }
17090             }
17091             this.onDestroy();
17092             Roo.ComponentMgr.unregister(this);
17093             this.fireEvent("destroy", this);
17094         }
17095     },
17096
17097         /** @private */
17098     beforeDestroy : function(){
17099
17100     },
17101
17102         /** @private */
17103         onDestroy : function(){
17104
17105     },
17106
17107     /**
17108      * Returns the underlying {@link Roo.Element}.
17109      * @return {Roo.Element} The element
17110      */
17111     getEl : function(){
17112         return this.el;
17113     },
17114
17115     /**
17116      * Returns the id of this component.
17117      * @return {String}
17118      */
17119     getId : function(){
17120         return this.id;
17121     },
17122
17123     /**
17124      * Try to focus this component.
17125      * @param {Boolean} selectText True to also select the text in this component (if applicable)
17126      * @return {Roo.Component} this
17127      */
17128     focus : function(selectText){
17129         if(this.rendered){
17130             this.el.focus();
17131             if(selectText === true){
17132                 this.el.dom.select();
17133             }
17134         }
17135         return this;
17136     },
17137
17138     /** @private */
17139     blur : function(){
17140         if(this.rendered){
17141             this.el.blur();
17142         }
17143         return this;
17144     },
17145
17146     /**
17147      * Disable this component.
17148      * @return {Roo.Component} this
17149      */
17150     disable : function(){
17151         if(this.rendered){
17152             this.onDisable();
17153         }
17154         this.disabled = true;
17155         this.fireEvent("disable", this);
17156         return this;
17157     },
17158
17159         // private
17160     onDisable : function(){
17161         this.getActionEl().addClass(this.disabledClass);
17162         this.el.dom.disabled = true;
17163     },
17164
17165     /**
17166      * Enable this component.
17167      * @return {Roo.Component} this
17168      */
17169     enable : function(){
17170         if(this.rendered){
17171             this.onEnable();
17172         }
17173         this.disabled = false;
17174         this.fireEvent("enable", this);
17175         return this;
17176     },
17177
17178         // private
17179     onEnable : function(){
17180         this.getActionEl().removeClass(this.disabledClass);
17181         this.el.dom.disabled = false;
17182     },
17183
17184     /**
17185      * Convenience function for setting disabled/enabled by boolean.
17186      * @param {Boolean} disabled
17187      */
17188     setDisabled : function(disabled){
17189         this[disabled ? "disable" : "enable"]();
17190     },
17191
17192     /**
17193      * Show this component.
17194      * @return {Roo.Component} this
17195      */
17196     show: function(){
17197         if(this.fireEvent("beforeshow", this) !== false){
17198             this.hidden = false;
17199             if(this.rendered){
17200                 this.onShow();
17201             }
17202             this.fireEvent("show", this);
17203         }
17204         return this;
17205     },
17206
17207     // private
17208     onShow : function(){
17209         var ae = this.getActionEl();
17210         if(this.hideMode == 'visibility'){
17211             ae.dom.style.visibility = "visible";
17212         }else if(this.hideMode == 'offsets'){
17213             ae.removeClass('x-hidden');
17214         }else{
17215             ae.dom.style.display = "";
17216         }
17217     },
17218
17219     /**
17220      * Hide this component.
17221      * @return {Roo.Component} this
17222      */
17223     hide: function(){
17224         if(this.fireEvent("beforehide", this) !== false){
17225             this.hidden = true;
17226             if(this.rendered){
17227                 this.onHide();
17228             }
17229             this.fireEvent("hide", this);
17230         }
17231         return this;
17232     },
17233
17234     // private
17235     onHide : function(){
17236         var ae = this.getActionEl();
17237         if(this.hideMode == 'visibility'){
17238             ae.dom.style.visibility = "hidden";
17239         }else if(this.hideMode == 'offsets'){
17240             ae.addClass('x-hidden');
17241         }else{
17242             ae.dom.style.display = "none";
17243         }
17244     },
17245
17246     /**
17247      * Convenience function to hide or show this component by boolean.
17248      * @param {Boolean} visible True to show, false to hide
17249      * @return {Roo.Component} this
17250      */
17251     setVisible: function(visible){
17252         if(visible) {
17253             this.show();
17254         }else{
17255             this.hide();
17256         }
17257         return this;
17258     },
17259
17260     /**
17261      * Returns true if this component is visible.
17262      */
17263     isVisible : function(){
17264         return this.getActionEl().isVisible();
17265     },
17266
17267     cloneConfig : function(overrides){
17268         overrides = overrides || {};
17269         var id = overrides.id || Roo.id();
17270         var cfg = Roo.applyIf(overrides, this.initialConfig);
17271         cfg.id = id; // prevent dup id
17272         return new this.constructor(cfg);
17273     }
17274 });/*
17275  * Based on:
17276  * Ext JS Library 1.1.1
17277  * Copyright(c) 2006-2007, Ext JS, LLC.
17278  *
17279  * Originally Released Under LGPL - original licence link has changed is not relivant.
17280  *
17281  * Fork - LGPL
17282  * <script type="text/javascript">
17283  */
17284
17285 /**
17286  * @class Roo.BoxComponent
17287  * @extends Roo.Component
17288  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
17289  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
17290  * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
17291  * layout containers.
17292  * @constructor
17293  * @param {Roo.Element/String/Object} config The configuration options.
17294  */
17295 Roo.BoxComponent = function(config){
17296     Roo.Component.call(this, config);
17297     this.addEvents({
17298         /**
17299          * @event resize
17300          * Fires after the component is resized.
17301              * @param {Roo.Component} this
17302              * @param {Number} adjWidth The box-adjusted width that was set
17303              * @param {Number} adjHeight The box-adjusted height that was set
17304              * @param {Number} rawWidth The width that was originally specified
17305              * @param {Number} rawHeight The height that was originally specified
17306              */
17307         resize : true,
17308         /**
17309          * @event move
17310          * Fires after the component is moved.
17311              * @param {Roo.Component} this
17312              * @param {Number} x The new x position
17313              * @param {Number} y The new y position
17314              */
17315         move : true
17316     });
17317 };
17318
17319 Roo.extend(Roo.BoxComponent, Roo.Component, {
17320     // private, set in afterRender to signify that the component has been rendered
17321     boxReady : false,
17322     // private, used to defer height settings to subclasses
17323     deferHeight: false,
17324     /** @cfg {Number} width
17325      * width (optional) size of component
17326      */
17327      /** @cfg {Number} height
17328      * height (optional) size of component
17329      */
17330      
17331     /**
17332      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
17333      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
17334      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
17335      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
17336      * @return {Roo.BoxComponent} this
17337      */
17338     setSize : function(w, h){
17339         // support for standard size objects
17340         if(typeof w == 'object'){
17341             h = w.height;
17342             w = w.width;
17343         }
17344         // not rendered
17345         if(!this.boxReady){
17346             this.width = w;
17347             this.height = h;
17348             return this;
17349         }
17350
17351         // prevent recalcs when not needed
17352         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
17353             return this;
17354         }
17355         this.lastSize = {width: w, height: h};
17356
17357         var adj = this.adjustSize(w, h);
17358         var aw = adj.width, ah = adj.height;
17359         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
17360             var rz = this.getResizeEl();
17361             if(!this.deferHeight && aw !== undefined && ah !== undefined){
17362                 rz.setSize(aw, ah);
17363             }else if(!this.deferHeight && ah !== undefined){
17364                 rz.setHeight(ah);
17365             }else if(aw !== undefined){
17366                 rz.setWidth(aw);
17367             }
17368             this.onResize(aw, ah, w, h);
17369             this.fireEvent('resize', this, aw, ah, w, h);
17370         }
17371         return this;
17372     },
17373
17374     /**
17375      * Gets the current size of the component's underlying element.
17376      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
17377      */
17378     getSize : function(){
17379         return this.el.getSize();
17380     },
17381
17382     /**
17383      * Gets the current XY position of the component's underlying element.
17384      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17385      * @return {Array} The XY position of the element (e.g., [100, 200])
17386      */
17387     getPosition : function(local){
17388         if(local === true){
17389             return [this.el.getLeft(true), this.el.getTop(true)];
17390         }
17391         return this.xy || this.el.getXY();
17392     },
17393
17394     /**
17395      * Gets the current box measurements of the component's underlying element.
17396      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
17397      * @returns {Object} box An object in the format {x, y, width, height}
17398      */
17399     getBox : function(local){
17400         var s = this.el.getSize();
17401         if(local){
17402             s.x = this.el.getLeft(true);
17403             s.y = this.el.getTop(true);
17404         }else{
17405             var xy = this.xy || this.el.getXY();
17406             s.x = xy[0];
17407             s.y = xy[1];
17408         }
17409         return s;
17410     },
17411
17412     /**
17413      * Sets the current box measurements of the component's underlying element.
17414      * @param {Object} box An object in the format {x, y, width, height}
17415      * @returns {Roo.BoxComponent} this
17416      */
17417     updateBox : function(box){
17418         this.setSize(box.width, box.height);
17419         this.setPagePosition(box.x, box.y);
17420         return this;
17421     },
17422
17423     // protected
17424     getResizeEl : function(){
17425         return this.resizeEl || this.el;
17426     },
17427
17428     // protected
17429     getPositionEl : function(){
17430         return this.positionEl || this.el;
17431     },
17432
17433     /**
17434      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
17435      * This method fires the move event.
17436      * @param {Number} left The new left
17437      * @param {Number} top The new top
17438      * @returns {Roo.BoxComponent} this
17439      */
17440     setPosition : function(x, y){
17441         this.x = x;
17442         this.y = y;
17443         if(!this.boxReady){
17444             return this;
17445         }
17446         var adj = this.adjustPosition(x, y);
17447         var ax = adj.x, ay = adj.y;
17448
17449         var el = this.getPositionEl();
17450         if(ax !== undefined || ay !== undefined){
17451             if(ax !== undefined && ay !== undefined){
17452                 el.setLeftTop(ax, ay);
17453             }else if(ax !== undefined){
17454                 el.setLeft(ax);
17455             }else if(ay !== undefined){
17456                 el.setTop(ay);
17457             }
17458             this.onPosition(ax, ay);
17459             this.fireEvent('move', this, ax, ay);
17460         }
17461         return this;
17462     },
17463
17464     /**
17465      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
17466      * This method fires the move event.
17467      * @param {Number} x The new x position
17468      * @param {Number} y The new y position
17469      * @returns {Roo.BoxComponent} this
17470      */
17471     setPagePosition : function(x, y){
17472         this.pageX = x;
17473         this.pageY = y;
17474         if(!this.boxReady){
17475             return;
17476         }
17477         if(x === undefined || y === undefined){ // cannot translate undefined points
17478             return;
17479         }
17480         var p = this.el.translatePoints(x, y);
17481         this.setPosition(p.left, p.top);
17482         return this;
17483     },
17484
17485     // private
17486     onRender : function(ct, position){
17487         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
17488         if(this.resizeEl){
17489             this.resizeEl = Roo.get(this.resizeEl);
17490         }
17491         if(this.positionEl){
17492             this.positionEl = Roo.get(this.positionEl);
17493         }
17494     },
17495
17496     // private
17497     afterRender : function(){
17498         Roo.BoxComponent.superclass.afterRender.call(this);
17499         this.boxReady = true;
17500         this.setSize(this.width, this.height);
17501         if(this.x || this.y){
17502             this.setPosition(this.x, this.y);
17503         }
17504         if(this.pageX || this.pageY){
17505             this.setPagePosition(this.pageX, this.pageY);
17506         }
17507     },
17508
17509     /**
17510      * Force the component's size to recalculate based on the underlying element's current height and width.
17511      * @returns {Roo.BoxComponent} this
17512      */
17513     syncSize : function(){
17514         delete this.lastSize;
17515         this.setSize(this.el.getWidth(), this.el.getHeight());
17516         return this;
17517     },
17518
17519     /**
17520      * Called after the component is resized, this method is empty by default but can be implemented by any
17521      * subclass that needs to perform custom logic after a resize occurs.
17522      * @param {Number} adjWidth The box-adjusted width that was set
17523      * @param {Number} adjHeight The box-adjusted height that was set
17524      * @param {Number} rawWidth The width that was originally specified
17525      * @param {Number} rawHeight The height that was originally specified
17526      */
17527     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17528
17529     },
17530
17531     /**
17532      * Called after the component is moved, this method is empty by default but can be implemented by any
17533      * subclass that needs to perform custom logic after a move occurs.
17534      * @param {Number} x The new x position
17535      * @param {Number} y The new y position
17536      */
17537     onPosition : function(x, y){
17538
17539     },
17540
17541     // private
17542     adjustSize : function(w, h){
17543         if(this.autoWidth){
17544             w = 'auto';
17545         }
17546         if(this.autoHeight){
17547             h = 'auto';
17548         }
17549         return {width : w, height: h};
17550     },
17551
17552     // private
17553     adjustPosition : function(x, y){
17554         return {x : x, y: y};
17555     }
17556 });/*
17557  * Based on:
17558  * Ext JS Library 1.1.1
17559  * Copyright(c) 2006-2007, Ext JS, LLC.
17560  *
17561  * Originally Released Under LGPL - original licence link has changed is not relivant.
17562  *
17563  * Fork - LGPL
17564  * <script type="text/javascript">
17565  */
17566  (function(){ 
17567 /**
17568  * @class Roo.Layer
17569  * @extends Roo.Element
17570  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17571  * automatic maintaining of shadow/shim positions.
17572  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17573  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17574  * you can pass a string with a CSS class name. False turns off the shadow.
17575  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17576  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17577  * @cfg {String} cls CSS class to add to the element
17578  * @cfg {Number} zindex Starting z-index (defaults to 11000)
17579  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17580  * @constructor
17581  * @param {Object} config An object with config options.
17582  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17583  */
17584
17585 Roo.Layer = function(config, existingEl){
17586     config = config || {};
17587     var dh = Roo.DomHelper;
17588     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17589     if(existingEl){
17590         this.dom = Roo.getDom(existingEl);
17591     }
17592     if(!this.dom){
17593         var o = config.dh || {tag: "div", cls: "x-layer"};
17594         this.dom = dh.append(pel, o);
17595     }
17596     if(config.cls){
17597         this.addClass(config.cls);
17598     }
17599     this.constrain = config.constrain !== false;
17600     this.visibilityMode = Roo.Element.VISIBILITY;
17601     if(config.id){
17602         this.id = this.dom.id = config.id;
17603     }else{
17604         this.id = Roo.id(this.dom);
17605     }
17606     this.zindex = config.zindex || this.getZIndex();
17607     this.position("absolute", this.zindex);
17608     if(config.shadow){
17609         this.shadowOffset = config.shadowOffset || 4;
17610         this.shadow = new Roo.Shadow({
17611             offset : this.shadowOffset,
17612             mode : config.shadow
17613         });
17614     }else{
17615         this.shadowOffset = 0;
17616     }
17617     this.useShim = config.shim !== false && Roo.useShims;
17618     this.useDisplay = config.useDisplay;
17619     this.hide();
17620 };
17621
17622 var supr = Roo.Element.prototype;
17623
17624 // shims are shared among layer to keep from having 100 iframes
17625 var shims = [];
17626
17627 Roo.extend(Roo.Layer, Roo.Element, {
17628
17629     getZIndex : function(){
17630         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17631     },
17632
17633     getShim : function(){
17634         if(!this.useShim){
17635             return null;
17636         }
17637         if(this.shim){
17638             return this.shim;
17639         }
17640         var shim = shims.shift();
17641         if(!shim){
17642             shim = this.createShim();
17643             shim.enableDisplayMode('block');
17644             shim.dom.style.display = 'none';
17645             shim.dom.style.visibility = 'visible';
17646         }
17647         var pn = this.dom.parentNode;
17648         if(shim.dom.parentNode != pn){
17649             pn.insertBefore(shim.dom, this.dom);
17650         }
17651         shim.setStyle('z-index', this.getZIndex()-2);
17652         this.shim = shim;
17653         return shim;
17654     },
17655
17656     hideShim : function(){
17657         if(this.shim){
17658             this.shim.setDisplayed(false);
17659             shims.push(this.shim);
17660             delete this.shim;
17661         }
17662     },
17663
17664     disableShadow : function(){
17665         if(this.shadow){
17666             this.shadowDisabled = true;
17667             this.shadow.hide();
17668             this.lastShadowOffset = this.shadowOffset;
17669             this.shadowOffset = 0;
17670         }
17671     },
17672
17673     enableShadow : function(show){
17674         if(this.shadow){
17675             this.shadowDisabled = false;
17676             this.shadowOffset = this.lastShadowOffset;
17677             delete this.lastShadowOffset;
17678             if(show){
17679                 this.sync(true);
17680             }
17681         }
17682     },
17683
17684     // private
17685     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17686     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17687     sync : function(doShow){
17688         var sw = this.shadow;
17689         if(!this.updating && this.isVisible() && (sw || this.useShim)){
17690             var sh = this.getShim();
17691
17692             var w = this.getWidth(),
17693                 h = this.getHeight();
17694
17695             var l = this.getLeft(true),
17696                 t = this.getTop(true);
17697
17698             if(sw && !this.shadowDisabled){
17699                 if(doShow && !sw.isVisible()){
17700                     sw.show(this);
17701                 }else{
17702                     sw.realign(l, t, w, h);
17703                 }
17704                 if(sh){
17705                     if(doShow){
17706                        sh.show();
17707                     }
17708                     // fit the shim behind the shadow, so it is shimmed too
17709                     var a = sw.adjusts, s = sh.dom.style;
17710                     s.left = (Math.min(l, l+a.l))+"px";
17711                     s.top = (Math.min(t, t+a.t))+"px";
17712                     s.width = (w+a.w)+"px";
17713                     s.height = (h+a.h)+"px";
17714                 }
17715             }else if(sh){
17716                 if(doShow){
17717                    sh.show();
17718                 }
17719                 sh.setSize(w, h);
17720                 sh.setLeftTop(l, t);
17721             }
17722             
17723         }
17724     },
17725
17726     // private
17727     destroy : function(){
17728         this.hideShim();
17729         if(this.shadow){
17730             this.shadow.hide();
17731         }
17732         this.removeAllListeners();
17733         var pn = this.dom.parentNode;
17734         if(pn){
17735             pn.removeChild(this.dom);
17736         }
17737         Roo.Element.uncache(this.id);
17738     },
17739
17740     remove : function(){
17741         this.destroy();
17742     },
17743
17744     // private
17745     beginUpdate : function(){
17746         this.updating = true;
17747     },
17748
17749     // private
17750     endUpdate : function(){
17751         this.updating = false;
17752         this.sync(true);
17753     },
17754
17755     // private
17756     hideUnders : function(negOffset){
17757         if(this.shadow){
17758             this.shadow.hide();
17759         }
17760         this.hideShim();
17761     },
17762
17763     // private
17764     constrainXY : function(){
17765         if(this.constrain){
17766             var vw = Roo.lib.Dom.getViewWidth(),
17767                 vh = Roo.lib.Dom.getViewHeight();
17768             var s = Roo.get(document).getScroll();
17769
17770             var xy = this.getXY();
17771             var x = xy[0], y = xy[1];   
17772             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17773             // only move it if it needs it
17774             var moved = false;
17775             // first validate right/bottom
17776             if((x + w) > vw+s.left){
17777                 x = vw - w - this.shadowOffset;
17778                 moved = true;
17779             }
17780             if((y + h) > vh+s.top){
17781                 y = vh - h - this.shadowOffset;
17782                 moved = true;
17783             }
17784             // then make sure top/left isn't negative
17785             if(x < s.left){
17786                 x = s.left;
17787                 moved = true;
17788             }
17789             if(y < s.top){
17790                 y = s.top;
17791                 moved = true;
17792             }
17793             if(moved){
17794                 if(this.avoidY){
17795                     var ay = this.avoidY;
17796                     if(y <= ay && (y+h) >= ay){
17797                         y = ay-h-5;   
17798                     }
17799                 }
17800                 xy = [x, y];
17801                 this.storeXY(xy);
17802                 supr.setXY.call(this, xy);
17803                 this.sync();
17804             }
17805         }
17806     },
17807
17808     isVisible : function(){
17809         return this.visible;    
17810     },
17811
17812     // private
17813     showAction : function(){
17814         this.visible = true; // track visibility to prevent getStyle calls
17815         if(this.useDisplay === true){
17816             this.setDisplayed("");
17817         }else if(this.lastXY){
17818             supr.setXY.call(this, this.lastXY);
17819         }else if(this.lastLT){
17820             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17821         }
17822     },
17823
17824     // private
17825     hideAction : function(){
17826         this.visible = false;
17827         if(this.useDisplay === true){
17828             this.setDisplayed(false);
17829         }else{
17830             this.setLeftTop(-10000,-10000);
17831         }
17832     },
17833
17834     // overridden Element method
17835     setVisible : function(v, a, d, c, e){
17836         if(v){
17837             this.showAction();
17838         }
17839         if(a && v){
17840             var cb = function(){
17841                 this.sync(true);
17842                 if(c){
17843                     c();
17844                 }
17845             }.createDelegate(this);
17846             supr.setVisible.call(this, true, true, d, cb, e);
17847         }else{
17848             if(!v){
17849                 this.hideUnders(true);
17850             }
17851             var cb = c;
17852             if(a){
17853                 cb = function(){
17854                     this.hideAction();
17855                     if(c){
17856                         c();
17857                     }
17858                 }.createDelegate(this);
17859             }
17860             supr.setVisible.call(this, v, a, d, cb, e);
17861             if(v){
17862                 this.sync(true);
17863             }else if(!a){
17864                 this.hideAction();
17865             }
17866         }
17867     },
17868
17869     storeXY : function(xy){
17870         delete this.lastLT;
17871         this.lastXY = xy;
17872     },
17873
17874     storeLeftTop : function(left, top){
17875         delete this.lastXY;
17876         this.lastLT = [left, top];
17877     },
17878
17879     // private
17880     beforeFx : function(){
17881         this.beforeAction();
17882         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17883     },
17884
17885     // private
17886     afterFx : function(){
17887         Roo.Layer.superclass.afterFx.apply(this, arguments);
17888         this.sync(this.isVisible());
17889     },
17890
17891     // private
17892     beforeAction : function(){
17893         if(!this.updating && this.shadow){
17894             this.shadow.hide();
17895         }
17896     },
17897
17898     // overridden Element method
17899     setLeft : function(left){
17900         this.storeLeftTop(left, this.getTop(true));
17901         supr.setLeft.apply(this, arguments);
17902         this.sync();
17903     },
17904
17905     setTop : function(top){
17906         this.storeLeftTop(this.getLeft(true), top);
17907         supr.setTop.apply(this, arguments);
17908         this.sync();
17909     },
17910
17911     setLeftTop : function(left, top){
17912         this.storeLeftTop(left, top);
17913         supr.setLeftTop.apply(this, arguments);
17914         this.sync();
17915     },
17916
17917     setXY : function(xy, a, d, c, e){
17918         this.fixDisplay();
17919         this.beforeAction();
17920         this.storeXY(xy);
17921         var cb = this.createCB(c);
17922         supr.setXY.call(this, xy, a, d, cb, e);
17923         if(!a){
17924             cb();
17925         }
17926     },
17927
17928     // private
17929     createCB : function(c){
17930         var el = this;
17931         return function(){
17932             el.constrainXY();
17933             el.sync(true);
17934             if(c){
17935                 c();
17936             }
17937         };
17938     },
17939
17940     // overridden Element method
17941     setX : function(x, a, d, c, e){
17942         this.setXY([x, this.getY()], a, d, c, e);
17943     },
17944
17945     // overridden Element method
17946     setY : function(y, a, d, c, e){
17947         this.setXY([this.getX(), y], a, d, c, e);
17948     },
17949
17950     // overridden Element method
17951     setSize : function(w, h, a, d, c, e){
17952         this.beforeAction();
17953         var cb = this.createCB(c);
17954         supr.setSize.call(this, w, h, a, d, cb, e);
17955         if(!a){
17956             cb();
17957         }
17958     },
17959
17960     // overridden Element method
17961     setWidth : function(w, a, d, c, e){
17962         this.beforeAction();
17963         var cb = this.createCB(c);
17964         supr.setWidth.call(this, w, a, d, cb, e);
17965         if(!a){
17966             cb();
17967         }
17968     },
17969
17970     // overridden Element method
17971     setHeight : function(h, a, d, c, e){
17972         this.beforeAction();
17973         var cb = this.createCB(c);
17974         supr.setHeight.call(this, h, a, d, cb, e);
17975         if(!a){
17976             cb();
17977         }
17978     },
17979
17980     // overridden Element method
17981     setBounds : function(x, y, w, h, a, d, c, e){
17982         this.beforeAction();
17983         var cb = this.createCB(c);
17984         if(!a){
17985             this.storeXY([x, y]);
17986             supr.setXY.call(this, [x, y]);
17987             supr.setSize.call(this, w, h, a, d, cb, e);
17988             cb();
17989         }else{
17990             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17991         }
17992         return this;
17993     },
17994     
17995     /**
17996      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17997      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17998      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17999      * @param {Number} zindex The new z-index to set
18000      * @return {this} The Layer
18001      */
18002     setZIndex : function(zindex){
18003         this.zindex = zindex;
18004         this.setStyle("z-index", zindex + 2);
18005         if(this.shadow){
18006             this.shadow.setZIndex(zindex + 1);
18007         }
18008         if(this.shim){
18009             this.shim.setStyle("z-index", zindex);
18010         }
18011     }
18012 });
18013 })();/*
18014  * Original code for Roojs - LGPL
18015  * <script type="text/javascript">
18016  */
18017  
18018 /**
18019  * @class Roo.XComponent
18020  * A delayed Element creator...
18021  * Or a way to group chunks of interface together.
18022  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
18023  *  used in conjunction with XComponent.build() it will create an instance of each element,
18024  *  then call addxtype() to build the User interface.
18025  * 
18026  * Mypart.xyx = new Roo.XComponent({
18027
18028     parent : 'Mypart.xyz', // empty == document.element.!!
18029     order : '001',
18030     name : 'xxxx'
18031     region : 'xxxx'
18032     disabled : function() {} 
18033      
18034     tree : function() { // return an tree of xtype declared components
18035         var MODULE = this;
18036         return 
18037         {
18038             xtype : 'NestedLayoutPanel',
18039             // technicall
18040         }
18041      ]
18042  *})
18043  *
18044  *
18045  * It can be used to build a big heiracy, with parent etc.
18046  * or you can just use this to render a single compoent to a dom element
18047  * MYPART.render(Roo.Element | String(id) | dom_element )
18048  *
18049  *
18050  * Usage patterns.
18051  *
18052  * Classic Roo
18053  *
18054  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
18055  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
18056  *
18057  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
18058  *
18059  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
18060  * - if mulitple topModules exist, the last one is defined as the top module.
18061  *
18062  * Embeded Roo
18063  * 
18064  * When the top level or multiple modules are to embedded into a existing HTML page,
18065  * the parent element can container '#id' of the element where the module will be drawn.
18066  *
18067  * Bootstrap Roo
18068  *
18069  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
18070  * it relies more on a include mechanism, where sub modules are included into an outer page.
18071  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
18072  * 
18073  * Bootstrap Roo Included elements
18074  *
18075  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
18076  * hence confusing the component builder as it thinks there are multiple top level elements. 
18077  *
18078  * String Over-ride & Translations
18079  *
18080  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
18081  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
18082  * are needed. @see Roo.XComponent.overlayString  
18083  * 
18084  * 
18085  * 
18086  * @extends Roo.util.Observable
18087  * @constructor
18088  * @param cfg {Object} configuration of component
18089  * 
18090  */
18091 Roo.XComponent = function(cfg) {
18092     Roo.apply(this, cfg);
18093     this.addEvents({ 
18094         /**
18095              * @event built
18096              * Fires when this the componnt is built
18097              * @param {Roo.XComponent} c the component
18098              */
18099         'built' : true
18100         
18101     });
18102     this.region = this.region || 'center'; // default..
18103     Roo.XComponent.register(this);
18104     this.modules = false;
18105     this.el = false; // where the layout goes..
18106     
18107     
18108 }
18109 Roo.extend(Roo.XComponent, Roo.util.Observable, {
18110     /**
18111      * @property el
18112      * The created element (with Roo.factory())
18113      * @type {Roo.Layout}
18114      */
18115     el  : false,
18116     
18117     /**
18118      * @property el
18119      * for BC  - use el in new code
18120      * @type {Roo.Layout}
18121      */
18122     panel : false,
18123     
18124     /**
18125      * @property layout
18126      * for BC  - use el in new code
18127      * @type {Roo.Layout}
18128      */
18129     layout : false,
18130     
18131      /**
18132      * @cfg {Function|boolean} disabled
18133      * If this module is disabled by some rule, return true from the funtion
18134      */
18135     disabled : false,
18136     
18137     /**
18138      * @cfg {String} parent 
18139      * Name of parent element which it get xtype added to..
18140      */
18141     parent: false,
18142     
18143     /**
18144      * @cfg {String} order
18145      * Used to set the order in which elements are created (usefull for multiple tabs)
18146      */
18147     
18148     order : false,
18149     /**
18150      * @cfg {String} name
18151      * String to display while loading.
18152      */
18153     name : false,
18154     /**
18155      * @cfg {String} region
18156      * Region to render component to (defaults to center)
18157      */
18158     region : 'center',
18159     
18160     /**
18161      * @cfg {Array} items
18162      * A single item array - the first element is the root of the tree..
18163      * It's done this way to stay compatible with the Xtype system...
18164      */
18165     items : false,
18166     
18167     /**
18168      * @property _tree
18169      * The method that retuns the tree of parts that make up this compoennt 
18170      * @type {function}
18171      */
18172     _tree  : false,
18173     
18174      /**
18175      * render
18176      * render element to dom or tree
18177      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
18178      */
18179     
18180     render : function(el)
18181     {
18182         
18183         el = el || false;
18184         var hp = this.parent ? 1 : 0;
18185         Roo.debug &&  Roo.log(this);
18186         
18187         var tree = this._tree ? this._tree() : this.tree();
18188
18189         
18190         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
18191             // if parent is a '#.....' string, then let's use that..
18192             var ename = this.parent.substr(1);
18193             this.parent = false;
18194             Roo.debug && Roo.log(ename);
18195             switch (ename) {
18196                 case 'bootstrap-body':
18197                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
18198                         // this is the BorderLayout standard?
18199                        this.parent = { el : true };
18200                        break;
18201                     }
18202                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
18203                         // need to insert stuff...
18204                         this.parent =  {
18205                              el : new Roo.bootstrap.layout.Border({
18206                                  el : document.body, 
18207                      
18208                                  center: {
18209                                     titlebar: false,
18210                                     autoScroll:false,
18211                                     closeOnTab: true,
18212                                     tabPosition: 'top',
18213                                       //resizeTabs: true,
18214                                     alwaysShowTabs: true,
18215                                     hideTabs: false
18216                                      //minTabWidth: 140
18217                                  }
18218                              })
18219                         
18220                          };
18221                          break;
18222                     }
18223                          
18224                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
18225                         this.parent = { el :  new  Roo.bootstrap.Body() };
18226                         Roo.debug && Roo.log("setting el to doc body");
18227                          
18228                     } else {
18229                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
18230                     }
18231                     break;
18232                 case 'bootstrap':
18233                     this.parent = { el : true};
18234                     // fall through
18235                 default:
18236                     el = Roo.get(ename);
18237                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
18238                         this.parent = { el : true};
18239                     }
18240                     
18241                     break;
18242             }
18243                 
18244             
18245             if (!el && !this.parent) {
18246                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
18247                 return;
18248             }
18249         }
18250         
18251         Roo.debug && Roo.log("EL:");
18252         Roo.debug && Roo.log(el);
18253         Roo.debug && Roo.log("this.parent.el:");
18254         Roo.debug && Roo.log(this.parent.el);
18255         
18256
18257         // altertive root elements ??? - we need a better way to indicate these.
18258         var is_alt = Roo.XComponent.is_alt ||
18259                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
18260                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
18261                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
18262         
18263         
18264         
18265         if (!this.parent && is_alt) {
18266             //el = Roo.get(document.body);
18267             this.parent = { el : true };
18268         }
18269             
18270             
18271         
18272         if (!this.parent) {
18273             
18274             Roo.debug && Roo.log("no parent - creating one");
18275             
18276             el = el ? Roo.get(el) : false;      
18277             
18278             if (typeof(Roo.BorderLayout) == 'undefined' ) {
18279                 
18280                 this.parent =  {
18281                     el : new Roo.bootstrap.layout.Border({
18282                         el: el || document.body,
18283                     
18284                         center: {
18285                             titlebar: false,
18286                             autoScroll:false,
18287                             closeOnTab: true,
18288                             tabPosition: 'top',
18289                              //resizeTabs: true,
18290                             alwaysShowTabs: false,
18291                             hideTabs: true,
18292                             minTabWidth: 140,
18293                             overflow: 'visible'
18294                          }
18295                      })
18296                 };
18297             } else {
18298             
18299                 // it's a top level one..
18300                 this.parent =  {
18301                     el : new Roo.BorderLayout(el || document.body, {
18302                         center: {
18303                             titlebar: false,
18304                             autoScroll:false,
18305                             closeOnTab: true,
18306                             tabPosition: 'top',
18307                              //resizeTabs: true,
18308                             alwaysShowTabs: el && hp? false :  true,
18309                             hideTabs: el || !hp ? true :  false,
18310                             minTabWidth: 140
18311                          }
18312                     })
18313                 };
18314             }
18315         }
18316         
18317         if (!this.parent.el) {
18318                 // probably an old style ctor, which has been disabled.
18319                 return;
18320
18321         }
18322                 // The 'tree' method is  '_tree now' 
18323             
18324         tree.region = tree.region || this.region;
18325         var is_body = false;
18326         if (this.parent.el === true) {
18327             // bootstrap... - body..
18328             if (el) {
18329                 tree.el = el;
18330             }
18331             this.parent.el = Roo.factory(tree);
18332             is_body = true;
18333         }
18334         
18335         this.el = this.parent.el.addxtype(tree, undefined, is_body);
18336         this.fireEvent('built', this);
18337         
18338         this.panel = this.el;
18339         this.layout = this.panel.layout;
18340         this.parentLayout = this.parent.layout  || false;  
18341          
18342     }
18343     
18344 });
18345
18346 Roo.apply(Roo.XComponent, {
18347     /**
18348      * @property  hideProgress
18349      * true to disable the building progress bar.. usefull on single page renders.
18350      * @type Boolean
18351      */
18352     hideProgress : false,
18353     /**
18354      * @property  buildCompleted
18355      * True when the builder has completed building the interface.
18356      * @type Boolean
18357      */
18358     buildCompleted : false,
18359      
18360     /**
18361      * @property  topModule
18362      * the upper most module - uses document.element as it's constructor.
18363      * @type Object
18364      */
18365      
18366     topModule  : false,
18367       
18368     /**
18369      * @property  modules
18370      * array of modules to be created by registration system.
18371      * @type {Array} of Roo.XComponent
18372      */
18373     
18374     modules : [],
18375     /**
18376      * @property  elmodules
18377      * array of modules to be created by which use #ID 
18378      * @type {Array} of Roo.XComponent
18379      */
18380      
18381     elmodules : [],
18382
18383      /**
18384      * @property  is_alt
18385      * Is an alternative Root - normally used by bootstrap or other systems,
18386      *    where the top element in the tree can wrap 'body' 
18387      * @type {boolean}  (default false)
18388      */
18389      
18390     is_alt : false,
18391     /**
18392      * @property  build_from_html
18393      * Build elements from html - used by bootstrap HTML stuff 
18394      *    - this is cleared after build is completed
18395      * @type {boolean}    (default false)
18396      */
18397      
18398     build_from_html : false,
18399     /**
18400      * Register components to be built later.
18401      *
18402      * This solves the following issues
18403      * - Building is not done on page load, but after an authentication process has occured.
18404      * - Interface elements are registered on page load
18405      * - Parent Interface elements may not be loaded before child, so this handles that..
18406      * 
18407      *
18408      * example:
18409      * 
18410      * MyApp.register({
18411           order : '000001',
18412           module : 'Pman.Tab.projectMgr',
18413           region : 'center',
18414           parent : 'Pman.layout',
18415           disabled : false,  // or use a function..
18416         })
18417      
18418      * * @param {Object} details about module
18419      */
18420     register : function(obj) {
18421                 
18422         Roo.XComponent.event.fireEvent('register', obj);
18423         switch(typeof(obj.disabled) ) {
18424                 
18425             case 'undefined':
18426                 break;
18427             
18428             case 'function':
18429                 if ( obj.disabled() ) {
18430                         return;
18431                 }
18432                 break;
18433             
18434             default:
18435                 if (obj.disabled || obj.region == '#disabled') {
18436                         return;
18437                 }
18438                 break;
18439         }
18440                 
18441         this.modules.push(obj);
18442          
18443     },
18444     /**
18445      * convert a string to an object..
18446      * eg. 'AAA.BBB' -> finds AAA.BBB
18447
18448      */
18449     
18450     toObject : function(str)
18451     {
18452         if (!str || typeof(str) == 'object') {
18453             return str;
18454         }
18455         if (str.substring(0,1) == '#') {
18456             return str;
18457         }
18458
18459         var ar = str.split('.');
18460         var rt, o;
18461         rt = ar.shift();
18462             /** eval:var:o */
18463         try {
18464             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
18465         } catch (e) {
18466             throw "Module not found : " + str;
18467         }
18468         
18469         if (o === false) {
18470             throw "Module not found : " + str;
18471         }
18472         Roo.each(ar, function(e) {
18473             if (typeof(o[e]) == 'undefined') {
18474                 throw "Module not found : " + str;
18475             }
18476             o = o[e];
18477         });
18478         
18479         return o;
18480         
18481     },
18482     
18483     
18484     /**
18485      * move modules into their correct place in the tree..
18486      * 
18487      */
18488     preBuild : function ()
18489     {
18490         var _t = this;
18491         Roo.each(this.modules , function (obj)
18492         {
18493             Roo.XComponent.event.fireEvent('beforebuild', obj);
18494             
18495             var opar = obj.parent;
18496             try { 
18497                 obj.parent = this.toObject(opar);
18498             } catch(e) {
18499                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
18500                 return;
18501             }
18502             
18503             if (!obj.parent) {
18504                 Roo.debug && Roo.log("GOT top level module");
18505                 Roo.debug && Roo.log(obj);
18506                 obj.modules = new Roo.util.MixedCollection(false, 
18507                     function(o) { return o.order + '' }
18508                 );
18509                 this.topModule = obj;
18510                 return;
18511             }
18512                         // parent is a string (usually a dom element name..)
18513             if (typeof(obj.parent) == 'string') {
18514                 this.elmodules.push(obj);
18515                 return;
18516             }
18517             if (obj.parent.constructor != Roo.XComponent) {
18518                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
18519             }
18520             if (!obj.parent.modules) {
18521                 obj.parent.modules = new Roo.util.MixedCollection(false, 
18522                     function(o) { return o.order + '' }
18523                 );
18524             }
18525             if (obj.parent.disabled) {
18526                 obj.disabled = true;
18527             }
18528             obj.parent.modules.add(obj);
18529         }, this);
18530     },
18531     
18532      /**
18533      * make a list of modules to build.
18534      * @return {Array} list of modules. 
18535      */ 
18536     
18537     buildOrder : function()
18538     {
18539         var _this = this;
18540         var cmp = function(a,b) {   
18541             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18542         };
18543         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18544             throw "No top level modules to build";
18545         }
18546         
18547         // make a flat list in order of modules to build.
18548         var mods = this.topModule ? [ this.topModule ] : [];
18549                 
18550         
18551         // elmodules (is a list of DOM based modules )
18552         Roo.each(this.elmodules, function(e) {
18553             mods.push(e);
18554             if (!this.topModule &&
18555                 typeof(e.parent) == 'string' &&
18556                 e.parent.substring(0,1) == '#' &&
18557                 Roo.get(e.parent.substr(1))
18558                ) {
18559                 
18560                 _this.topModule = e;
18561             }
18562             
18563         });
18564
18565         
18566         // add modules to their parents..
18567         var addMod = function(m) {
18568             Roo.debug && Roo.log("build Order: add: " + m.name);
18569                 
18570             mods.push(m);
18571             if (m.modules && !m.disabled) {
18572                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18573                 m.modules.keySort('ASC',  cmp );
18574                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18575     
18576                 m.modules.each(addMod);
18577             } else {
18578                 Roo.debug && Roo.log("build Order: no child modules");
18579             }
18580             // not sure if this is used any more..
18581             if (m.finalize) {
18582                 m.finalize.name = m.name + " (clean up) ";
18583                 mods.push(m.finalize);
18584             }
18585             
18586         }
18587         if (this.topModule && this.topModule.modules) { 
18588             this.topModule.modules.keySort('ASC',  cmp );
18589             this.topModule.modules.each(addMod);
18590         } 
18591         return mods;
18592     },
18593     
18594      /**
18595      * Build the registered modules.
18596      * @param {Object} parent element.
18597      * @param {Function} optional method to call after module has been added.
18598      * 
18599      */ 
18600    
18601     build : function(opts) 
18602     {
18603         
18604         if (typeof(opts) != 'undefined') {
18605             Roo.apply(this,opts);
18606         }
18607         
18608         this.preBuild();
18609         var mods = this.buildOrder();
18610       
18611         //this.allmods = mods;
18612         //Roo.debug && Roo.log(mods);
18613         //return;
18614         if (!mods.length) { // should not happen
18615             throw "NO modules!!!";
18616         }
18617         
18618         
18619         var msg = "Building Interface...";
18620         // flash it up as modal - so we store the mask!?
18621         if (!this.hideProgress && Roo.MessageBox) {
18622             Roo.MessageBox.show({ title: 'loading' });
18623             Roo.MessageBox.show({
18624                title: "Please wait...",
18625                msg: msg,
18626                width:450,
18627                progress:true,
18628                buttons : false,
18629                closable:false,
18630                modal: false
18631               
18632             });
18633         }
18634         var total = mods.length;
18635         
18636         var _this = this;
18637         var progressRun = function() {
18638             if (!mods.length) {
18639                 Roo.debug && Roo.log('hide?');
18640                 if (!this.hideProgress && Roo.MessageBox) {
18641                     Roo.MessageBox.hide();
18642                 }
18643                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18644                 
18645                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18646                 
18647                 // THE END...
18648                 return false;   
18649             }
18650             
18651             var m = mods.shift();
18652             
18653             
18654             Roo.debug && Roo.log(m);
18655             // not sure if this is supported any more.. - modules that are are just function
18656             if (typeof(m) == 'function') { 
18657                 m.call(this);
18658                 return progressRun.defer(10, _this);
18659             } 
18660             
18661             
18662             msg = "Building Interface " + (total  - mods.length) + 
18663                     " of " + total + 
18664                     (m.name ? (' - ' + m.name) : '');
18665                         Roo.debug && Roo.log(msg);
18666             if (!_this.hideProgress &&  Roo.MessageBox) { 
18667                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
18668             }
18669             
18670          
18671             // is the module disabled?
18672             var disabled = (typeof(m.disabled) == 'function') ?
18673                 m.disabled.call(m.module.disabled) : m.disabled;    
18674             
18675             
18676             if (disabled) {
18677                 return progressRun(); // we do not update the display!
18678             }
18679             
18680             // now build 
18681             
18682                         
18683                         
18684             m.render();
18685             // it's 10 on top level, and 1 on others??? why...
18686             return progressRun.defer(10, _this);
18687              
18688         }
18689         progressRun.defer(1, _this);
18690      
18691         
18692         
18693     },
18694     /**
18695      * Overlay a set of modified strings onto a component
18696      * This is dependant on our builder exporting the strings and 'named strings' elements.
18697      * 
18698      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18699      * @param {Object} associative array of 'named' string and it's new value.
18700      * 
18701      */
18702         overlayStrings : function( component, strings )
18703     {
18704         if (typeof(component['_named_strings']) == 'undefined') {
18705             throw "ERROR: component does not have _named_strings";
18706         }
18707         for ( var k in strings ) {
18708             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18709             if (md !== false) {
18710                 component['_strings'][md] = strings[k];
18711             } else {
18712                 Roo.log('could not find named string: ' + k + ' in');
18713                 Roo.log(component);
18714             }
18715             
18716         }
18717         
18718     },
18719     
18720         
18721         /**
18722          * Event Object.
18723          *
18724          *
18725          */
18726         event: false, 
18727     /**
18728          * wrapper for event.on - aliased later..  
18729          * Typically use to register a event handler for register:
18730          *
18731          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18732          *
18733          */
18734     on : false
18735    
18736     
18737     
18738 });
18739
18740 Roo.XComponent.event = new Roo.util.Observable({
18741                 events : { 
18742                         /**
18743                          * @event register
18744                          * Fires when an Component is registered,
18745                          * set the disable property on the Component to stop registration.
18746                          * @param {Roo.XComponent} c the component being registerd.
18747                          * 
18748                          */
18749                         'register' : true,
18750             /**
18751                          * @event beforebuild
18752                          * Fires before each Component is built
18753                          * can be used to apply permissions.
18754                          * @param {Roo.XComponent} c the component being registerd.
18755                          * 
18756                          */
18757                         'beforebuild' : true,
18758                         /**
18759                          * @event buildcomplete
18760                          * Fires on the top level element when all elements have been built
18761                          * @param {Roo.XComponent} the top level component.
18762                          */
18763                         'buildcomplete' : true
18764                         
18765                 }
18766 });
18767
18768 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
18769  //
18770  /**
18771  * marked - a markdown parser
18772  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18773  * https://github.com/chjj/marked
18774  */
18775
18776
18777 /**
18778  *
18779  * Roo.Markdown - is a very crude wrapper around marked..
18780  *
18781  * usage:
18782  * 
18783  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18784  * 
18785  * Note: move the sample code to the bottom of this
18786  * file before uncommenting it.
18787  *
18788  */
18789
18790 Roo.Markdown = {};
18791 Roo.Markdown.toHtml = function(text) {
18792     
18793     var c = new Roo.Markdown.marked.setOptions({
18794             renderer: new Roo.Markdown.marked.Renderer(),
18795             gfm: true,
18796             tables: true,
18797             breaks: false,
18798             pedantic: false,
18799             sanitize: false,
18800             smartLists: true,
18801             smartypants: false
18802           });
18803     // A FEW HACKS!!?
18804     
18805     text = text.replace(/\\\n/g,' ');
18806     return Roo.Markdown.marked(text);
18807 };
18808 //
18809 // converter
18810 //
18811 // Wraps all "globals" so that the only thing
18812 // exposed is makeHtml().
18813 //
18814 (function() {
18815     
18816      /**
18817          * eval:var:escape
18818          * eval:var:unescape
18819          * eval:var:replace
18820          */
18821       
18822     /**
18823      * Helpers
18824      */
18825     
18826     var escape = function (html, encode) {
18827       return html
18828         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
18829         .replace(/</g, '&lt;')
18830         .replace(/>/g, '&gt;')
18831         .replace(/"/g, '&quot;')
18832         .replace(/'/g, '&#39;');
18833     }
18834     
18835     var unescape = function (html) {
18836         // explicitly match decimal, hex, and named HTML entities 
18837       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18838         n = n.toLowerCase();
18839         if (n === 'colon') { return ':'; }
18840         if (n.charAt(0) === '#') {
18841           return n.charAt(1) === 'x'
18842             ? String.fromCharCode(parseInt(n.substring(2), 16))
18843             : String.fromCharCode(+n.substring(1));
18844         }
18845         return '';
18846       });
18847     }
18848     
18849     var replace = function (regex, opt) {
18850       regex = regex.source;
18851       opt = opt || '';
18852       return function self(name, val) {
18853         if (!name) { return new RegExp(regex, opt); }
18854         val = val.source || val;
18855         val = val.replace(/(^|[^\[])\^/g, '$1');
18856         regex = regex.replace(name, val);
18857         return self;
18858       };
18859     }
18860
18861
18862          /**
18863          * eval:var:noop
18864     */
18865     var noop = function () {}
18866     noop.exec = noop;
18867     
18868          /**
18869          * eval:var:merge
18870     */
18871     var merge = function (obj) {
18872       var i = 1
18873         , target
18874         , key;
18875     
18876       for (; i < arguments.length; i++) {
18877         target = arguments[i];
18878         for (key in target) {
18879           if (Object.prototype.hasOwnProperty.call(target, key)) {
18880             obj[key] = target[key];
18881           }
18882         }
18883       }
18884     
18885       return obj;
18886     }
18887     
18888     
18889     /**
18890      * Block-Level Grammar
18891      */
18892     
18893     
18894     
18895     
18896     var block = {
18897       newline: /^\n+/,
18898       code: /^( {4}[^\n]+\n*)+/,
18899       fences: noop,
18900       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18901       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18902       nptable: noop,
18903       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18904       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18905       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18906       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18907       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18908       table: noop,
18909       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18910       text: /^[^\n]+/
18911     };
18912     
18913     block.bullet = /(?:[*+-]|\d+\.)/;
18914     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18915     block.item = replace(block.item, 'gm')
18916       (/bull/g, block.bullet)
18917       ();
18918     
18919     block.list = replace(block.list)
18920       (/bull/g, block.bullet)
18921       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18922       ('def', '\\n+(?=' + block.def.source + ')')
18923       ();
18924     
18925     block.blockquote = replace(block.blockquote)
18926       ('def', block.def)
18927       ();
18928     
18929     block._tag = '(?!(?:'
18930       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18931       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18932       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18933     
18934     block.html = replace(block.html)
18935       ('comment', /<!--[\s\S]*?-->/)
18936       ('closed', /<(tag)[\s\S]+?<\/\1>/)
18937       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18938       (/tag/g, block._tag)
18939       ();
18940     
18941     block.paragraph = replace(block.paragraph)
18942       ('hr', block.hr)
18943       ('heading', block.heading)
18944       ('lheading', block.lheading)
18945       ('blockquote', block.blockquote)
18946       ('tag', '<' + block._tag)
18947       ('def', block.def)
18948       ();
18949     
18950     /**
18951      * Normal Block Grammar
18952      */
18953     
18954     block.normal = merge({}, block);
18955     
18956     /**
18957      * GFM Block Grammar
18958      */
18959     
18960     block.gfm = merge({}, block.normal, {
18961       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18962       paragraph: /^/,
18963       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18964     });
18965     
18966     block.gfm.paragraph = replace(block.paragraph)
18967       ('(?!', '(?!'
18968         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18969         + block.list.source.replace('\\1', '\\3') + '|')
18970       ();
18971     
18972     /**
18973      * GFM + Tables Block Grammar
18974      */
18975     
18976     block.tables = merge({}, block.gfm, {
18977       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18978       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18979     });
18980     
18981     /**
18982      * Block Lexer
18983      */
18984     
18985     var Lexer = function (options) {
18986       this.tokens = [];
18987       this.tokens.links = {};
18988       this.options = options || marked.defaults;
18989       this.rules = block.normal;
18990     
18991       if (this.options.gfm) {
18992         if (this.options.tables) {
18993           this.rules = block.tables;
18994         } else {
18995           this.rules = block.gfm;
18996         }
18997       }
18998     }
18999     
19000     /**
19001      * Expose Block Rules
19002      */
19003     
19004     Lexer.rules = block;
19005     
19006     /**
19007      * Static Lex Method
19008      */
19009     
19010     Lexer.lex = function(src, options) {
19011       var lexer = new Lexer(options);
19012       return lexer.lex(src);
19013     };
19014     
19015     /**
19016      * Preprocessing
19017      */
19018     
19019     Lexer.prototype.lex = function(src) {
19020       src = src
19021         .replace(/\r\n|\r/g, '\n')
19022         .replace(/\t/g, '    ')
19023         .replace(/\u00a0/g, ' ')
19024         .replace(/\u2424/g, '\n');
19025     
19026       return this.token(src, true);
19027     };
19028     
19029     /**
19030      * Lexing
19031      */
19032     
19033     Lexer.prototype.token = function(src, top, bq) {
19034       var src = src.replace(/^ +$/gm, '')
19035         , next
19036         , loose
19037         , cap
19038         , bull
19039         , b
19040         , item
19041         , space
19042         , i
19043         , l;
19044     
19045       while (src) {
19046         // newline
19047         if (cap = this.rules.newline.exec(src)) {
19048           src = src.substring(cap[0].length);
19049           if (cap[0].length > 1) {
19050             this.tokens.push({
19051               type: 'space'
19052             });
19053           }
19054         }
19055     
19056         // code
19057         if (cap = this.rules.code.exec(src)) {
19058           src = src.substring(cap[0].length);
19059           cap = cap[0].replace(/^ {4}/gm, '');
19060           this.tokens.push({
19061             type: 'code',
19062             text: !this.options.pedantic
19063               ? cap.replace(/\n+$/, '')
19064               : cap
19065           });
19066           continue;
19067         }
19068     
19069         // fences (gfm)
19070         if (cap = this.rules.fences.exec(src)) {
19071           src = src.substring(cap[0].length);
19072           this.tokens.push({
19073             type: 'code',
19074             lang: cap[2],
19075             text: cap[3] || ''
19076           });
19077           continue;
19078         }
19079     
19080         // heading
19081         if (cap = this.rules.heading.exec(src)) {
19082           src = src.substring(cap[0].length);
19083           this.tokens.push({
19084             type: 'heading',
19085             depth: cap[1].length,
19086             text: cap[2]
19087           });
19088           continue;
19089         }
19090     
19091         // table no leading pipe (gfm)
19092         if (top && (cap = this.rules.nptable.exec(src))) {
19093           src = src.substring(cap[0].length);
19094     
19095           item = {
19096             type: 'table',
19097             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19098             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19099             cells: cap[3].replace(/\n$/, '').split('\n')
19100           };
19101     
19102           for (i = 0; i < item.align.length; i++) {
19103             if (/^ *-+: *$/.test(item.align[i])) {
19104               item.align[i] = 'right';
19105             } else if (/^ *:-+: *$/.test(item.align[i])) {
19106               item.align[i] = 'center';
19107             } else if (/^ *:-+ *$/.test(item.align[i])) {
19108               item.align[i] = 'left';
19109             } else {
19110               item.align[i] = null;
19111             }
19112           }
19113     
19114           for (i = 0; i < item.cells.length; i++) {
19115             item.cells[i] = item.cells[i].split(/ *\| */);
19116           }
19117     
19118           this.tokens.push(item);
19119     
19120           continue;
19121         }
19122     
19123         // lheading
19124         if (cap = this.rules.lheading.exec(src)) {
19125           src = src.substring(cap[0].length);
19126           this.tokens.push({
19127             type: 'heading',
19128             depth: cap[2] === '=' ? 1 : 2,
19129             text: cap[1]
19130           });
19131           continue;
19132         }
19133     
19134         // hr
19135         if (cap = this.rules.hr.exec(src)) {
19136           src = src.substring(cap[0].length);
19137           this.tokens.push({
19138             type: 'hr'
19139           });
19140           continue;
19141         }
19142     
19143         // blockquote
19144         if (cap = this.rules.blockquote.exec(src)) {
19145           src = src.substring(cap[0].length);
19146     
19147           this.tokens.push({
19148             type: 'blockquote_start'
19149           });
19150     
19151           cap = cap[0].replace(/^ *> ?/gm, '');
19152     
19153           // Pass `top` to keep the current
19154           // "toplevel" state. This is exactly
19155           // how markdown.pl works.
19156           this.token(cap, top, true);
19157     
19158           this.tokens.push({
19159             type: 'blockquote_end'
19160           });
19161     
19162           continue;
19163         }
19164     
19165         // list
19166         if (cap = this.rules.list.exec(src)) {
19167           src = src.substring(cap[0].length);
19168           bull = cap[2];
19169     
19170           this.tokens.push({
19171             type: 'list_start',
19172             ordered: bull.length > 1
19173           });
19174     
19175           // Get each top-level item.
19176           cap = cap[0].match(this.rules.item);
19177     
19178           next = false;
19179           l = cap.length;
19180           i = 0;
19181     
19182           for (; i < l; i++) {
19183             item = cap[i];
19184     
19185             // Remove the list item's bullet
19186             // so it is seen as the next token.
19187             space = item.length;
19188             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19189     
19190             // Outdent whatever the
19191             // list item contains. Hacky.
19192             if (~item.indexOf('\n ')) {
19193               space -= item.length;
19194               item = !this.options.pedantic
19195                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19196                 : item.replace(/^ {1,4}/gm, '');
19197             }
19198     
19199             // Determine whether the next list item belongs here.
19200             // Backpedal if it does not belong in this list.
19201             if (this.options.smartLists && i !== l - 1) {
19202               b = block.bullet.exec(cap[i + 1])[0];
19203               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19204                 src = cap.slice(i + 1).join('\n') + src;
19205                 i = l - 1;
19206               }
19207             }
19208     
19209             // Determine whether item is loose or not.
19210             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19211             // for discount behavior.
19212             loose = next || /\n\n(?!\s*$)/.test(item);
19213             if (i !== l - 1) {
19214               next = item.charAt(item.length - 1) === '\n';
19215               if (!loose) { loose = next; }
19216             }
19217     
19218             this.tokens.push({
19219               type: loose
19220                 ? 'loose_item_start'
19221                 : 'list_item_start'
19222             });
19223     
19224             // Recurse.
19225             this.token(item, false, bq);
19226     
19227             this.tokens.push({
19228               type: 'list_item_end'
19229             });
19230           }
19231     
19232           this.tokens.push({
19233             type: 'list_end'
19234           });
19235     
19236           continue;
19237         }
19238     
19239         // html
19240         if (cap = this.rules.html.exec(src)) {
19241           src = src.substring(cap[0].length);
19242           this.tokens.push({
19243             type: this.options.sanitize
19244               ? 'paragraph'
19245               : 'html',
19246             pre: !this.options.sanitizer
19247               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
19248             text: cap[0]
19249           });
19250           continue;
19251         }
19252     
19253         // def
19254         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
19255           src = src.substring(cap[0].length);
19256           this.tokens.links[cap[1].toLowerCase()] = {
19257             href: cap[2],
19258             title: cap[3]
19259           };
19260           continue;
19261         }
19262     
19263         // table (gfm)
19264         if (top && (cap = this.rules.table.exec(src))) {
19265           src = src.substring(cap[0].length);
19266     
19267           item = {
19268             type: 'table',
19269             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19270             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19271             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19272           };
19273     
19274           for (i = 0; i < item.align.length; i++) {
19275             if (/^ *-+: *$/.test(item.align[i])) {
19276               item.align[i] = 'right';
19277             } else if (/^ *:-+: *$/.test(item.align[i])) {
19278               item.align[i] = 'center';
19279             } else if (/^ *:-+ *$/.test(item.align[i])) {
19280               item.align[i] = 'left';
19281             } else {
19282               item.align[i] = null;
19283             }
19284           }
19285     
19286           for (i = 0; i < item.cells.length; i++) {
19287             item.cells[i] = item.cells[i]
19288               .replace(/^ *\| *| *\| *$/g, '')
19289               .split(/ *\| */);
19290           }
19291     
19292           this.tokens.push(item);
19293     
19294           continue;
19295         }
19296     
19297         // top-level paragraph
19298         if (top && (cap = this.rules.paragraph.exec(src))) {
19299           src = src.substring(cap[0].length);
19300           this.tokens.push({
19301             type: 'paragraph',
19302             text: cap[1].charAt(cap[1].length - 1) === '\n'
19303               ? cap[1].slice(0, -1)
19304               : cap[1]
19305           });
19306           continue;
19307         }
19308     
19309         // text
19310         if (cap = this.rules.text.exec(src)) {
19311           // Top-level should never reach here.
19312           src = src.substring(cap[0].length);
19313           this.tokens.push({
19314             type: 'text',
19315             text: cap[0]
19316           });
19317           continue;
19318         }
19319     
19320         if (src) {
19321           throw new
19322             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19323         }
19324       }
19325     
19326       return this.tokens;
19327     };
19328     
19329     /**
19330      * Inline-Level Grammar
19331      */
19332     
19333     var inline = {
19334       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19335       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19336       url: noop,
19337       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19338       link: /^!?\[(inside)\]\(href\)/,
19339       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19340       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19341       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19342       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19343       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19344       br: /^ {2,}\n(?!\s*$)/,
19345       del: noop,
19346       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19347     };
19348     
19349     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
19350     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19351     
19352     inline.link = replace(inline.link)
19353       ('inside', inline._inside)
19354       ('href', inline._href)
19355       ();
19356     
19357     inline.reflink = replace(inline.reflink)
19358       ('inside', inline._inside)
19359       ();
19360     
19361     /**
19362      * Normal Inline Grammar
19363      */
19364     
19365     inline.normal = merge({}, inline);
19366     
19367     /**
19368      * Pedantic Inline Grammar
19369      */
19370     
19371     inline.pedantic = merge({}, inline.normal, {
19372       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19373       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19374     });
19375     
19376     /**
19377      * GFM Inline Grammar
19378      */
19379     
19380     inline.gfm = merge({}, inline.normal, {
19381       escape: replace(inline.escape)('])', '~|])')(),
19382       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19383       del: /^~~(?=\S)([\s\S]*?\S)~~/,
19384       text: replace(inline.text)
19385         (']|', '~]|')
19386         ('|', '|https?://|')
19387         ()
19388     });
19389     
19390     /**
19391      * GFM + Line Breaks Inline Grammar
19392      */
19393     
19394     inline.breaks = merge({}, inline.gfm, {
19395       br: replace(inline.br)('{2,}', '*')(),
19396       text: replace(inline.gfm.text)('{2,}', '*')()
19397     });
19398     
19399     /**
19400      * Inline Lexer & Compiler
19401      */
19402     
19403     var InlineLexer  = function (links, options) {
19404       this.options = options || marked.defaults;
19405       this.links = links;
19406       this.rules = inline.normal;
19407       this.renderer = this.options.renderer || new Renderer;
19408       this.renderer.options = this.options;
19409     
19410       if (!this.links) {
19411         throw new
19412           Error('Tokens array requires a `links` property.');
19413       }
19414     
19415       if (this.options.gfm) {
19416         if (this.options.breaks) {
19417           this.rules = inline.breaks;
19418         } else {
19419           this.rules = inline.gfm;
19420         }
19421       } else if (this.options.pedantic) {
19422         this.rules = inline.pedantic;
19423       }
19424     }
19425     
19426     /**
19427      * Expose Inline Rules
19428      */
19429     
19430     InlineLexer.rules = inline;
19431     
19432     /**
19433      * Static Lexing/Compiling Method
19434      */
19435     
19436     InlineLexer.output = function(src, links, options) {
19437       var inline = new InlineLexer(links, options);
19438       return inline.output(src);
19439     };
19440     
19441     /**
19442      * Lexing/Compiling
19443      */
19444     
19445     InlineLexer.prototype.output = function(src) {
19446       var out = ''
19447         , link
19448         , text
19449         , href
19450         , cap;
19451     
19452       while (src) {
19453         // escape
19454         if (cap = this.rules.escape.exec(src)) {
19455           src = src.substring(cap[0].length);
19456           out += cap[1];
19457           continue;
19458         }
19459     
19460         // autolink
19461         if (cap = this.rules.autolink.exec(src)) {
19462           src = src.substring(cap[0].length);
19463           if (cap[2] === '@') {
19464             text = cap[1].charAt(6) === ':'
19465               ? this.mangle(cap[1].substring(7))
19466               : this.mangle(cap[1]);
19467             href = this.mangle('mailto:') + text;
19468           } else {
19469             text = escape(cap[1]);
19470             href = text;
19471           }
19472           out += this.renderer.link(href, null, text);
19473           continue;
19474         }
19475     
19476         // url (gfm)
19477         if (!this.inLink && (cap = this.rules.url.exec(src))) {
19478           src = src.substring(cap[0].length);
19479           text = escape(cap[1]);
19480           href = text;
19481           out += this.renderer.link(href, null, text);
19482           continue;
19483         }
19484     
19485         // tag
19486         if (cap = this.rules.tag.exec(src)) {
19487           if (!this.inLink && /^<a /i.test(cap[0])) {
19488             this.inLink = true;
19489           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
19490             this.inLink = false;
19491           }
19492           src = src.substring(cap[0].length);
19493           out += this.options.sanitize
19494             ? this.options.sanitizer
19495               ? this.options.sanitizer(cap[0])
19496               : escape(cap[0])
19497             : cap[0];
19498           continue;
19499         }
19500     
19501         // link
19502         if (cap = this.rules.link.exec(src)) {
19503           src = src.substring(cap[0].length);
19504           this.inLink = true;
19505           out += this.outputLink(cap, {
19506             href: cap[2],
19507             title: cap[3]
19508           });
19509           this.inLink = false;
19510           continue;
19511         }
19512     
19513         // reflink, nolink
19514         if ((cap = this.rules.reflink.exec(src))
19515             || (cap = this.rules.nolink.exec(src))) {
19516           src = src.substring(cap[0].length);
19517           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19518           link = this.links[link.toLowerCase()];
19519           if (!link || !link.href) {
19520             out += cap[0].charAt(0);
19521             src = cap[0].substring(1) + src;
19522             continue;
19523           }
19524           this.inLink = true;
19525           out += this.outputLink(cap, link);
19526           this.inLink = false;
19527           continue;
19528         }
19529     
19530         // strong
19531         if (cap = this.rules.strong.exec(src)) {
19532           src = src.substring(cap[0].length);
19533           out += this.renderer.strong(this.output(cap[2] || cap[1]));
19534           continue;
19535         }
19536     
19537         // em
19538         if (cap = this.rules.em.exec(src)) {
19539           src = src.substring(cap[0].length);
19540           out += this.renderer.em(this.output(cap[2] || cap[1]));
19541           continue;
19542         }
19543     
19544         // code
19545         if (cap = this.rules.code.exec(src)) {
19546           src = src.substring(cap[0].length);
19547           out += this.renderer.codespan(escape(cap[2], true));
19548           continue;
19549         }
19550     
19551         // br
19552         if (cap = this.rules.br.exec(src)) {
19553           src = src.substring(cap[0].length);
19554           out += this.renderer.br();
19555           continue;
19556         }
19557     
19558         // del (gfm)
19559         if (cap = this.rules.del.exec(src)) {
19560           src = src.substring(cap[0].length);
19561           out += this.renderer.del(this.output(cap[1]));
19562           continue;
19563         }
19564     
19565         // text
19566         if (cap = this.rules.text.exec(src)) {
19567           src = src.substring(cap[0].length);
19568           out += this.renderer.text(escape(this.smartypants(cap[0])));
19569           continue;
19570         }
19571     
19572         if (src) {
19573           throw new
19574             Error('Infinite loop on byte: ' + src.charCodeAt(0));
19575         }
19576       }
19577     
19578       return out;
19579     };
19580     
19581     /**
19582      * Compile Link
19583      */
19584     
19585     InlineLexer.prototype.outputLink = function(cap, link) {
19586       var href = escape(link.href)
19587         , title = link.title ? escape(link.title) : null;
19588     
19589       return cap[0].charAt(0) !== '!'
19590         ? this.renderer.link(href, title, this.output(cap[1]))
19591         : this.renderer.image(href, title, escape(cap[1]));
19592     };
19593     
19594     /**
19595      * Smartypants Transformations
19596      */
19597     
19598     InlineLexer.prototype.smartypants = function(text) {
19599       if (!this.options.smartypants)  { return text; }
19600       return text
19601         // em-dashes
19602         .replace(/---/g, '\u2014')
19603         // en-dashes
19604         .replace(/--/g, '\u2013')
19605         // opening singles
19606         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19607         // closing singles & apostrophes
19608         .replace(/'/g, '\u2019')
19609         // opening doubles
19610         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19611         // closing doubles
19612         .replace(/"/g, '\u201d')
19613         // ellipses
19614         .replace(/\.{3}/g, '\u2026');
19615     };
19616     
19617     /**
19618      * Mangle Links
19619      */
19620     
19621     InlineLexer.prototype.mangle = function(text) {
19622       if (!this.options.mangle) { return text; }
19623       var out = ''
19624         , l = text.length
19625         , i = 0
19626         , ch;
19627     
19628       for (; i < l; i++) {
19629         ch = text.charCodeAt(i);
19630         if (Math.random() > 0.5) {
19631           ch = 'x' + ch.toString(16);
19632         }
19633         out += '&#' + ch + ';';
19634       }
19635     
19636       return out;
19637     };
19638     
19639     /**
19640      * Renderer
19641      */
19642     
19643      /**
19644          * eval:var:Renderer
19645     */
19646     
19647     var Renderer   = function (options) {
19648       this.options = options || {};
19649     }
19650     
19651     Renderer.prototype.code = function(code, lang, escaped) {
19652       if (this.options.highlight) {
19653         var out = this.options.highlight(code, lang);
19654         if (out != null && out !== code) {
19655           escaped = true;
19656           code = out;
19657         }
19658       } else {
19659             // hack!!! - it's already escapeD?
19660             escaped = true;
19661       }
19662     
19663       if (!lang) {
19664         return '<pre><code>'
19665           + (escaped ? code : escape(code, true))
19666           + '\n</code></pre>';
19667       }
19668     
19669       return '<pre><code class="'
19670         + this.options.langPrefix
19671         + escape(lang, true)
19672         + '">'
19673         + (escaped ? code : escape(code, true))
19674         + '\n</code></pre>\n';
19675     };
19676     
19677     Renderer.prototype.blockquote = function(quote) {
19678       return '<blockquote>\n' + quote + '</blockquote>\n';
19679     };
19680     
19681     Renderer.prototype.html = function(html) {
19682       return html;
19683     };
19684     
19685     Renderer.prototype.heading = function(text, level, raw) {
19686       return '<h'
19687         + level
19688         + ' id="'
19689         + this.options.headerPrefix
19690         + raw.toLowerCase().replace(/[^\w]+/g, '-')
19691         + '">'
19692         + text
19693         + '</h'
19694         + level
19695         + '>\n';
19696     };
19697     
19698     Renderer.prototype.hr = function() {
19699       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19700     };
19701     
19702     Renderer.prototype.list = function(body, ordered) {
19703       var type = ordered ? 'ol' : 'ul';
19704       return '<' + type + '>\n' + body + '</' + type + '>\n';
19705     };
19706     
19707     Renderer.prototype.listitem = function(text) {
19708       return '<li>' + text + '</li>\n';
19709     };
19710     
19711     Renderer.prototype.paragraph = function(text) {
19712       return '<p>' + text + '</p>\n';
19713     };
19714     
19715     Renderer.prototype.table = function(header, body) {
19716       return '<table class="table table-striped">\n'
19717         + '<thead>\n'
19718         + header
19719         + '</thead>\n'
19720         + '<tbody>\n'
19721         + body
19722         + '</tbody>\n'
19723         + '</table>\n';
19724     };
19725     
19726     Renderer.prototype.tablerow = function(content) {
19727       return '<tr>\n' + content + '</tr>\n';
19728     };
19729     
19730     Renderer.prototype.tablecell = function(content, flags) {
19731       var type = flags.header ? 'th' : 'td';
19732       var tag = flags.align
19733         ? '<' + type + ' style="text-align:' + flags.align + '">'
19734         : '<' + type + '>';
19735       return tag + content + '</' + type + '>\n';
19736     };
19737     
19738     // span level renderer
19739     Renderer.prototype.strong = function(text) {
19740       return '<strong>' + text + '</strong>';
19741     };
19742     
19743     Renderer.prototype.em = function(text) {
19744       return '<em>' + text + '</em>';
19745     };
19746     
19747     Renderer.prototype.codespan = function(text) {
19748       return '<code>' + text + '</code>';
19749     };
19750     
19751     Renderer.prototype.br = function() {
19752       return this.options.xhtml ? '<br/>' : '<br>';
19753     };
19754     
19755     Renderer.prototype.del = function(text) {
19756       return '<del>' + text + '</del>';
19757     };
19758     
19759     Renderer.prototype.link = function(href, title, text) {
19760       if (this.options.sanitize) {
19761         try {
19762           var prot = decodeURIComponent(unescape(href))
19763             .replace(/[^\w:]/g, '')
19764             .toLowerCase();
19765         } catch (e) {
19766           return '';
19767         }
19768         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19769           return '';
19770         }
19771       }
19772       var out = '<a href="' + href + '"';
19773       if (title) {
19774         out += ' title="' + title + '"';
19775       }
19776       out += '>' + text + '</a>';
19777       return out;
19778     };
19779     
19780     Renderer.prototype.image = function(href, title, text) {
19781       var out = '<img src="' + href + '" alt="' + text + '"';
19782       if (title) {
19783         out += ' title="' + title + '"';
19784       }
19785       out += this.options.xhtml ? '/>' : '>';
19786       return out;
19787     };
19788     
19789     Renderer.prototype.text = function(text) {
19790       return text;
19791     };
19792     
19793     /**
19794      * Parsing & Compiling
19795      */
19796          /**
19797          * eval:var:Parser
19798     */
19799     
19800     var Parser= function (options) {
19801       this.tokens = [];
19802       this.token = null;
19803       this.options = options || marked.defaults;
19804       this.options.renderer = this.options.renderer || new Renderer;
19805       this.renderer = this.options.renderer;
19806       this.renderer.options = this.options;
19807     }
19808     
19809     /**
19810      * Static Parse Method
19811      */
19812     
19813     Parser.parse = function(src, options, renderer) {
19814       var parser = new Parser(options, renderer);
19815       return parser.parse(src);
19816     };
19817     
19818     /**
19819      * Parse Loop
19820      */
19821     
19822     Parser.prototype.parse = function(src) {
19823       this.inline = new InlineLexer(src.links, this.options, this.renderer);
19824       this.tokens = src.reverse();
19825     
19826       var out = '';
19827       while (this.next()) {
19828         out += this.tok();
19829       }
19830     
19831       return out;
19832     };
19833     
19834     /**
19835      * Next Token
19836      */
19837     
19838     Parser.prototype.next = function() {
19839       return this.token = this.tokens.pop();
19840     };
19841     
19842     /**
19843      * Preview Next Token
19844      */
19845     
19846     Parser.prototype.peek = function() {
19847       return this.tokens[this.tokens.length - 1] || 0;
19848     };
19849     
19850     /**
19851      * Parse Text Tokens
19852      */
19853     
19854     Parser.prototype.parseText = function() {
19855       var body = this.token.text;
19856     
19857       while (this.peek().type === 'text') {
19858         body += '\n' + this.next().text;
19859       }
19860     
19861       return this.inline.output(body);
19862     };
19863     
19864     /**
19865      * Parse Current Token
19866      */
19867     
19868     Parser.prototype.tok = function() {
19869       switch (this.token.type) {
19870         case 'space': {
19871           return '';
19872         }
19873         case 'hr': {
19874           return this.renderer.hr();
19875         }
19876         case 'heading': {
19877           return this.renderer.heading(
19878             this.inline.output(this.token.text),
19879             this.token.depth,
19880             this.token.text);
19881         }
19882         case 'code': {
19883           return this.renderer.code(this.token.text,
19884             this.token.lang,
19885             this.token.escaped);
19886         }
19887         case 'table': {
19888           var header = ''
19889             , body = ''
19890             , i
19891             , row
19892             , cell
19893             , flags
19894             , j;
19895     
19896           // header
19897           cell = '';
19898           for (i = 0; i < this.token.header.length; i++) {
19899             flags = { header: true, align: this.token.align[i] };
19900             cell += this.renderer.tablecell(
19901               this.inline.output(this.token.header[i]),
19902               { header: true, align: this.token.align[i] }
19903             );
19904           }
19905           header += this.renderer.tablerow(cell);
19906     
19907           for (i = 0; i < this.token.cells.length; i++) {
19908             row = this.token.cells[i];
19909     
19910             cell = '';
19911             for (j = 0; j < row.length; j++) {
19912               cell += this.renderer.tablecell(
19913                 this.inline.output(row[j]),
19914                 { header: false, align: this.token.align[j] }
19915               );
19916             }
19917     
19918             body += this.renderer.tablerow(cell);
19919           }
19920           return this.renderer.table(header, body);
19921         }
19922         case 'blockquote_start': {
19923           var body = '';
19924     
19925           while (this.next().type !== 'blockquote_end') {
19926             body += this.tok();
19927           }
19928     
19929           return this.renderer.blockquote(body);
19930         }
19931         case 'list_start': {
19932           var body = ''
19933             , ordered = this.token.ordered;
19934     
19935           while (this.next().type !== 'list_end') {
19936             body += this.tok();
19937           }
19938     
19939           return this.renderer.list(body, ordered);
19940         }
19941         case 'list_item_start': {
19942           var body = '';
19943     
19944           while (this.next().type !== 'list_item_end') {
19945             body += this.token.type === 'text'
19946               ? this.parseText()
19947               : this.tok();
19948           }
19949     
19950           return this.renderer.listitem(body);
19951         }
19952         case 'loose_item_start': {
19953           var body = '';
19954     
19955           while (this.next().type !== 'list_item_end') {
19956             body += this.tok();
19957           }
19958     
19959           return this.renderer.listitem(body);
19960         }
19961         case 'html': {
19962           var html = !this.token.pre && !this.options.pedantic
19963             ? this.inline.output(this.token.text)
19964             : this.token.text;
19965           return this.renderer.html(html);
19966         }
19967         case 'paragraph': {
19968           return this.renderer.paragraph(this.inline.output(this.token.text));
19969         }
19970         case 'text': {
19971           return this.renderer.paragraph(this.parseText());
19972         }
19973       }
19974     };
19975   
19976     
19977     /**
19978      * Marked
19979      */
19980          /**
19981          * eval:var:marked
19982     */
19983     var marked = function (src, opt, callback) {
19984       if (callback || typeof opt === 'function') {
19985         if (!callback) {
19986           callback = opt;
19987           opt = null;
19988         }
19989     
19990         opt = merge({}, marked.defaults, opt || {});
19991     
19992         var highlight = opt.highlight
19993           , tokens
19994           , pending
19995           , i = 0;
19996     
19997         try {
19998           tokens = Lexer.lex(src, opt)
19999         } catch (e) {
20000           return callback(e);
20001         }
20002     
20003         pending = tokens.length;
20004          /**
20005          * eval:var:done
20006     */
20007         var done = function(err) {
20008           if (err) {
20009             opt.highlight = highlight;
20010             return callback(err);
20011           }
20012     
20013           var out;
20014     
20015           try {
20016             out = Parser.parse(tokens, opt);
20017           } catch (e) {
20018             err = e;
20019           }
20020     
20021           opt.highlight = highlight;
20022     
20023           return err
20024             ? callback(err)
20025             : callback(null, out);
20026         };
20027     
20028         if (!highlight || highlight.length < 3) {
20029           return done();
20030         }
20031     
20032         delete opt.highlight;
20033     
20034         if (!pending) { return done(); }
20035     
20036         for (; i < tokens.length; i++) {
20037           (function(token) {
20038             if (token.type !== 'code') {
20039               return --pending || done();
20040             }
20041             return highlight(token.text, token.lang, function(err, code) {
20042               if (err) { return done(err); }
20043               if (code == null || code === token.text) {
20044                 return --pending || done();
20045               }
20046               token.text = code;
20047               token.escaped = true;
20048               --pending || done();
20049             });
20050           })(tokens[i]);
20051         }
20052     
20053         return;
20054       }
20055       try {
20056         if (opt) { opt = merge({}, marked.defaults, opt); }
20057         return Parser.parse(Lexer.lex(src, opt), opt);
20058       } catch (e) {
20059         e.message += '\nPlease report this to https://github.com/chjj/marked.';
20060         if ((opt || marked.defaults).silent) {
20061           return '<p>An error occured:</p><pre>'
20062             + escape(e.message + '', true)
20063             + '</pre>';
20064         }
20065         throw e;
20066       }
20067     }
20068     
20069     /**
20070      * Options
20071      */
20072     
20073     marked.options =
20074     marked.setOptions = function(opt) {
20075       merge(marked.defaults, opt);
20076       return marked;
20077     };
20078     
20079     marked.defaults = {
20080       gfm: true,
20081       tables: true,
20082       breaks: false,
20083       pedantic: false,
20084       sanitize: false,
20085       sanitizer: null,
20086       mangle: true,
20087       smartLists: false,
20088       silent: false,
20089       highlight: null,
20090       langPrefix: 'lang-',
20091       smartypants: false,
20092       headerPrefix: '',
20093       renderer: new Renderer,
20094       xhtml: false
20095     };
20096     
20097     /**
20098      * Expose
20099      */
20100     
20101     marked.Parser = Parser;
20102     marked.parser = Parser.parse;
20103     
20104     marked.Renderer = Renderer;
20105     
20106     marked.Lexer = Lexer;
20107     marked.lexer = Lexer.lex;
20108     
20109     marked.InlineLexer = InlineLexer;
20110     marked.inlineLexer = InlineLexer.output;
20111     
20112     marked.parse = marked;
20113     
20114     Roo.Markdown.marked = marked;
20115
20116 })();/*
20117  * Based on:
20118  * Ext JS Library 1.1.1
20119  * Copyright(c) 2006-2007, Ext JS, LLC.
20120  *
20121  * Originally Released Under LGPL - original licence link has changed is not relivant.
20122  *
20123  * Fork - LGPL
20124  * <script type="text/javascript">
20125  */
20126
20127
20128
20129 /*
20130  * These classes are derivatives of the similarly named classes in the YUI Library.
20131  * The original license:
20132  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
20133  * Code licensed under the BSD License:
20134  * http://developer.yahoo.net/yui/license.txt
20135  */
20136
20137 (function() {
20138
20139 var Event=Roo.EventManager;
20140 var Dom=Roo.lib.Dom;
20141
20142 /**
20143  * @class Roo.dd.DragDrop
20144  * @extends Roo.util.Observable
20145  * Defines the interface and base operation of items that that can be
20146  * dragged or can be drop targets.  It was designed to be extended, overriding
20147  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
20148  * Up to three html elements can be associated with a DragDrop instance:
20149  * <ul>
20150  * <li>linked element: the element that is passed into the constructor.
20151  * This is the element which defines the boundaries for interaction with
20152  * other DragDrop objects.</li>
20153  * <li>handle element(s): The drag operation only occurs if the element that
20154  * was clicked matches a handle element.  By default this is the linked
20155  * element, but there are times that you will want only a portion of the
20156  * linked element to initiate the drag operation, and the setHandleElId()
20157  * method provides a way to define this.</li>
20158  * <li>drag element: this represents the element that would be moved along
20159  * with the cursor during a drag operation.  By default, this is the linked
20160  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
20161  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
20162  * </li>
20163  * </ul>
20164  * This class should not be instantiated until the onload event to ensure that
20165  * the associated elements are available.
20166  * The following would define a DragDrop obj that would interact with any
20167  * other DragDrop obj in the "group1" group:
20168  * <pre>
20169  *  dd = new Roo.dd.DragDrop("div1", "group1");
20170  * </pre>
20171  * Since none of the event handlers have been implemented, nothing would
20172  * actually happen if you were to run the code above.  Normally you would
20173  * override this class or one of the default implementations, but you can
20174  * also override the methods you want on an instance of the class...
20175  * <pre>
20176  *  dd.onDragDrop = function(e, id) {
20177  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
20178  *  }
20179  * </pre>
20180  * @constructor
20181  * @param {String} id of the element that is linked to this instance
20182  * @param {String} sGroup the group of related DragDrop objects
20183  * @param {object} config an object containing configurable attributes
20184  *                Valid properties for DragDrop:
20185  *                    padding, isTarget, maintainOffset, primaryButtonOnly
20186  */
20187 Roo.dd.DragDrop = function(id, sGroup, config) {
20188     if (id) {
20189         this.init(id, sGroup, config);
20190     }
20191     
20192 };
20193
20194 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
20195
20196     /**
20197      * The id of the element associated with this object.  This is what we
20198      * refer to as the "linked element" because the size and position of
20199      * this element is used to determine when the drag and drop objects have
20200      * interacted.
20201      * @property id
20202      * @type String
20203      */
20204     id: null,
20205
20206     /**
20207      * Configuration attributes passed into the constructor
20208      * @property config
20209      * @type object
20210      */
20211     config: null,
20212
20213     /**
20214      * The id of the element that will be dragged.  By default this is same
20215      * as the linked element , but could be changed to another element. Ex:
20216      * Roo.dd.DDProxy
20217      * @property dragElId
20218      * @type String
20219      * @private
20220      */
20221     dragElId: null,
20222
20223     /**
20224      * the id of the element that initiates the drag operation.  By default
20225      * this is the linked element, but could be changed to be a child of this
20226      * element.  This lets us do things like only starting the drag when the
20227      * header element within the linked html element is clicked.
20228      * @property handleElId
20229      * @type String
20230      * @private
20231      */
20232     handleElId: null,
20233
20234     /**
20235      * An associative array of HTML tags that will be ignored if clicked.
20236      * @property invalidHandleTypes
20237      * @type {string: string}
20238      */
20239     invalidHandleTypes: null,
20240
20241     /**
20242      * An associative array of ids for elements that will be ignored if clicked
20243      * @property invalidHandleIds
20244      * @type {string: string}
20245      */
20246     invalidHandleIds: null,
20247
20248     /**
20249      * An indexted array of css class names for elements that will be ignored
20250      * if clicked.
20251      * @property invalidHandleClasses
20252      * @type string[]
20253      */
20254     invalidHandleClasses: null,
20255
20256     /**
20257      * The linked element's absolute X position at the time the drag was
20258      * started
20259      * @property startPageX
20260      * @type int
20261      * @private
20262      */
20263     startPageX: 0,
20264
20265     /**
20266      * The linked element's absolute X position at the time the drag was
20267      * started
20268      * @property startPageY
20269      * @type int
20270      * @private
20271      */
20272     startPageY: 0,
20273
20274     /**
20275      * The group defines a logical collection of DragDrop objects that are
20276      * related.  Instances only get events when interacting with other
20277      * DragDrop object in the same group.  This lets us define multiple
20278      * groups using a single DragDrop subclass if we want.
20279      * @property groups
20280      * @type {string: string}
20281      */
20282     groups: null,
20283
20284     /**
20285      * Individual drag/drop instances can be locked.  This will prevent
20286      * onmousedown start drag.
20287      * @property locked
20288      * @type boolean
20289      * @private
20290      */
20291     locked: false,
20292
20293     /**
20294      * Lock this instance
20295      * @method lock
20296      */
20297     lock: function() { this.locked = true; },
20298
20299     /**
20300      * Unlock this instace
20301      * @method unlock
20302      */
20303     unlock: function() { this.locked = false; },
20304
20305     /**
20306      * By default, all insances can be a drop target.  This can be disabled by
20307      * setting isTarget to false.
20308      * @method isTarget
20309      * @type boolean
20310      */
20311     isTarget: true,
20312
20313     /**
20314      * The padding configured for this drag and drop object for calculating
20315      * the drop zone intersection with this object.
20316      * @method padding
20317      * @type int[]
20318      */
20319     padding: null,
20320
20321     /**
20322      * Cached reference to the linked element
20323      * @property _domRef
20324      * @private
20325      */
20326     _domRef: null,
20327
20328     /**
20329      * Internal typeof flag
20330      * @property __ygDragDrop
20331      * @private
20332      */
20333     __ygDragDrop: true,
20334
20335     /**
20336      * Set to true when horizontal contraints are applied
20337      * @property constrainX
20338      * @type boolean
20339      * @private
20340      */
20341     constrainX: false,
20342
20343     /**
20344      * Set to true when vertical contraints are applied
20345      * @property constrainY
20346      * @type boolean
20347      * @private
20348      */
20349     constrainY: false,
20350
20351     /**
20352      * The left constraint
20353      * @property minX
20354      * @type int
20355      * @private
20356      */
20357     minX: 0,
20358
20359     /**
20360      * The right constraint
20361      * @property maxX
20362      * @type int
20363      * @private
20364      */
20365     maxX: 0,
20366
20367     /**
20368      * The up constraint
20369      * @property minY
20370      * @type int
20371      * @type int
20372      * @private
20373      */
20374     minY: 0,
20375
20376     /**
20377      * The down constraint
20378      * @property maxY
20379      * @type int
20380      * @private
20381      */
20382     maxY: 0,
20383
20384     /**
20385      * Maintain offsets when we resetconstraints.  Set to true when you want
20386      * the position of the element relative to its parent to stay the same
20387      * when the page changes
20388      *
20389      * @property maintainOffset
20390      * @type boolean
20391      */
20392     maintainOffset: false,
20393
20394     /**
20395      * Array of pixel locations the element will snap to if we specified a
20396      * horizontal graduation/interval.  This array is generated automatically
20397      * when you define a tick interval.
20398      * @property xTicks
20399      * @type int[]
20400      */
20401     xTicks: null,
20402
20403     /**
20404      * Array of pixel locations the element will snap to if we specified a
20405      * vertical graduation/interval.  This array is generated automatically
20406      * when you define a tick interval.
20407      * @property yTicks
20408      * @type int[]
20409      */
20410     yTicks: null,
20411
20412     /**
20413      * By default the drag and drop instance will only respond to the primary
20414      * button click (left button for a right-handed mouse).  Set to true to
20415      * allow drag and drop to start with any mouse click that is propogated
20416      * by the browser
20417      * @property primaryButtonOnly
20418      * @type boolean
20419      */
20420     primaryButtonOnly: true,
20421
20422     /**
20423      * The availabe property is false until the linked dom element is accessible.
20424      * @property available
20425      * @type boolean
20426      */
20427     available: false,
20428
20429     /**
20430      * By default, drags can only be initiated if the mousedown occurs in the
20431      * region the linked element is.  This is done in part to work around a
20432      * bug in some browsers that mis-report the mousedown if the previous
20433      * mouseup happened outside of the window.  This property is set to true
20434      * if outer handles are defined.
20435      *
20436      * @property hasOuterHandles
20437      * @type boolean
20438      * @default false
20439      */
20440     hasOuterHandles: false,
20441
20442     /**
20443      * Code that executes immediately before the startDrag event
20444      * @method b4StartDrag
20445      * @private
20446      */
20447     b4StartDrag: function(x, y) { },
20448
20449     /**
20450      * Abstract method called after a drag/drop object is clicked
20451      * and the drag or mousedown time thresholds have beeen met.
20452      * @method startDrag
20453      * @param {int} X click location
20454      * @param {int} Y click location
20455      */
20456     startDrag: function(x, y) { /* override this */ },
20457
20458     /**
20459      * Code that executes immediately before the onDrag event
20460      * @method b4Drag
20461      * @private
20462      */
20463     b4Drag: function(e) { },
20464
20465     /**
20466      * Abstract method called during the onMouseMove event while dragging an
20467      * object.
20468      * @method onDrag
20469      * @param {Event} e the mousemove event
20470      */
20471     onDrag: function(e) { /* override this */ },
20472
20473     /**
20474      * Abstract method called when this element fist begins hovering over
20475      * another DragDrop obj
20476      * @method onDragEnter
20477      * @param {Event} e the mousemove event
20478      * @param {String|DragDrop[]} id In POINT mode, the element
20479      * id this is hovering over.  In INTERSECT mode, an array of one or more
20480      * dragdrop items being hovered over.
20481      */
20482     onDragEnter: function(e, id) { /* override this */ },
20483
20484     /**
20485      * Code that executes immediately before the onDragOver event
20486      * @method b4DragOver
20487      * @private
20488      */
20489     b4DragOver: function(e) { },
20490
20491     /**
20492      * Abstract method called when this element is hovering over another
20493      * DragDrop obj
20494      * @method onDragOver
20495      * @param {Event} e the mousemove event
20496      * @param {String|DragDrop[]} id In POINT mode, the element
20497      * id this is hovering over.  In INTERSECT mode, an array of dd items
20498      * being hovered over.
20499      */
20500     onDragOver: function(e, id) { /* override this */ },
20501
20502     /**
20503      * Code that executes immediately before the onDragOut event
20504      * @method b4DragOut
20505      * @private
20506      */
20507     b4DragOut: function(e) { },
20508
20509     /**
20510      * Abstract method called when we are no longer hovering over an element
20511      * @method onDragOut
20512      * @param {Event} e the mousemove event
20513      * @param {String|DragDrop[]} id In POINT mode, the element
20514      * id this was hovering over.  In INTERSECT mode, an array of dd items
20515      * that the mouse is no longer over.
20516      */
20517     onDragOut: function(e, id) { /* override this */ },
20518
20519     /**
20520      * Code that executes immediately before the onDragDrop event
20521      * @method b4DragDrop
20522      * @private
20523      */
20524     b4DragDrop: function(e) { },
20525
20526     /**
20527      * Abstract method called when this item is dropped on another DragDrop
20528      * obj
20529      * @method onDragDrop
20530      * @param {Event} e the mouseup event
20531      * @param {String|DragDrop[]} id In POINT mode, the element
20532      * id this was dropped on.  In INTERSECT mode, an array of dd items this
20533      * was dropped on.
20534      */
20535     onDragDrop: function(e, id) { /* override this */ },
20536
20537     /**
20538      * Abstract method called when this item is dropped on an area with no
20539      * drop target
20540      * @method onInvalidDrop
20541      * @param {Event} e the mouseup event
20542      */
20543     onInvalidDrop: function(e) { /* override this */ },
20544
20545     /**
20546      * Code that executes immediately before the endDrag event
20547      * @method b4EndDrag
20548      * @private
20549      */
20550     b4EndDrag: function(e) { },
20551
20552     /**
20553      * Fired when we are done dragging the object
20554      * @method endDrag
20555      * @param {Event} e the mouseup event
20556      */
20557     endDrag: function(e) { /* override this */ },
20558
20559     /**
20560      * Code executed immediately before the onMouseDown event
20561      * @method b4MouseDown
20562      * @param {Event} e the mousedown event
20563      * @private
20564      */
20565     b4MouseDown: function(e) {  },
20566
20567     /**
20568      * Event handler that fires when a drag/drop obj gets a mousedown
20569      * @method onMouseDown
20570      * @param {Event} e the mousedown event
20571      */
20572     onMouseDown: function(e) { /* override this */ },
20573
20574     /**
20575      * Event handler that fires when a drag/drop obj gets a mouseup
20576      * @method onMouseUp
20577      * @param {Event} e the mouseup event
20578      */
20579     onMouseUp: function(e) { /* override this */ },
20580
20581     /**
20582      * Override the onAvailable method to do what is needed after the initial
20583      * position was determined.
20584      * @method onAvailable
20585      */
20586     onAvailable: function () {
20587     },
20588
20589     /*
20590      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20591      * @type Object
20592      */
20593     defaultPadding : {left:0, right:0, top:0, bottom:0},
20594
20595     /*
20596      * Initializes the drag drop object's constraints to restrict movement to a certain element.
20597  *
20598  * Usage:
20599  <pre><code>
20600  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20601                 { dragElId: "existingProxyDiv" });
20602  dd.startDrag = function(){
20603      this.constrainTo("parent-id");
20604  };
20605  </code></pre>
20606  * Or you can initalize it using the {@link Roo.Element} object:
20607  <pre><code>
20608  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20609      startDrag : function(){
20610          this.constrainTo("parent-id");
20611      }
20612  });
20613  </code></pre>
20614      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20615      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20616      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20617      * an object containing the sides to pad. For example: {right:10, bottom:10}
20618      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20619      */
20620     constrainTo : function(constrainTo, pad, inContent){
20621         if(typeof pad == "number"){
20622             pad = {left: pad, right:pad, top:pad, bottom:pad};
20623         }
20624         pad = pad || this.defaultPadding;
20625         var b = Roo.get(this.getEl()).getBox();
20626         var ce = Roo.get(constrainTo);
20627         var s = ce.getScroll();
20628         var c, cd = ce.dom;
20629         if(cd == document.body){
20630             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20631         }else{
20632             xy = ce.getXY();
20633             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20634         }
20635
20636
20637         var topSpace = b.y - c.y;
20638         var leftSpace = b.x - c.x;
20639
20640         this.resetConstraints();
20641         this.setXConstraint(leftSpace - (pad.left||0), // left
20642                 c.width - leftSpace - b.width - (pad.right||0) //right
20643         );
20644         this.setYConstraint(topSpace - (pad.top||0), //top
20645                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20646         );
20647     },
20648
20649     /**
20650      * Returns a reference to the linked element
20651      * @method getEl
20652      * @return {HTMLElement} the html element
20653      */
20654     getEl: function() {
20655         if (!this._domRef) {
20656             this._domRef = Roo.getDom(this.id);
20657         }
20658
20659         return this._domRef;
20660     },
20661
20662     /**
20663      * Returns a reference to the actual element to drag.  By default this is
20664      * the same as the html element, but it can be assigned to another
20665      * element. An example of this can be found in Roo.dd.DDProxy
20666      * @method getDragEl
20667      * @return {HTMLElement} the html element
20668      */
20669     getDragEl: function() {
20670         return Roo.getDom(this.dragElId);
20671     },
20672
20673     /**
20674      * Sets up the DragDrop object.  Must be called in the constructor of any
20675      * Roo.dd.DragDrop subclass
20676      * @method init
20677      * @param id the id of the linked element
20678      * @param {String} sGroup the group of related items
20679      * @param {object} config configuration attributes
20680      */
20681     init: function(id, sGroup, config) {
20682         this.initTarget(id, sGroup, config);
20683         if (!Roo.isTouch) {
20684             Event.on(this.id, "mousedown", this.handleMouseDown, this);
20685         }
20686         Event.on(this.id, "touchstart", this.handleMouseDown, this);
20687         // Event.on(this.id, "selectstart", Event.preventDefault);
20688     },
20689
20690     /**
20691      * Initializes Targeting functionality only... the object does not
20692      * get a mousedown handler.
20693      * @method initTarget
20694      * @param id the id of the linked element
20695      * @param {String} sGroup the group of related items
20696      * @param {object} config configuration attributes
20697      */
20698     initTarget: function(id, sGroup, config) {
20699
20700         // configuration attributes
20701         this.config = config || {};
20702
20703         // create a local reference to the drag and drop manager
20704         this.DDM = Roo.dd.DDM;
20705         // initialize the groups array
20706         this.groups = {};
20707
20708         // assume that we have an element reference instead of an id if the
20709         // parameter is not a string
20710         if (typeof id !== "string") {
20711             id = Roo.id(id);
20712         }
20713
20714         // set the id
20715         this.id = id;
20716
20717         // add to an interaction group
20718         this.addToGroup((sGroup) ? sGroup : "default");
20719
20720         // We don't want to register this as the handle with the manager
20721         // so we just set the id rather than calling the setter.
20722         this.handleElId = id;
20723
20724         // the linked element is the element that gets dragged by default
20725         this.setDragElId(id);
20726
20727         // by default, clicked anchors will not start drag operations.
20728         this.invalidHandleTypes = { A: "A" };
20729         this.invalidHandleIds = {};
20730         this.invalidHandleClasses = [];
20731
20732         this.applyConfig();
20733
20734         this.handleOnAvailable();
20735     },
20736
20737     /**
20738      * Applies the configuration parameters that were passed into the constructor.
20739      * This is supposed to happen at each level through the inheritance chain.  So
20740      * a DDProxy implentation will execute apply config on DDProxy, DD, and
20741      * DragDrop in order to get all of the parameters that are available in
20742      * each object.
20743      * @method applyConfig
20744      */
20745     applyConfig: function() {
20746
20747         // configurable properties:
20748         //    padding, isTarget, maintainOffset, primaryButtonOnly
20749         this.padding           = this.config.padding || [0, 0, 0, 0];
20750         this.isTarget          = (this.config.isTarget !== false);
20751         this.maintainOffset    = (this.config.maintainOffset);
20752         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20753
20754     },
20755
20756     /**
20757      * Executed when the linked element is available
20758      * @method handleOnAvailable
20759      * @private
20760      */
20761     handleOnAvailable: function() {
20762         this.available = true;
20763         this.resetConstraints();
20764         this.onAvailable();
20765     },
20766
20767      /**
20768      * Configures the padding for the target zone in px.  Effectively expands
20769      * (or reduces) the virtual object size for targeting calculations.
20770      * Supports css-style shorthand; if only one parameter is passed, all sides
20771      * will have that padding, and if only two are passed, the top and bottom
20772      * will have the first param, the left and right the second.
20773      * @method setPadding
20774      * @param {int} iTop    Top pad
20775      * @param {int} iRight  Right pad
20776      * @param {int} iBot    Bot pad
20777      * @param {int} iLeft   Left pad
20778      */
20779     setPadding: function(iTop, iRight, iBot, iLeft) {
20780         // this.padding = [iLeft, iRight, iTop, iBot];
20781         if (!iRight && 0 !== iRight) {
20782             this.padding = [iTop, iTop, iTop, iTop];
20783         } else if (!iBot && 0 !== iBot) {
20784             this.padding = [iTop, iRight, iTop, iRight];
20785         } else {
20786             this.padding = [iTop, iRight, iBot, iLeft];
20787         }
20788     },
20789
20790     /**
20791      * Stores the initial placement of the linked element.
20792      * @method setInitialPosition
20793      * @param {int} diffX   the X offset, default 0
20794      * @param {int} diffY   the Y offset, default 0
20795      */
20796     setInitPosition: function(diffX, diffY) {
20797         var el = this.getEl();
20798
20799         if (!this.DDM.verifyEl(el)) {
20800             return;
20801         }
20802
20803         var dx = diffX || 0;
20804         var dy = diffY || 0;
20805
20806         var p = Dom.getXY( el );
20807
20808         this.initPageX = p[0] - dx;
20809         this.initPageY = p[1] - dy;
20810
20811         this.lastPageX = p[0];
20812         this.lastPageY = p[1];
20813
20814
20815         this.setStartPosition(p);
20816     },
20817
20818     /**
20819      * Sets the start position of the element.  This is set when the obj
20820      * is initialized, the reset when a drag is started.
20821      * @method setStartPosition
20822      * @param pos current position (from previous lookup)
20823      * @private
20824      */
20825     setStartPosition: function(pos) {
20826         var p = pos || Dom.getXY( this.getEl() );
20827         this.deltaSetXY = null;
20828
20829         this.startPageX = p[0];
20830         this.startPageY = p[1];
20831     },
20832
20833     /**
20834      * Add this instance to a group of related drag/drop objects.  All
20835      * instances belong to at least one group, and can belong to as many
20836      * groups as needed.
20837      * @method addToGroup
20838      * @param sGroup {string} the name of the group
20839      */
20840     addToGroup: function(sGroup) {
20841         this.groups[sGroup] = true;
20842         this.DDM.regDragDrop(this, sGroup);
20843     },
20844
20845     /**
20846      * Remove's this instance from the supplied interaction group
20847      * @method removeFromGroup
20848      * @param {string}  sGroup  The group to drop
20849      */
20850     removeFromGroup: function(sGroup) {
20851         if (this.groups[sGroup]) {
20852             delete this.groups[sGroup];
20853         }
20854
20855         this.DDM.removeDDFromGroup(this, sGroup);
20856     },
20857
20858     /**
20859      * Allows you to specify that an element other than the linked element
20860      * will be moved with the cursor during a drag
20861      * @method setDragElId
20862      * @param id {string} the id of the element that will be used to initiate the drag
20863      */
20864     setDragElId: function(id) {
20865         this.dragElId = id;
20866     },
20867
20868     /**
20869      * Allows you to specify a child of the linked element that should be
20870      * used to initiate the drag operation.  An example of this would be if
20871      * you have a content div with text and links.  Clicking anywhere in the
20872      * content area would normally start the drag operation.  Use this method
20873      * to specify that an element inside of the content div is the element
20874      * that starts the drag operation.
20875      * @method setHandleElId
20876      * @param id {string} the id of the element that will be used to
20877      * initiate the drag.
20878      */
20879     setHandleElId: function(id) {
20880         if (typeof id !== "string") {
20881             id = Roo.id(id);
20882         }
20883         this.handleElId = id;
20884         this.DDM.regHandle(this.id, id);
20885     },
20886
20887     /**
20888      * Allows you to set an element outside of the linked element as a drag
20889      * handle
20890      * @method setOuterHandleElId
20891      * @param id the id of the element that will be used to initiate the drag
20892      */
20893     setOuterHandleElId: function(id) {
20894         if (typeof id !== "string") {
20895             id = Roo.id(id);
20896         }
20897         Event.on(id, "mousedown",
20898                 this.handleMouseDown, this);
20899         this.setHandleElId(id);
20900
20901         this.hasOuterHandles = true;
20902     },
20903
20904     /**
20905      * Remove all drag and drop hooks for this element
20906      * @method unreg
20907      */
20908     unreg: function() {
20909         Event.un(this.id, "mousedown",
20910                 this.handleMouseDown);
20911         Event.un(this.id, "touchstart",
20912                 this.handleMouseDown);
20913         this._domRef = null;
20914         this.DDM._remove(this);
20915     },
20916
20917     destroy : function(){
20918         this.unreg();
20919     },
20920
20921     /**
20922      * Returns true if this instance is locked, or the drag drop mgr is locked
20923      * (meaning that all drag/drop is disabled on the page.)
20924      * @method isLocked
20925      * @return {boolean} true if this obj or all drag/drop is locked, else
20926      * false
20927      */
20928     isLocked: function() {
20929         return (this.DDM.isLocked() || this.locked);
20930     },
20931
20932     /**
20933      * Fired when this object is clicked
20934      * @method handleMouseDown
20935      * @param {Event} e
20936      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20937      * @private
20938      */
20939     handleMouseDown: function(e, oDD){
20940      
20941         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20942             //Roo.log('not touch/ button !=0');
20943             return;
20944         }
20945         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20946             return; // double touch..
20947         }
20948         
20949
20950         if (this.isLocked()) {
20951             //Roo.log('locked');
20952             return;
20953         }
20954
20955         this.DDM.refreshCache(this.groups);
20956 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20957         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20958         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
20959             //Roo.log('no outer handes or not over target');
20960                 // do nothing.
20961         } else {
20962 //            Roo.log('check validator');
20963             if (this.clickValidator(e)) {
20964 //                Roo.log('validate success');
20965                 // set the initial element position
20966                 this.setStartPosition();
20967
20968
20969                 this.b4MouseDown(e);
20970                 this.onMouseDown(e);
20971
20972                 this.DDM.handleMouseDown(e, this);
20973
20974                 this.DDM.stopEvent(e);
20975             } else {
20976
20977
20978             }
20979         }
20980     },
20981
20982     clickValidator: function(e) {
20983         var target = e.getTarget();
20984         return ( this.isValidHandleChild(target) &&
20985                     (this.id == this.handleElId ||
20986                         this.DDM.handleWasClicked(target, this.id)) );
20987     },
20988
20989     /**
20990      * Allows you to specify a tag name that should not start a drag operation
20991      * when clicked.  This is designed to facilitate embedding links within a
20992      * drag handle that do something other than start the drag.
20993      * @method addInvalidHandleType
20994      * @param {string} tagName the type of element to exclude
20995      */
20996     addInvalidHandleType: function(tagName) {
20997         var type = tagName.toUpperCase();
20998         this.invalidHandleTypes[type] = type;
20999     },
21000
21001     /**
21002      * Lets you to specify an element id for a child of a drag handle
21003      * that should not initiate a drag
21004      * @method addInvalidHandleId
21005      * @param {string} id the element id of the element you wish to ignore
21006      */
21007     addInvalidHandleId: function(id) {
21008         if (typeof id !== "string") {
21009             id = Roo.id(id);
21010         }
21011         this.invalidHandleIds[id] = id;
21012     },
21013
21014     /**
21015      * Lets you specify a css class of elements that will not initiate a drag
21016      * @method addInvalidHandleClass
21017      * @param {string} cssClass the class of the elements you wish to ignore
21018      */
21019     addInvalidHandleClass: function(cssClass) {
21020         this.invalidHandleClasses.push(cssClass);
21021     },
21022
21023     /**
21024      * Unsets an excluded tag name set by addInvalidHandleType
21025      * @method removeInvalidHandleType
21026      * @param {string} tagName the type of element to unexclude
21027      */
21028     removeInvalidHandleType: function(tagName) {
21029         var type = tagName.toUpperCase();
21030         // this.invalidHandleTypes[type] = null;
21031         delete this.invalidHandleTypes[type];
21032     },
21033
21034     /**
21035      * Unsets an invalid handle id
21036      * @method removeInvalidHandleId
21037      * @param {string} id the id of the element to re-enable
21038      */
21039     removeInvalidHandleId: function(id) {
21040         if (typeof id !== "string") {
21041             id = Roo.id(id);
21042         }
21043         delete this.invalidHandleIds[id];
21044     },
21045
21046     /**
21047      * Unsets an invalid css class
21048      * @method removeInvalidHandleClass
21049      * @param {string} cssClass the class of the element(s) you wish to
21050      * re-enable
21051      */
21052     removeInvalidHandleClass: function(cssClass) {
21053         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
21054             if (this.invalidHandleClasses[i] == cssClass) {
21055                 delete this.invalidHandleClasses[i];
21056             }
21057         }
21058     },
21059
21060     /**
21061      * Checks the tag exclusion list to see if this click should be ignored
21062      * @method isValidHandleChild
21063      * @param {HTMLElement} node the HTMLElement to evaluate
21064      * @return {boolean} true if this is a valid tag type, false if not
21065      */
21066     isValidHandleChild: function(node) {
21067
21068         var valid = true;
21069         // var n = (node.nodeName == "#text") ? node.parentNode : node;
21070         var nodeName;
21071         try {
21072             nodeName = node.nodeName.toUpperCase();
21073         } catch(e) {
21074             nodeName = node.nodeName;
21075         }
21076         valid = valid && !this.invalidHandleTypes[nodeName];
21077         valid = valid && !this.invalidHandleIds[node.id];
21078
21079         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
21080             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
21081         }
21082
21083
21084         return valid;
21085
21086     },
21087
21088     /**
21089      * Create the array of horizontal tick marks if an interval was specified
21090      * in setXConstraint().
21091      * @method setXTicks
21092      * @private
21093      */
21094     setXTicks: function(iStartX, iTickSize) {
21095         this.xTicks = [];
21096         this.xTickSize = iTickSize;
21097
21098         var tickMap = {};
21099
21100         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
21101             if (!tickMap[i]) {
21102                 this.xTicks[this.xTicks.length] = i;
21103                 tickMap[i] = true;
21104             }
21105         }
21106
21107         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
21108             if (!tickMap[i]) {
21109                 this.xTicks[this.xTicks.length] = i;
21110                 tickMap[i] = true;
21111             }
21112         }
21113
21114         this.xTicks.sort(this.DDM.numericSort) ;
21115     },
21116
21117     /**
21118      * Create the array of vertical tick marks if an interval was specified in
21119      * setYConstraint().
21120      * @method setYTicks
21121      * @private
21122      */
21123     setYTicks: function(iStartY, iTickSize) {
21124         this.yTicks = [];
21125         this.yTickSize = iTickSize;
21126
21127         var tickMap = {};
21128
21129         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
21130             if (!tickMap[i]) {
21131                 this.yTicks[this.yTicks.length] = i;
21132                 tickMap[i] = true;
21133             }
21134         }
21135
21136         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
21137             if (!tickMap[i]) {
21138                 this.yTicks[this.yTicks.length] = i;
21139                 tickMap[i] = true;
21140             }
21141         }
21142
21143         this.yTicks.sort(this.DDM.numericSort) ;
21144     },
21145
21146     /**
21147      * By default, the element can be dragged any place on the screen.  Use
21148      * this method to limit the horizontal travel of the element.  Pass in
21149      * 0,0 for the parameters if you want to lock the drag to the y axis.
21150      * @method setXConstraint
21151      * @param {int} iLeft the number of pixels the element can move to the left
21152      * @param {int} iRight the number of pixels the element can move to the
21153      * right
21154      * @param {int} iTickSize optional parameter for specifying that the
21155      * element
21156      * should move iTickSize pixels at a time.
21157      */
21158     setXConstraint: function(iLeft, iRight, iTickSize) {
21159         this.leftConstraint = iLeft;
21160         this.rightConstraint = iRight;
21161
21162         this.minX = this.initPageX - iLeft;
21163         this.maxX = this.initPageX + iRight;
21164         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
21165
21166         this.constrainX = true;
21167     },
21168
21169     /**
21170      * Clears any constraints applied to this instance.  Also clears ticks
21171      * since they can't exist independent of a constraint at this time.
21172      * @method clearConstraints
21173      */
21174     clearConstraints: function() {
21175         this.constrainX = false;
21176         this.constrainY = false;
21177         this.clearTicks();
21178     },
21179
21180     /**
21181      * Clears any tick interval defined for this instance
21182      * @method clearTicks
21183      */
21184     clearTicks: function() {
21185         this.xTicks = null;
21186         this.yTicks = null;
21187         this.xTickSize = 0;
21188         this.yTickSize = 0;
21189     },
21190
21191     /**
21192      * By default, the element can be dragged any place on the screen.  Set
21193      * this to limit the vertical travel of the element.  Pass in 0,0 for the
21194      * parameters if you want to lock the drag to the x axis.
21195      * @method setYConstraint
21196      * @param {int} iUp the number of pixels the element can move up
21197      * @param {int} iDown the number of pixels the element can move down
21198      * @param {int} iTickSize optional parameter for specifying that the
21199      * element should move iTickSize pixels at a time.
21200      */
21201     setYConstraint: function(iUp, iDown, iTickSize) {
21202         this.topConstraint = iUp;
21203         this.bottomConstraint = iDown;
21204
21205         this.minY = this.initPageY - iUp;
21206         this.maxY = this.initPageY + iDown;
21207         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
21208
21209         this.constrainY = true;
21210
21211     },
21212
21213     /**
21214      * resetConstraints must be called if you manually reposition a dd element.
21215      * @method resetConstraints
21216      * @param {boolean} maintainOffset
21217      */
21218     resetConstraints: function() {
21219
21220
21221         // Maintain offsets if necessary
21222         if (this.initPageX || this.initPageX === 0) {
21223             // figure out how much this thing has moved
21224             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
21225             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
21226
21227             this.setInitPosition(dx, dy);
21228
21229         // This is the first time we have detected the element's position
21230         } else {
21231             this.setInitPosition();
21232         }
21233
21234         if (this.constrainX) {
21235             this.setXConstraint( this.leftConstraint,
21236                                  this.rightConstraint,
21237                                  this.xTickSize        );
21238         }
21239
21240         if (this.constrainY) {
21241             this.setYConstraint( this.topConstraint,
21242                                  this.bottomConstraint,
21243                                  this.yTickSize         );
21244         }
21245     },
21246
21247     /**
21248      * Normally the drag element is moved pixel by pixel, but we can specify
21249      * that it move a number of pixels at a time.  This method resolves the
21250      * location when we have it set up like this.
21251      * @method getTick
21252      * @param {int} val where we want to place the object
21253      * @param {int[]} tickArray sorted array of valid points
21254      * @return {int} the closest tick
21255      * @private
21256      */
21257     getTick: function(val, tickArray) {
21258
21259         if (!tickArray) {
21260             // If tick interval is not defined, it is effectively 1 pixel,
21261             // so we return the value passed to us.
21262             return val;
21263         } else if (tickArray[0] >= val) {
21264             // The value is lower than the first tick, so we return the first
21265             // tick.
21266             return tickArray[0];
21267         } else {
21268             for (var i=0, len=tickArray.length; i<len; ++i) {
21269                 var next = i + 1;
21270                 if (tickArray[next] && tickArray[next] >= val) {
21271                     var diff1 = val - tickArray[i];
21272                     var diff2 = tickArray[next] - val;
21273                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
21274                 }
21275             }
21276
21277             // The value is larger than the last tick, so we return the last
21278             // tick.
21279             return tickArray[tickArray.length - 1];
21280         }
21281     },
21282
21283     /**
21284      * toString method
21285      * @method toString
21286      * @return {string} string representation of the dd obj
21287      */
21288     toString: function() {
21289         return ("DragDrop " + this.id);
21290     }
21291
21292 });
21293
21294 })();
21295 /*
21296  * Based on:
21297  * Ext JS Library 1.1.1
21298  * Copyright(c) 2006-2007, Ext JS, LLC.
21299  *
21300  * Originally Released Under LGPL - original licence link has changed is not relivant.
21301  *
21302  * Fork - LGPL
21303  * <script type="text/javascript">
21304  */
21305
21306
21307 /**
21308  * The drag and drop utility provides a framework for building drag and drop
21309  * applications.  In addition to enabling drag and drop for specific elements,
21310  * the drag and drop elements are tracked by the manager class, and the
21311  * interactions between the various elements are tracked during the drag and
21312  * the implementing code is notified about these important moments.
21313  */
21314
21315 // Only load the library once.  Rewriting the manager class would orphan
21316 // existing drag and drop instances.
21317 if (!Roo.dd.DragDropMgr) {
21318
21319 /**
21320  * @class Roo.dd.DragDropMgr
21321  * DragDropMgr is a singleton that tracks the element interaction for
21322  * all DragDrop items in the window.  Generally, you will not call
21323  * this class directly, but it does have helper methods that could
21324  * be useful in your DragDrop implementations.
21325  * @static
21326  */
21327 Roo.dd.DragDropMgr = function() {
21328
21329     var Event = Roo.EventManager;
21330
21331     return {
21332
21333         /**
21334          * Two dimensional Array of registered DragDrop objects.  The first
21335          * dimension is the DragDrop item group, the second the DragDrop
21336          * object.
21337          * @property ids
21338          * @type {string: string}
21339          * @private
21340          * @static
21341          */
21342         ids: {},
21343
21344         /**
21345          * Array of element ids defined as drag handles.  Used to determine
21346          * if the element that generated the mousedown event is actually the
21347          * handle and not the html element itself.
21348          * @property handleIds
21349          * @type {string: string}
21350          * @private
21351          * @static
21352          */
21353         handleIds: {},
21354
21355         /**
21356          * the DragDrop object that is currently being dragged
21357          * @property dragCurrent
21358          * @type DragDrop
21359          * @private
21360          * @static
21361          **/
21362         dragCurrent: null,
21363
21364         /**
21365          * the DragDrop object(s) that are being hovered over
21366          * @property dragOvers
21367          * @type Array
21368          * @private
21369          * @static
21370          */
21371         dragOvers: {},
21372
21373         /**
21374          * the X distance between the cursor and the object being dragged
21375          * @property deltaX
21376          * @type int
21377          * @private
21378          * @static
21379          */
21380         deltaX: 0,
21381
21382         /**
21383          * the Y distance between the cursor and the object being dragged
21384          * @property deltaY
21385          * @type int
21386          * @private
21387          * @static
21388          */
21389         deltaY: 0,
21390
21391         /**
21392          * Flag to determine if we should prevent the default behavior of the
21393          * events we define. By default this is true, but this can be set to
21394          * false if you need the default behavior (not recommended)
21395          * @property preventDefault
21396          * @type boolean
21397          * @static
21398          */
21399         preventDefault: true,
21400
21401         /**
21402          * Flag to determine if we should stop the propagation of the events
21403          * we generate. This is true by default but you may want to set it to
21404          * false if the html element contains other features that require the
21405          * mouse click.
21406          * @property stopPropagation
21407          * @type boolean
21408          * @static
21409          */
21410         stopPropagation: true,
21411
21412         /**
21413          * Internal flag that is set to true when drag and drop has been
21414          * intialized
21415          * @property initialized
21416          * @private
21417          * @static
21418          */
21419         initalized: false,
21420
21421         /**
21422          * All drag and drop can be disabled.
21423          * @property locked
21424          * @private
21425          * @static
21426          */
21427         locked: false,
21428
21429         /**
21430          * Called the first time an element is registered.
21431          * @method init
21432          * @private
21433          * @static
21434          */
21435         init: function() {
21436             this.initialized = true;
21437         },
21438
21439         /**
21440          * In point mode, drag and drop interaction is defined by the
21441          * location of the cursor during the drag/drop
21442          * @property POINT
21443          * @type int
21444          * @static
21445          */
21446         POINT: 0,
21447
21448         /**
21449          * In intersect mode, drag and drop interactio nis defined by the
21450          * overlap of two or more drag and drop objects.
21451          * @property INTERSECT
21452          * @type int
21453          * @static
21454          */
21455         INTERSECT: 1,
21456
21457         /**
21458          * The current drag and drop mode.  Default: POINT
21459          * @property mode
21460          * @type int
21461          * @static
21462          */
21463         mode: 0,
21464
21465         /**
21466          * Runs method on all drag and drop objects
21467          * @method _execOnAll
21468          * @private
21469          * @static
21470          */
21471         _execOnAll: function(sMethod, args) {
21472             for (var i in this.ids) {
21473                 for (var j in this.ids[i]) {
21474                     var oDD = this.ids[i][j];
21475                     if (! this.isTypeOfDD(oDD)) {
21476                         continue;
21477                     }
21478                     oDD[sMethod].apply(oDD, args);
21479                 }
21480             }
21481         },
21482
21483         /**
21484          * Drag and drop initialization.  Sets up the global event handlers
21485          * @method _onLoad
21486          * @private
21487          * @static
21488          */
21489         _onLoad: function() {
21490
21491             this.init();
21492
21493             if (!Roo.isTouch) {
21494                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
21495                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
21496             }
21497             Event.on(document, "touchend",   this.handleMouseUp, this, true);
21498             Event.on(document, "touchmove", this.handleMouseMove, this, true);
21499             
21500             Event.on(window,   "unload",    this._onUnload, this, true);
21501             Event.on(window,   "resize",    this._onResize, this, true);
21502             // Event.on(window,   "mouseout",    this._test);
21503
21504         },
21505
21506         /**
21507          * Reset constraints on all drag and drop objs
21508          * @method _onResize
21509          * @private
21510          * @static
21511          */
21512         _onResize: function(e) {
21513             this._execOnAll("resetConstraints", []);
21514         },
21515
21516         /**
21517          * Lock all drag and drop functionality
21518          * @method lock
21519          * @static
21520          */
21521         lock: function() { this.locked = true; },
21522
21523         /**
21524          * Unlock all drag and drop functionality
21525          * @method unlock
21526          * @static
21527          */
21528         unlock: function() { this.locked = false; },
21529
21530         /**
21531          * Is drag and drop locked?
21532          * @method isLocked
21533          * @return {boolean} True if drag and drop is locked, false otherwise.
21534          * @static
21535          */
21536         isLocked: function() { return this.locked; },
21537
21538         /**
21539          * Location cache that is set for all drag drop objects when a drag is
21540          * initiated, cleared when the drag is finished.
21541          * @property locationCache
21542          * @private
21543          * @static
21544          */
21545         locationCache: {},
21546
21547         /**
21548          * Set useCache to false if you want to force object the lookup of each
21549          * drag and drop linked element constantly during a drag.
21550          * @property useCache
21551          * @type boolean
21552          * @static
21553          */
21554         useCache: true,
21555
21556         /**
21557          * The number of pixels that the mouse needs to move after the
21558          * mousedown before the drag is initiated.  Default=3;
21559          * @property clickPixelThresh
21560          * @type int
21561          * @static
21562          */
21563         clickPixelThresh: 3,
21564
21565         /**
21566          * The number of milliseconds after the mousedown event to initiate the
21567          * drag if we don't get a mouseup event. Default=1000
21568          * @property clickTimeThresh
21569          * @type int
21570          * @static
21571          */
21572         clickTimeThresh: 350,
21573
21574         /**
21575          * Flag that indicates that either the drag pixel threshold or the
21576          * mousdown time threshold has been met
21577          * @property dragThreshMet
21578          * @type boolean
21579          * @private
21580          * @static
21581          */
21582         dragThreshMet: false,
21583
21584         /**
21585          * Timeout used for the click time threshold
21586          * @property clickTimeout
21587          * @type Object
21588          * @private
21589          * @static
21590          */
21591         clickTimeout: null,
21592
21593         /**
21594          * The X position of the mousedown event stored for later use when a
21595          * drag threshold is met.
21596          * @property startX
21597          * @type int
21598          * @private
21599          * @static
21600          */
21601         startX: 0,
21602
21603         /**
21604          * The Y position of the mousedown event stored for later use when a
21605          * drag threshold is met.
21606          * @property startY
21607          * @type int
21608          * @private
21609          * @static
21610          */
21611         startY: 0,
21612
21613         /**
21614          * Each DragDrop instance must be registered with the DragDropMgr.
21615          * This is executed in DragDrop.init()
21616          * @method regDragDrop
21617          * @param {DragDrop} oDD the DragDrop object to register
21618          * @param {String} sGroup the name of the group this element belongs to
21619          * @static
21620          */
21621         regDragDrop: function(oDD, sGroup) {
21622             if (!this.initialized) { this.init(); }
21623
21624             if (!this.ids[sGroup]) {
21625                 this.ids[sGroup] = {};
21626             }
21627             this.ids[sGroup][oDD.id] = oDD;
21628         },
21629
21630         /**
21631          * Removes the supplied dd instance from the supplied group. Executed
21632          * by DragDrop.removeFromGroup, so don't call this function directly.
21633          * @method removeDDFromGroup
21634          * @private
21635          * @static
21636          */
21637         removeDDFromGroup: function(oDD, sGroup) {
21638             if (!this.ids[sGroup]) {
21639                 this.ids[sGroup] = {};
21640             }
21641
21642             var obj = this.ids[sGroup];
21643             if (obj && obj[oDD.id]) {
21644                 delete obj[oDD.id];
21645             }
21646         },
21647
21648         /**
21649          * Unregisters a drag and drop item.  This is executed in
21650          * DragDrop.unreg, use that method instead of calling this directly.
21651          * @method _remove
21652          * @private
21653          * @static
21654          */
21655         _remove: function(oDD) {
21656             for (var g in oDD.groups) {
21657                 if (g && this.ids[g][oDD.id]) {
21658                     delete this.ids[g][oDD.id];
21659                 }
21660             }
21661             delete this.handleIds[oDD.id];
21662         },
21663
21664         /**
21665          * Each DragDrop handle element must be registered.  This is done
21666          * automatically when executing DragDrop.setHandleElId()
21667          * @method regHandle
21668          * @param {String} sDDId the DragDrop id this element is a handle for
21669          * @param {String} sHandleId the id of the element that is the drag
21670          * handle
21671          * @static
21672          */
21673         regHandle: function(sDDId, sHandleId) {
21674             if (!this.handleIds[sDDId]) {
21675                 this.handleIds[sDDId] = {};
21676             }
21677             this.handleIds[sDDId][sHandleId] = sHandleId;
21678         },
21679
21680         /**
21681          * Utility function to determine if a given element has been
21682          * registered as a drag drop item.
21683          * @method isDragDrop
21684          * @param {String} id the element id to check
21685          * @return {boolean} true if this element is a DragDrop item,
21686          * false otherwise
21687          * @static
21688          */
21689         isDragDrop: function(id) {
21690             return ( this.getDDById(id) ) ? true : false;
21691         },
21692
21693         /**
21694          * Returns the drag and drop instances that are in all groups the
21695          * passed in instance belongs to.
21696          * @method getRelated
21697          * @param {DragDrop} p_oDD the obj to get related data for
21698          * @param {boolean} bTargetsOnly if true, only return targetable objs
21699          * @return {DragDrop[]} the related instances
21700          * @static
21701          */
21702         getRelated: function(p_oDD, bTargetsOnly) {
21703             var oDDs = [];
21704             for (var i in p_oDD.groups) {
21705                 for (j in this.ids[i]) {
21706                     var dd = this.ids[i][j];
21707                     if (! this.isTypeOfDD(dd)) {
21708                         continue;
21709                     }
21710                     if (!bTargetsOnly || dd.isTarget) {
21711                         oDDs[oDDs.length] = dd;
21712                     }
21713                 }
21714             }
21715
21716             return oDDs;
21717         },
21718
21719         /**
21720          * Returns true if the specified dd target is a legal target for
21721          * the specifice drag obj
21722          * @method isLegalTarget
21723          * @param {DragDrop} the drag obj
21724          * @param {DragDrop} the target
21725          * @return {boolean} true if the target is a legal target for the
21726          * dd obj
21727          * @static
21728          */
21729         isLegalTarget: function (oDD, oTargetDD) {
21730             var targets = this.getRelated(oDD, true);
21731             for (var i=0, len=targets.length;i<len;++i) {
21732                 if (targets[i].id == oTargetDD.id) {
21733                     return true;
21734                 }
21735             }
21736
21737             return false;
21738         },
21739
21740         /**
21741          * My goal is to be able to transparently determine if an object is
21742          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
21743          * returns "object", oDD.constructor.toString() always returns
21744          * "DragDrop" and not the name of the subclass.  So for now it just
21745          * evaluates a well-known variable in DragDrop.
21746          * @method isTypeOfDD
21747          * @param {Object} the object to evaluate
21748          * @return {boolean} true if typeof oDD = DragDrop
21749          * @static
21750          */
21751         isTypeOfDD: function (oDD) {
21752             return (oDD && oDD.__ygDragDrop);
21753         },
21754
21755         /**
21756          * Utility function to determine if a given element has been
21757          * registered as a drag drop handle for the given Drag Drop object.
21758          * @method isHandle
21759          * @param {String} id the element id to check
21760          * @return {boolean} true if this element is a DragDrop handle, false
21761          * otherwise
21762          * @static
21763          */
21764         isHandle: function(sDDId, sHandleId) {
21765             return ( this.handleIds[sDDId] &&
21766                             this.handleIds[sDDId][sHandleId] );
21767         },
21768
21769         /**
21770          * Returns the DragDrop instance for a given id
21771          * @method getDDById
21772          * @param {String} id the id of the DragDrop object
21773          * @return {DragDrop} the drag drop object, null if it is not found
21774          * @static
21775          */
21776         getDDById: function(id) {
21777             for (var i in this.ids) {
21778                 if (this.ids[i][id]) {
21779                     return this.ids[i][id];
21780                 }
21781             }
21782             return null;
21783         },
21784
21785         /**
21786          * Fired after a registered DragDrop object gets the mousedown event.
21787          * Sets up the events required to track the object being dragged
21788          * @method handleMouseDown
21789          * @param {Event} e the event
21790          * @param oDD the DragDrop object being dragged
21791          * @private
21792          * @static
21793          */
21794         handleMouseDown: function(e, oDD) {
21795             if(Roo.QuickTips){
21796                 Roo.QuickTips.disable();
21797             }
21798             this.currentTarget = e.getTarget();
21799
21800             this.dragCurrent = oDD;
21801
21802             var el = oDD.getEl();
21803
21804             // track start position
21805             this.startX = e.getPageX();
21806             this.startY = e.getPageY();
21807
21808             this.deltaX = this.startX - el.offsetLeft;
21809             this.deltaY = this.startY - el.offsetTop;
21810
21811             this.dragThreshMet = false;
21812
21813             this.clickTimeout = setTimeout(
21814                     function() {
21815                         var DDM = Roo.dd.DDM;
21816                         DDM.startDrag(DDM.startX, DDM.startY);
21817                     },
21818                     this.clickTimeThresh );
21819         },
21820
21821         /**
21822          * Fired when either the drag pixel threshol or the mousedown hold
21823          * time threshold has been met.
21824          * @method startDrag
21825          * @param x {int} the X position of the original mousedown
21826          * @param y {int} the Y position of the original mousedown
21827          * @static
21828          */
21829         startDrag: function(x, y) {
21830             clearTimeout(this.clickTimeout);
21831             if (this.dragCurrent) {
21832                 this.dragCurrent.b4StartDrag(x, y);
21833                 this.dragCurrent.startDrag(x, y);
21834             }
21835             this.dragThreshMet = true;
21836         },
21837
21838         /**
21839          * Internal function to handle the mouseup event.  Will be invoked
21840          * from the context of the document.
21841          * @method handleMouseUp
21842          * @param {Event} e the event
21843          * @private
21844          * @static
21845          */
21846         handleMouseUp: function(e) {
21847
21848             if(Roo.QuickTips){
21849                 Roo.QuickTips.enable();
21850             }
21851             if (! this.dragCurrent) {
21852                 return;
21853             }
21854
21855             clearTimeout(this.clickTimeout);
21856
21857             if (this.dragThreshMet) {
21858                 this.fireEvents(e, true);
21859             } else {
21860             }
21861
21862             this.stopDrag(e);
21863
21864             this.stopEvent(e);
21865         },
21866
21867         /**
21868          * Utility to stop event propagation and event default, if these
21869          * features are turned on.
21870          * @method stopEvent
21871          * @param {Event} e the event as returned by this.getEvent()
21872          * @static
21873          */
21874         stopEvent: function(e){
21875             if(this.stopPropagation) {
21876                 e.stopPropagation();
21877             }
21878
21879             if (this.preventDefault) {
21880                 e.preventDefault();
21881             }
21882         },
21883
21884         /**
21885          * Internal function to clean up event handlers after the drag
21886          * operation is complete
21887          * @method stopDrag
21888          * @param {Event} e the event
21889          * @private
21890          * @static
21891          */
21892         stopDrag: function(e) {
21893             // Fire the drag end event for the item that was dragged
21894             if (this.dragCurrent) {
21895                 if (this.dragThreshMet) {
21896                     this.dragCurrent.b4EndDrag(e);
21897                     this.dragCurrent.endDrag(e);
21898                 }
21899
21900                 this.dragCurrent.onMouseUp(e);
21901             }
21902
21903             this.dragCurrent = null;
21904             this.dragOvers = {};
21905         },
21906
21907         /**
21908          * Internal function to handle the mousemove event.  Will be invoked
21909          * from the context of the html element.
21910          *
21911          * @TODO figure out what we can do about mouse events lost when the
21912          * user drags objects beyond the window boundary.  Currently we can
21913          * detect this in internet explorer by verifying that the mouse is
21914          * down during the mousemove event.  Firefox doesn't give us the
21915          * button state on the mousemove event.
21916          * @method handleMouseMove
21917          * @param {Event} e the event
21918          * @private
21919          * @static
21920          */
21921         handleMouseMove: function(e) {
21922             if (! this.dragCurrent) {
21923                 return true;
21924             }
21925
21926             // var button = e.which || e.button;
21927
21928             // check for IE mouseup outside of page boundary
21929             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21930                 this.stopEvent(e);
21931                 return this.handleMouseUp(e);
21932             }
21933
21934             if (!this.dragThreshMet) {
21935                 var diffX = Math.abs(this.startX - e.getPageX());
21936                 var diffY = Math.abs(this.startY - e.getPageY());
21937                 if (diffX > this.clickPixelThresh ||
21938                             diffY > this.clickPixelThresh) {
21939                     this.startDrag(this.startX, this.startY);
21940                 }
21941             }
21942
21943             if (this.dragThreshMet) {
21944                 this.dragCurrent.b4Drag(e);
21945                 this.dragCurrent.onDrag(e);
21946                 if(!this.dragCurrent.moveOnly){
21947                     this.fireEvents(e, false);
21948                 }
21949             }
21950
21951             this.stopEvent(e);
21952
21953             return true;
21954         },
21955
21956         /**
21957          * Iterates over all of the DragDrop elements to find ones we are
21958          * hovering over or dropping on
21959          * @method fireEvents
21960          * @param {Event} e the event
21961          * @param {boolean} isDrop is this a drop op or a mouseover op?
21962          * @private
21963          * @static
21964          */
21965         fireEvents: function(e, isDrop) {
21966             var dc = this.dragCurrent;
21967
21968             // If the user did the mouse up outside of the window, we could
21969             // get here even though we have ended the drag.
21970             if (!dc || dc.isLocked()) {
21971                 return;
21972             }
21973
21974             var pt = e.getPoint();
21975
21976             // cache the previous dragOver array
21977             var oldOvers = [];
21978
21979             var outEvts   = [];
21980             var overEvts  = [];
21981             var dropEvts  = [];
21982             var enterEvts = [];
21983
21984             // Check to see if the object(s) we were hovering over is no longer
21985             // being hovered over so we can fire the onDragOut event
21986             for (var i in this.dragOvers) {
21987
21988                 var ddo = this.dragOvers[i];
21989
21990                 if (! this.isTypeOfDD(ddo)) {
21991                     continue;
21992                 }
21993
21994                 if (! this.isOverTarget(pt, ddo, this.mode)) {
21995                     outEvts.push( ddo );
21996                 }
21997
21998                 oldOvers[i] = true;
21999                 delete this.dragOvers[i];
22000             }
22001
22002             for (var sGroup in dc.groups) {
22003
22004                 if ("string" != typeof sGroup) {
22005                     continue;
22006                 }
22007
22008                 for (i in this.ids[sGroup]) {
22009                     var oDD = this.ids[sGroup][i];
22010                     if (! this.isTypeOfDD(oDD)) {
22011                         continue;
22012                     }
22013
22014                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
22015                         if (this.isOverTarget(pt, oDD, this.mode)) {
22016                             // look for drop interactions
22017                             if (isDrop) {
22018                                 dropEvts.push( oDD );
22019                             // look for drag enter and drag over interactions
22020                             } else {
22021
22022                                 // initial drag over: dragEnter fires
22023                                 if (!oldOvers[oDD.id]) {
22024                                     enterEvts.push( oDD );
22025                                 // subsequent drag overs: dragOver fires
22026                                 } else {
22027                                     overEvts.push( oDD );
22028                                 }
22029
22030                                 this.dragOvers[oDD.id] = oDD;
22031                             }
22032                         }
22033                     }
22034                 }
22035             }
22036
22037             if (this.mode) {
22038                 if (outEvts.length) {
22039                     dc.b4DragOut(e, outEvts);
22040                     dc.onDragOut(e, outEvts);
22041                 }
22042
22043                 if (enterEvts.length) {
22044                     dc.onDragEnter(e, enterEvts);
22045                 }
22046
22047                 if (overEvts.length) {
22048                     dc.b4DragOver(e, overEvts);
22049                     dc.onDragOver(e, overEvts);
22050                 }
22051
22052                 if (dropEvts.length) {
22053                     dc.b4DragDrop(e, dropEvts);
22054                     dc.onDragDrop(e, dropEvts);
22055                 }
22056
22057             } else {
22058                 // fire dragout events
22059                 var len = 0;
22060                 for (i=0, len=outEvts.length; i<len; ++i) {
22061                     dc.b4DragOut(e, outEvts[i].id);
22062                     dc.onDragOut(e, outEvts[i].id);
22063                 }
22064
22065                 // fire enter events
22066                 for (i=0,len=enterEvts.length; i<len; ++i) {
22067                     // dc.b4DragEnter(e, oDD.id);
22068                     dc.onDragEnter(e, enterEvts[i].id);
22069                 }
22070
22071                 // fire over events
22072                 for (i=0,len=overEvts.length; i<len; ++i) {
22073                     dc.b4DragOver(e, overEvts[i].id);
22074                     dc.onDragOver(e, overEvts[i].id);
22075                 }
22076
22077                 // fire drop events
22078                 for (i=0, len=dropEvts.length; i<len; ++i) {
22079                     dc.b4DragDrop(e, dropEvts[i].id);
22080                     dc.onDragDrop(e, dropEvts[i].id);
22081                 }
22082
22083             }
22084
22085             // notify about a drop that did not find a target
22086             if (isDrop && !dropEvts.length) {
22087                 dc.onInvalidDrop(e);
22088             }
22089
22090         },
22091
22092         /**
22093          * Helper function for getting the best match from the list of drag
22094          * and drop objects returned by the drag and drop events when we are
22095          * in INTERSECT mode.  It returns either the first object that the
22096          * cursor is over, or the object that has the greatest overlap with
22097          * the dragged element.
22098          * @method getBestMatch
22099          * @param  {DragDrop[]} dds The array of drag and drop objects
22100          * targeted
22101          * @return {DragDrop}       The best single match
22102          * @static
22103          */
22104         getBestMatch: function(dds) {
22105             var winner = null;
22106             // Return null if the input is not what we expect
22107             //if (!dds || !dds.length || dds.length == 0) {
22108                // winner = null;
22109             // If there is only one item, it wins
22110             //} else if (dds.length == 1) {
22111
22112             var len = dds.length;
22113
22114             if (len == 1) {
22115                 winner = dds[0];
22116             } else {
22117                 // Loop through the targeted items
22118                 for (var i=0; i<len; ++i) {
22119                     var dd = dds[i];
22120                     // If the cursor is over the object, it wins.  If the
22121                     // cursor is over multiple matches, the first one we come
22122                     // to wins.
22123                     if (dd.cursorIsOver) {
22124                         winner = dd;
22125                         break;
22126                     // Otherwise the object with the most overlap wins
22127                     } else {
22128                         if (!winner ||
22129                             winner.overlap.getArea() < dd.overlap.getArea()) {
22130                             winner = dd;
22131                         }
22132                     }
22133                 }
22134             }
22135
22136             return winner;
22137         },
22138
22139         /**
22140          * Refreshes the cache of the top-left and bottom-right points of the
22141          * drag and drop objects in the specified group(s).  This is in the
22142          * format that is stored in the drag and drop instance, so typical
22143          * usage is:
22144          * <code>
22145          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
22146          * </code>
22147          * Alternatively:
22148          * <code>
22149          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
22150          * </code>
22151          * @TODO this really should be an indexed array.  Alternatively this
22152          * method could accept both.
22153          * @method refreshCache
22154          * @param {Object} groups an associative array of groups to refresh
22155          * @static
22156          */
22157         refreshCache: function(groups) {
22158             for (var sGroup in groups) {
22159                 if ("string" != typeof sGroup) {
22160                     continue;
22161                 }
22162                 for (var i in this.ids[sGroup]) {
22163                     var oDD = this.ids[sGroup][i];
22164
22165                     if (this.isTypeOfDD(oDD)) {
22166                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
22167                         var loc = this.getLocation(oDD);
22168                         if (loc) {
22169                             this.locationCache[oDD.id] = loc;
22170                         } else {
22171                             delete this.locationCache[oDD.id];
22172                             // this will unregister the drag and drop object if
22173                             // the element is not in a usable state
22174                             // oDD.unreg();
22175                         }
22176                     }
22177                 }
22178             }
22179         },
22180
22181         /**
22182          * This checks to make sure an element exists and is in the DOM.  The
22183          * main purpose is to handle cases where innerHTML is used to remove
22184          * drag and drop objects from the DOM.  IE provides an 'unspecified
22185          * error' when trying to access the offsetParent of such an element
22186          * @method verifyEl
22187          * @param {HTMLElement} el the element to check
22188          * @return {boolean} true if the element looks usable
22189          * @static
22190          */
22191         verifyEl: function(el) {
22192             if (el) {
22193                 var parent;
22194                 if(Roo.isIE){
22195                     try{
22196                         parent = el.offsetParent;
22197                     }catch(e){}
22198                 }else{
22199                     parent = el.offsetParent;
22200                 }
22201                 if (parent) {
22202                     return true;
22203                 }
22204             }
22205
22206             return false;
22207         },
22208
22209         /**
22210          * Returns a Region object containing the drag and drop element's position
22211          * and size, including the padding configured for it
22212          * @method getLocation
22213          * @param {DragDrop} oDD the drag and drop object to get the
22214          *                       location for
22215          * @return {Roo.lib.Region} a Region object representing the total area
22216          *                             the element occupies, including any padding
22217          *                             the instance is configured for.
22218          * @static
22219          */
22220         getLocation: function(oDD) {
22221             if (! this.isTypeOfDD(oDD)) {
22222                 return null;
22223             }
22224
22225             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
22226
22227             try {
22228                 pos= Roo.lib.Dom.getXY(el);
22229             } catch (e) { }
22230
22231             if (!pos) {
22232                 return null;
22233             }
22234
22235             x1 = pos[0];
22236             x2 = x1 + el.offsetWidth;
22237             y1 = pos[1];
22238             y2 = y1 + el.offsetHeight;
22239
22240             t = y1 - oDD.padding[0];
22241             r = x2 + oDD.padding[1];
22242             b = y2 + oDD.padding[2];
22243             l = x1 - oDD.padding[3];
22244
22245             return new Roo.lib.Region( t, r, b, l );
22246         },
22247
22248         /**
22249          * Checks the cursor location to see if it over the target
22250          * @method isOverTarget
22251          * @param {Roo.lib.Point} pt The point to evaluate
22252          * @param {DragDrop} oTarget the DragDrop object we are inspecting
22253          * @return {boolean} true if the mouse is over the target
22254          * @private
22255          * @static
22256          */
22257         isOverTarget: function(pt, oTarget, intersect) {
22258             // use cache if available
22259             var loc = this.locationCache[oTarget.id];
22260             if (!loc || !this.useCache) {
22261                 loc = this.getLocation(oTarget);
22262                 this.locationCache[oTarget.id] = loc;
22263
22264             }
22265
22266             if (!loc) {
22267                 return false;
22268             }
22269
22270             oTarget.cursorIsOver = loc.contains( pt );
22271
22272             // DragDrop is using this as a sanity check for the initial mousedown
22273             // in this case we are done.  In POINT mode, if the drag obj has no
22274             // contraints, we are also done. Otherwise we need to evaluate the
22275             // location of the target as related to the actual location of the
22276             // dragged element.
22277             var dc = this.dragCurrent;
22278             if (!dc || !dc.getTargetCoord ||
22279                     (!intersect && !dc.constrainX && !dc.constrainY)) {
22280                 return oTarget.cursorIsOver;
22281             }
22282
22283             oTarget.overlap = null;
22284
22285             // Get the current location of the drag element, this is the
22286             // location of the mouse event less the delta that represents
22287             // where the original mousedown happened on the element.  We
22288             // need to consider constraints and ticks as well.
22289             var pos = dc.getTargetCoord(pt.x, pt.y);
22290
22291             var el = dc.getDragEl();
22292             var curRegion = new Roo.lib.Region( pos.y,
22293                                                    pos.x + el.offsetWidth,
22294                                                    pos.y + el.offsetHeight,
22295                                                    pos.x );
22296
22297             var overlap = curRegion.intersect(loc);
22298
22299             if (overlap) {
22300                 oTarget.overlap = overlap;
22301                 return (intersect) ? true : oTarget.cursorIsOver;
22302             } else {
22303                 return false;
22304             }
22305         },
22306
22307         /**
22308          * unload event handler
22309          * @method _onUnload
22310          * @private
22311          * @static
22312          */
22313         _onUnload: function(e, me) {
22314             Roo.dd.DragDropMgr.unregAll();
22315         },
22316
22317         /**
22318          * Cleans up the drag and drop events and objects.
22319          * @method unregAll
22320          * @private
22321          * @static
22322          */
22323         unregAll: function() {
22324
22325             if (this.dragCurrent) {
22326                 this.stopDrag();
22327                 this.dragCurrent = null;
22328             }
22329
22330             this._execOnAll("unreg", []);
22331
22332             for (i in this.elementCache) {
22333                 delete this.elementCache[i];
22334             }
22335
22336             this.elementCache = {};
22337             this.ids = {};
22338         },
22339
22340         /**
22341          * A cache of DOM elements
22342          * @property elementCache
22343          * @private
22344          * @static
22345          */
22346         elementCache: {},
22347
22348         /**
22349          * Get the wrapper for the DOM element specified
22350          * @method getElWrapper
22351          * @param {String} id the id of the element to get
22352          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
22353          * @private
22354          * @deprecated This wrapper isn't that useful
22355          * @static
22356          */
22357         getElWrapper: function(id) {
22358             var oWrapper = this.elementCache[id];
22359             if (!oWrapper || !oWrapper.el) {
22360                 oWrapper = this.elementCache[id] =
22361                     new this.ElementWrapper(Roo.getDom(id));
22362             }
22363             return oWrapper;
22364         },
22365
22366         /**
22367          * Returns the actual DOM element
22368          * @method getElement
22369          * @param {String} id the id of the elment to get
22370          * @return {Object} The element
22371          * @deprecated use Roo.getDom instead
22372          * @static
22373          */
22374         getElement: function(id) {
22375             return Roo.getDom(id);
22376         },
22377
22378         /**
22379          * Returns the style property for the DOM element (i.e.,
22380          * document.getElById(id).style)
22381          * @method getCss
22382          * @param {String} id the id of the elment to get
22383          * @return {Object} The style property of the element
22384          * @deprecated use Roo.getDom instead
22385          * @static
22386          */
22387         getCss: function(id) {
22388             var el = Roo.getDom(id);
22389             return (el) ? el.style : null;
22390         },
22391
22392         /**
22393          * Inner class for cached elements
22394          * @class DragDropMgr.ElementWrapper
22395          * @for DragDropMgr
22396          * @private
22397          * @deprecated
22398          */
22399         ElementWrapper: function(el) {
22400                 /**
22401                  * The element
22402                  * @property el
22403                  */
22404                 this.el = el || null;
22405                 /**
22406                  * The element id
22407                  * @property id
22408                  */
22409                 this.id = this.el && el.id;
22410                 /**
22411                  * A reference to the style property
22412                  * @property css
22413                  */
22414                 this.css = this.el && el.style;
22415             },
22416
22417         /**
22418          * Returns the X position of an html element
22419          * @method getPosX
22420          * @param el the element for which to get the position
22421          * @return {int} the X coordinate
22422          * @for DragDropMgr
22423          * @deprecated use Roo.lib.Dom.getX instead
22424          * @static
22425          */
22426         getPosX: function(el) {
22427             return Roo.lib.Dom.getX(el);
22428         },
22429
22430         /**
22431          * Returns the Y position of an html element
22432          * @method getPosY
22433          * @param el the element for which to get the position
22434          * @return {int} the Y coordinate
22435          * @deprecated use Roo.lib.Dom.getY instead
22436          * @static
22437          */
22438         getPosY: function(el) {
22439             return Roo.lib.Dom.getY(el);
22440         },
22441
22442         /**
22443          * Swap two nodes.  In IE, we use the native method, for others we
22444          * emulate the IE behavior
22445          * @method swapNode
22446          * @param n1 the first node to swap
22447          * @param n2 the other node to swap
22448          * @static
22449          */
22450         swapNode: function(n1, n2) {
22451             if (n1.swapNode) {
22452                 n1.swapNode(n2);
22453             } else {
22454                 var p = n2.parentNode;
22455                 var s = n2.nextSibling;
22456
22457                 if (s == n1) {
22458                     p.insertBefore(n1, n2);
22459                 } else if (n2 == n1.nextSibling) {
22460                     p.insertBefore(n2, n1);
22461                 } else {
22462                     n1.parentNode.replaceChild(n2, n1);
22463                     p.insertBefore(n1, s);
22464                 }
22465             }
22466         },
22467
22468         /**
22469          * Returns the current scroll position
22470          * @method getScroll
22471          * @private
22472          * @static
22473          */
22474         getScroll: function () {
22475             var t, l, dde=document.documentElement, db=document.body;
22476             if (dde && (dde.scrollTop || dde.scrollLeft)) {
22477                 t = dde.scrollTop;
22478                 l = dde.scrollLeft;
22479             } else if (db) {
22480                 t = db.scrollTop;
22481                 l = db.scrollLeft;
22482             } else {
22483
22484             }
22485             return { top: t, left: l };
22486         },
22487
22488         /**
22489          * Returns the specified element style property
22490          * @method getStyle
22491          * @param {HTMLElement} el          the element
22492          * @param {string}      styleProp   the style property
22493          * @return {string} The value of the style property
22494          * @deprecated use Roo.lib.Dom.getStyle
22495          * @static
22496          */
22497         getStyle: function(el, styleProp) {
22498             return Roo.fly(el).getStyle(styleProp);
22499         },
22500
22501         /**
22502          * Gets the scrollTop
22503          * @method getScrollTop
22504          * @return {int} the document's scrollTop
22505          * @static
22506          */
22507         getScrollTop: function () { return this.getScroll().top; },
22508
22509         /**
22510          * Gets the scrollLeft
22511          * @method getScrollLeft
22512          * @return {int} the document's scrollTop
22513          * @static
22514          */
22515         getScrollLeft: function () { return this.getScroll().left; },
22516
22517         /**
22518          * Sets the x/y position of an element to the location of the
22519          * target element.
22520          * @method moveToEl
22521          * @param {HTMLElement} moveEl      The element to move
22522          * @param {HTMLElement} targetEl    The position reference element
22523          * @static
22524          */
22525         moveToEl: function (moveEl, targetEl) {
22526             var aCoord = Roo.lib.Dom.getXY(targetEl);
22527             Roo.lib.Dom.setXY(moveEl, aCoord);
22528         },
22529
22530         /**
22531          * Numeric array sort function
22532          * @method numericSort
22533          * @static
22534          */
22535         numericSort: function(a, b) { return (a - b); },
22536
22537         /**
22538          * Internal counter
22539          * @property _timeoutCount
22540          * @private
22541          * @static
22542          */
22543         _timeoutCount: 0,
22544
22545         /**
22546          * Trying to make the load order less important.  Without this we get
22547          * an error if this file is loaded before the Event Utility.
22548          * @method _addListeners
22549          * @private
22550          * @static
22551          */
22552         _addListeners: function() {
22553             var DDM = Roo.dd.DDM;
22554             if ( Roo.lib.Event && document ) {
22555                 DDM._onLoad();
22556             } else {
22557                 if (DDM._timeoutCount > 2000) {
22558                 } else {
22559                     setTimeout(DDM._addListeners, 10);
22560                     if (document && document.body) {
22561                         DDM._timeoutCount += 1;
22562                     }
22563                 }
22564             }
22565         },
22566
22567         /**
22568          * Recursively searches the immediate parent and all child nodes for
22569          * the handle element in order to determine wheter or not it was
22570          * clicked.
22571          * @method handleWasClicked
22572          * @param node the html element to inspect
22573          * @static
22574          */
22575         handleWasClicked: function(node, id) {
22576             if (this.isHandle(id, node.id)) {
22577                 return true;
22578             } else {
22579                 // check to see if this is a text node child of the one we want
22580                 var p = node.parentNode;
22581
22582                 while (p) {
22583                     if (this.isHandle(id, p.id)) {
22584                         return true;
22585                     } else {
22586                         p = p.parentNode;
22587                     }
22588                 }
22589             }
22590
22591             return false;
22592         }
22593
22594     };
22595
22596 }();
22597
22598 // shorter alias, save a few bytes
22599 Roo.dd.DDM = Roo.dd.DragDropMgr;
22600 Roo.dd.DDM._addListeners();
22601
22602 }/*
22603  * Based on:
22604  * Ext JS Library 1.1.1
22605  * Copyright(c) 2006-2007, Ext JS, LLC.
22606  *
22607  * Originally Released Under LGPL - original licence link has changed is not relivant.
22608  *
22609  * Fork - LGPL
22610  * <script type="text/javascript">
22611  */
22612
22613 /**
22614  * @class Roo.dd.DD
22615  * A DragDrop implementation where the linked element follows the
22616  * mouse cursor during a drag.
22617  * @extends Roo.dd.DragDrop
22618  * @constructor
22619  * @param {String} id the id of the linked element
22620  * @param {String} sGroup the group of related DragDrop items
22621  * @param {object} config an object containing configurable attributes
22622  *                Valid properties for DD:
22623  *                    scroll
22624  */
22625 Roo.dd.DD = function(id, sGroup, config) {
22626     if (id) {
22627         this.init(id, sGroup, config);
22628     }
22629 };
22630
22631 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22632
22633     /**
22634      * When set to true, the utility automatically tries to scroll the browser
22635      * window wehn a drag and drop element is dragged near the viewport boundary.
22636      * Defaults to true.
22637      * @property scroll
22638      * @type boolean
22639      */
22640     scroll: true,
22641
22642     /**
22643      * Sets the pointer offset to the distance between the linked element's top
22644      * left corner and the location the element was clicked
22645      * @method autoOffset
22646      * @param {int} iPageX the X coordinate of the click
22647      * @param {int} iPageY the Y coordinate of the click
22648      */
22649     autoOffset: function(iPageX, iPageY) {
22650         var x = iPageX - this.startPageX;
22651         var y = iPageY - this.startPageY;
22652         this.setDelta(x, y);
22653     },
22654
22655     /**
22656      * Sets the pointer offset.  You can call this directly to force the
22657      * offset to be in a particular location (e.g., pass in 0,0 to set it
22658      * to the center of the object)
22659      * @method setDelta
22660      * @param {int} iDeltaX the distance from the left
22661      * @param {int} iDeltaY the distance from the top
22662      */
22663     setDelta: function(iDeltaX, iDeltaY) {
22664         this.deltaX = iDeltaX;
22665         this.deltaY = iDeltaY;
22666     },
22667
22668     /**
22669      * Sets the drag element to the location of the mousedown or click event,
22670      * maintaining the cursor location relative to the location on the element
22671      * that was clicked.  Override this if you want to place the element in a
22672      * location other than where the cursor is.
22673      * @method setDragElPos
22674      * @param {int} iPageX the X coordinate of the mousedown or drag event
22675      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22676      */
22677     setDragElPos: function(iPageX, iPageY) {
22678         // the first time we do this, we are going to check to make sure
22679         // the element has css positioning
22680
22681         var el = this.getDragEl();
22682         this.alignElWithMouse(el, iPageX, iPageY);
22683     },
22684
22685     /**
22686      * Sets the element to the location of the mousedown or click event,
22687      * maintaining the cursor location relative to the location on the element
22688      * that was clicked.  Override this if you want to place the element in a
22689      * location other than where the cursor is.
22690      * @method alignElWithMouse
22691      * @param {HTMLElement} el the element to move
22692      * @param {int} iPageX the X coordinate of the mousedown or drag event
22693      * @param {int} iPageY the Y coordinate of the mousedown or drag event
22694      */
22695     alignElWithMouse: function(el, iPageX, iPageY) {
22696         var oCoord = this.getTargetCoord(iPageX, iPageY);
22697         var fly = el.dom ? el : Roo.fly(el);
22698         if (!this.deltaSetXY) {
22699             var aCoord = [oCoord.x, oCoord.y];
22700             fly.setXY(aCoord);
22701             var newLeft = fly.getLeft(true);
22702             var newTop  = fly.getTop(true);
22703             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22704         } else {
22705             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22706         }
22707
22708         this.cachePosition(oCoord.x, oCoord.y);
22709         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22710         return oCoord;
22711     },
22712
22713     /**
22714      * Saves the most recent position so that we can reset the constraints and
22715      * tick marks on-demand.  We need to know this so that we can calculate the
22716      * number of pixels the element is offset from its original position.
22717      * @method cachePosition
22718      * @param iPageX the current x position (optional, this just makes it so we
22719      * don't have to look it up again)
22720      * @param iPageY the current y position (optional, this just makes it so we
22721      * don't have to look it up again)
22722      */
22723     cachePosition: function(iPageX, iPageY) {
22724         if (iPageX) {
22725             this.lastPageX = iPageX;
22726             this.lastPageY = iPageY;
22727         } else {
22728             var aCoord = Roo.lib.Dom.getXY(this.getEl());
22729             this.lastPageX = aCoord[0];
22730             this.lastPageY = aCoord[1];
22731         }
22732     },
22733
22734     /**
22735      * Auto-scroll the window if the dragged object has been moved beyond the
22736      * visible window boundary.
22737      * @method autoScroll
22738      * @param {int} x the drag element's x position
22739      * @param {int} y the drag element's y position
22740      * @param {int} h the height of the drag element
22741      * @param {int} w the width of the drag element
22742      * @private
22743      */
22744     autoScroll: function(x, y, h, w) {
22745
22746         if (this.scroll) {
22747             // The client height
22748             var clientH = Roo.lib.Dom.getViewWidth();
22749
22750             // The client width
22751             var clientW = Roo.lib.Dom.getViewHeight();
22752
22753             // The amt scrolled down
22754             var st = this.DDM.getScrollTop();
22755
22756             // The amt scrolled right
22757             var sl = this.DDM.getScrollLeft();
22758
22759             // Location of the bottom of the element
22760             var bot = h + y;
22761
22762             // Location of the right of the element
22763             var right = w + x;
22764
22765             // The distance from the cursor to the bottom of the visible area,
22766             // adjusted so that we don't scroll if the cursor is beyond the
22767             // element drag constraints
22768             var toBot = (clientH + st - y - this.deltaY);
22769
22770             // The distance from the cursor to the right of the visible area
22771             var toRight = (clientW + sl - x - this.deltaX);
22772
22773
22774             // How close to the edge the cursor must be before we scroll
22775             // var thresh = (document.all) ? 100 : 40;
22776             var thresh = 40;
22777
22778             // How many pixels to scroll per autoscroll op.  This helps to reduce
22779             // clunky scrolling. IE is more sensitive about this ... it needs this
22780             // value to be higher.
22781             var scrAmt = (document.all) ? 80 : 30;
22782
22783             // Scroll down if we are near the bottom of the visible page and the
22784             // obj extends below the crease
22785             if ( bot > clientH && toBot < thresh ) {
22786                 window.scrollTo(sl, st + scrAmt);
22787             }
22788
22789             // Scroll up if the window is scrolled down and the top of the object
22790             // goes above the top border
22791             if ( y < st && st > 0 && y - st < thresh ) {
22792                 window.scrollTo(sl, st - scrAmt);
22793             }
22794
22795             // Scroll right if the obj is beyond the right border and the cursor is
22796             // near the border.
22797             if ( right > clientW && toRight < thresh ) {
22798                 window.scrollTo(sl + scrAmt, st);
22799             }
22800
22801             // Scroll left if the window has been scrolled to the right and the obj
22802             // extends past the left border
22803             if ( x < sl && sl > 0 && x - sl < thresh ) {
22804                 window.scrollTo(sl - scrAmt, st);
22805             }
22806         }
22807     },
22808
22809     /**
22810      * Finds the location the element should be placed if we want to move
22811      * it to where the mouse location less the click offset would place us.
22812      * @method getTargetCoord
22813      * @param {int} iPageX the X coordinate of the click
22814      * @param {int} iPageY the Y coordinate of the click
22815      * @return an object that contains the coordinates (Object.x and Object.y)
22816      * @private
22817      */
22818     getTargetCoord: function(iPageX, iPageY) {
22819
22820
22821         var x = iPageX - this.deltaX;
22822         var y = iPageY - this.deltaY;
22823
22824         if (this.constrainX) {
22825             if (x < this.minX) { x = this.minX; }
22826             if (x > this.maxX) { x = this.maxX; }
22827         }
22828
22829         if (this.constrainY) {
22830             if (y < this.minY) { y = this.minY; }
22831             if (y > this.maxY) { y = this.maxY; }
22832         }
22833
22834         x = this.getTick(x, this.xTicks);
22835         y = this.getTick(y, this.yTicks);
22836
22837
22838         return {x:x, y:y};
22839     },
22840
22841     /*
22842      * Sets up config options specific to this class. Overrides
22843      * Roo.dd.DragDrop, but all versions of this method through the
22844      * inheritance chain are called
22845      */
22846     applyConfig: function() {
22847         Roo.dd.DD.superclass.applyConfig.call(this);
22848         this.scroll = (this.config.scroll !== false);
22849     },
22850
22851     /*
22852      * Event that fires prior to the onMouseDown event.  Overrides
22853      * Roo.dd.DragDrop.
22854      */
22855     b4MouseDown: function(e) {
22856         // this.resetConstraints();
22857         this.autoOffset(e.getPageX(),
22858                             e.getPageY());
22859     },
22860
22861     /*
22862      * Event that fires prior to the onDrag event.  Overrides
22863      * Roo.dd.DragDrop.
22864      */
22865     b4Drag: function(e) {
22866         this.setDragElPos(e.getPageX(),
22867                             e.getPageY());
22868     },
22869
22870     toString: function() {
22871         return ("DD " + this.id);
22872     }
22873
22874     //////////////////////////////////////////////////////////////////////////
22875     // Debugging ygDragDrop events that can be overridden
22876     //////////////////////////////////////////////////////////////////////////
22877     /*
22878     startDrag: function(x, y) {
22879     },
22880
22881     onDrag: function(e) {
22882     },
22883
22884     onDragEnter: function(e, id) {
22885     },
22886
22887     onDragOver: function(e, id) {
22888     },
22889
22890     onDragOut: function(e, id) {
22891     },
22892
22893     onDragDrop: function(e, id) {
22894     },
22895
22896     endDrag: function(e) {
22897     }
22898
22899     */
22900
22901 });/*
22902  * Based on:
22903  * Ext JS Library 1.1.1
22904  * Copyright(c) 2006-2007, Ext JS, LLC.
22905  *
22906  * Originally Released Under LGPL - original licence link has changed is not relivant.
22907  *
22908  * Fork - LGPL
22909  * <script type="text/javascript">
22910  */
22911
22912 /**
22913  * @class Roo.dd.DDProxy
22914  * A DragDrop implementation that inserts an empty, bordered div into
22915  * the document that follows the cursor during drag operations.  At the time of
22916  * the click, the frame div is resized to the dimensions of the linked html
22917  * element, and moved to the exact location of the linked element.
22918  *
22919  * References to the "frame" element refer to the single proxy element that
22920  * was created to be dragged in place of all DDProxy elements on the
22921  * page.
22922  *
22923  * @extends Roo.dd.DD
22924  * @constructor
22925  * @param {String} id the id of the linked html element
22926  * @param {String} sGroup the group of related DragDrop objects
22927  * @param {object} config an object containing configurable attributes
22928  *                Valid properties for DDProxy in addition to those in DragDrop:
22929  *                   resizeFrame, centerFrame, dragElId
22930  */
22931 Roo.dd.DDProxy = function(id, sGroup, config) {
22932     if (id) {
22933         this.init(id, sGroup, config);
22934         this.initFrame();
22935     }
22936 };
22937
22938 /**
22939  * The default drag frame div id
22940  * @property Roo.dd.DDProxy.dragElId
22941  * @type String
22942  * @static
22943  */
22944 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22945
22946 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22947
22948     /**
22949      * By default we resize the drag frame to be the same size as the element
22950      * we want to drag (this is to get the frame effect).  We can turn it off
22951      * if we want a different behavior.
22952      * @property resizeFrame
22953      * @type boolean
22954      */
22955     resizeFrame: true,
22956
22957     /**
22958      * By default the frame is positioned exactly where the drag element is, so
22959      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
22960      * you do not have constraints on the obj is to have the drag frame centered
22961      * around the cursor.  Set centerFrame to true for this effect.
22962      * @property centerFrame
22963      * @type boolean
22964      */
22965     centerFrame: false,
22966
22967     /**
22968      * Creates the proxy element if it does not yet exist
22969      * @method createFrame
22970      */
22971     createFrame: function() {
22972         var self = this;
22973         var body = document.body;
22974
22975         if (!body || !body.firstChild) {
22976             setTimeout( function() { self.createFrame(); }, 50 );
22977             return;
22978         }
22979
22980         var div = this.getDragEl();
22981
22982         if (!div) {
22983             div    = document.createElement("div");
22984             div.id = this.dragElId;
22985             var s  = div.style;
22986
22987             s.position   = "absolute";
22988             s.visibility = "hidden";
22989             s.cursor     = "move";
22990             s.border     = "2px solid #aaa";
22991             s.zIndex     = 999;
22992
22993             // appendChild can blow up IE if invoked prior to the window load event
22994             // while rendering a table.  It is possible there are other scenarios
22995             // that would cause this to happen as well.
22996             body.insertBefore(div, body.firstChild);
22997         }
22998     },
22999
23000     /**
23001      * Initialization for the drag frame element.  Must be called in the
23002      * constructor of all subclasses
23003      * @method initFrame
23004      */
23005     initFrame: function() {
23006         this.createFrame();
23007     },
23008
23009     applyConfig: function() {
23010         Roo.dd.DDProxy.superclass.applyConfig.call(this);
23011
23012         this.resizeFrame = (this.config.resizeFrame !== false);
23013         this.centerFrame = (this.config.centerFrame);
23014         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
23015     },
23016
23017     /**
23018      * Resizes the drag frame to the dimensions of the clicked object, positions
23019      * it over the object, and finally displays it
23020      * @method showFrame
23021      * @param {int} iPageX X click position
23022      * @param {int} iPageY Y click position
23023      * @private
23024      */
23025     showFrame: function(iPageX, iPageY) {
23026         var el = this.getEl();
23027         var dragEl = this.getDragEl();
23028         var s = dragEl.style;
23029
23030         this._resizeProxy();
23031
23032         if (this.centerFrame) {
23033             this.setDelta( Math.round(parseInt(s.width,  10)/2),
23034                            Math.round(parseInt(s.height, 10)/2) );
23035         }
23036
23037         this.setDragElPos(iPageX, iPageY);
23038
23039         Roo.fly(dragEl).show();
23040     },
23041
23042     /**
23043      * The proxy is automatically resized to the dimensions of the linked
23044      * element when a drag is initiated, unless resizeFrame is set to false
23045      * @method _resizeProxy
23046      * @private
23047      */
23048     _resizeProxy: function() {
23049         if (this.resizeFrame) {
23050             var el = this.getEl();
23051             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
23052         }
23053     },
23054
23055     // overrides Roo.dd.DragDrop
23056     b4MouseDown: function(e) {
23057         var x = e.getPageX();
23058         var y = e.getPageY();
23059         this.autoOffset(x, y);
23060         this.setDragElPos(x, y);
23061     },
23062
23063     // overrides Roo.dd.DragDrop
23064     b4StartDrag: function(x, y) {
23065         // show the drag frame
23066         this.showFrame(x, y);
23067     },
23068
23069     // overrides Roo.dd.DragDrop
23070     b4EndDrag: function(e) {
23071         Roo.fly(this.getDragEl()).hide();
23072     },
23073
23074     // overrides Roo.dd.DragDrop
23075     // By default we try to move the element to the last location of the frame.
23076     // This is so that the default behavior mirrors that of Roo.dd.DD.
23077     endDrag: function(e) {
23078
23079         var lel = this.getEl();
23080         var del = this.getDragEl();
23081
23082         // Show the drag frame briefly so we can get its position
23083         del.style.visibility = "";
23084
23085         this.beforeMove();
23086         // Hide the linked element before the move to get around a Safari
23087         // rendering bug.
23088         lel.style.visibility = "hidden";
23089         Roo.dd.DDM.moveToEl(lel, del);
23090         del.style.visibility = "hidden";
23091         lel.style.visibility = "";
23092
23093         this.afterDrag();
23094     },
23095
23096     beforeMove : function(){
23097
23098     },
23099
23100     afterDrag : function(){
23101
23102     },
23103
23104     toString: function() {
23105         return ("DDProxy " + this.id);
23106     }
23107
23108 });
23109 /*
23110  * Based on:
23111  * Ext JS Library 1.1.1
23112  * Copyright(c) 2006-2007, Ext JS, LLC.
23113  *
23114  * Originally Released Under LGPL - original licence link has changed is not relivant.
23115  *
23116  * Fork - LGPL
23117  * <script type="text/javascript">
23118  */
23119
23120  /**
23121  * @class Roo.dd.DDTarget
23122  * A DragDrop implementation that does not move, but can be a drop
23123  * target.  You would get the same result by simply omitting implementation
23124  * for the event callbacks, but this way we reduce the processing cost of the
23125  * event listener and the callbacks.
23126  * @extends Roo.dd.DragDrop
23127  * @constructor
23128  * @param {String} id the id of the element that is a drop target
23129  * @param {String} sGroup the group of related DragDrop objects
23130  * @param {object} config an object containing configurable attributes
23131  *                 Valid properties for DDTarget in addition to those in
23132  *                 DragDrop:
23133  *                    none
23134  */
23135 Roo.dd.DDTarget = function(id, sGroup, config) {
23136     if (id) {
23137         this.initTarget(id, sGroup, config);
23138     }
23139     if (config && (config.listeners || config.events)) { 
23140         Roo.dd.DragDrop.superclass.constructor.call(this,  { 
23141             listeners : config.listeners || {}, 
23142             events : config.events || {} 
23143         });    
23144     }
23145 };
23146
23147 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
23148 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
23149     toString: function() {
23150         return ("DDTarget " + this.id);
23151     }
23152 });
23153 /*
23154  * Based on:
23155  * Ext JS Library 1.1.1
23156  * Copyright(c) 2006-2007, Ext JS, LLC.
23157  *
23158  * Originally Released Under LGPL - original licence link has changed is not relivant.
23159  *
23160  * Fork - LGPL
23161  * <script type="text/javascript">
23162  */
23163  
23164
23165 /**
23166  * @class Roo.dd.ScrollManager
23167  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
23168  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
23169  * @static
23170  */
23171 Roo.dd.ScrollManager = function(){
23172     var ddm = Roo.dd.DragDropMgr;
23173     var els = {};
23174     var dragEl = null;
23175     var proc = {};
23176     
23177     
23178     
23179     var onStop = function(e){
23180         dragEl = null;
23181         clearProc();
23182     };
23183     
23184     var triggerRefresh = function(){
23185         if(ddm.dragCurrent){
23186              ddm.refreshCache(ddm.dragCurrent.groups);
23187         }
23188     };
23189     
23190     var doScroll = function(){
23191         if(ddm.dragCurrent){
23192             var dds = Roo.dd.ScrollManager;
23193             if(!dds.animate){
23194                 if(proc.el.scroll(proc.dir, dds.increment)){
23195                     triggerRefresh();
23196                 }
23197             }else{
23198                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
23199             }
23200         }
23201     };
23202     
23203     var clearProc = function(){
23204         if(proc.id){
23205             clearInterval(proc.id);
23206         }
23207         proc.id = 0;
23208         proc.el = null;
23209         proc.dir = "";
23210     };
23211     
23212     var startProc = function(el, dir){
23213          Roo.log('scroll startproc');
23214         clearProc();
23215         proc.el = el;
23216         proc.dir = dir;
23217         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
23218     };
23219     
23220     var onFire = function(e, isDrop){
23221        
23222         if(isDrop || !ddm.dragCurrent){ return; }
23223         var dds = Roo.dd.ScrollManager;
23224         if(!dragEl || dragEl != ddm.dragCurrent){
23225             dragEl = ddm.dragCurrent;
23226             // refresh regions on drag start
23227             dds.refreshCache();
23228         }
23229         
23230         var xy = Roo.lib.Event.getXY(e);
23231         var pt = new Roo.lib.Point(xy[0], xy[1]);
23232         for(var id in els){
23233             var el = els[id], r = el._region;
23234             if(r && r.contains(pt) && el.isScrollable()){
23235                 if(r.bottom - pt.y <= dds.thresh){
23236                     if(proc.el != el){
23237                         startProc(el, "down");
23238                     }
23239                     return;
23240                 }else if(r.right - pt.x <= dds.thresh){
23241                     if(proc.el != el){
23242                         startProc(el, "left");
23243                     }
23244                     return;
23245                 }else if(pt.y - r.top <= dds.thresh){
23246                     if(proc.el != el){
23247                         startProc(el, "up");
23248                     }
23249                     return;
23250                 }else if(pt.x - r.left <= dds.thresh){
23251                     if(proc.el != el){
23252                         startProc(el, "right");
23253                     }
23254                     return;
23255                 }
23256             }
23257         }
23258         clearProc();
23259     };
23260     
23261     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
23262     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
23263     
23264     return {
23265         /**
23266          * Registers new overflow element(s) to auto scroll
23267          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
23268          */
23269         register : function(el){
23270             if(el instanceof Array){
23271                 for(var i = 0, len = el.length; i < len; i++) {
23272                         this.register(el[i]);
23273                 }
23274             }else{
23275                 el = Roo.get(el);
23276                 els[el.id] = el;
23277             }
23278             Roo.dd.ScrollManager.els = els;
23279         },
23280         
23281         /**
23282          * Unregisters overflow element(s) so they are no longer scrolled
23283          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
23284          */
23285         unregister : function(el){
23286             if(el instanceof Array){
23287                 for(var i = 0, len = el.length; i < len; i++) {
23288                         this.unregister(el[i]);
23289                 }
23290             }else{
23291                 el = Roo.get(el);
23292                 delete els[el.id];
23293             }
23294         },
23295         
23296         /**
23297          * The number of pixels from the edge of a container the pointer needs to be to 
23298          * trigger scrolling (defaults to 25)
23299          * @type Number
23300          */
23301         thresh : 25,
23302         
23303         /**
23304          * The number of pixels to scroll in each scroll increment (defaults to 50)
23305          * @type Number
23306          */
23307         increment : 100,
23308         
23309         /**
23310          * The frequency of scrolls in milliseconds (defaults to 500)
23311          * @type Number
23312          */
23313         frequency : 500,
23314         
23315         /**
23316          * True to animate the scroll (defaults to true)
23317          * @type Boolean
23318          */
23319         animate: true,
23320         
23321         /**
23322          * The animation duration in seconds - 
23323          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
23324          * @type Number
23325          */
23326         animDuration: .4,
23327         
23328         /**
23329          * Manually trigger a cache refresh.
23330          */
23331         refreshCache : function(){
23332             for(var id in els){
23333                 if(typeof els[id] == 'object'){ // for people extending the object prototype
23334                     els[id]._region = els[id].getRegion();
23335                 }
23336             }
23337         }
23338     };
23339 }();/*
23340  * Based on:
23341  * Ext JS Library 1.1.1
23342  * Copyright(c) 2006-2007, Ext JS, LLC.
23343  *
23344  * Originally Released Under LGPL - original licence link has changed is not relivant.
23345  *
23346  * Fork - LGPL
23347  * <script type="text/javascript">
23348  */
23349  
23350
23351 /**
23352  * @class Roo.dd.Registry
23353  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
23354  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
23355  * @static
23356  */
23357 Roo.dd.Registry = function(){
23358     var elements = {}; 
23359     var handles = {}; 
23360     var autoIdSeed = 0;
23361
23362     var getId = function(el, autogen){
23363         if(typeof el == "string"){
23364             return el;
23365         }
23366         var id = el.id;
23367         if(!id && autogen !== false){
23368             id = "roodd-" + (++autoIdSeed);
23369             el.id = id;
23370         }
23371         return id;
23372     };
23373     
23374     return {
23375     /**
23376      * Register a drag drop element
23377      * @param {String|HTMLElement} element The id or DOM node to register
23378      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
23379      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
23380      * knows how to interpret, plus there are some specific properties known to the Registry that should be
23381      * populated in the data object (if applicable):
23382      * <pre>
23383 Value      Description<br />
23384 ---------  ------------------------------------------<br />
23385 handles    Array of DOM nodes that trigger dragging<br />
23386            for the element being registered<br />
23387 isHandle   True if the element passed in triggers<br />
23388            dragging itself, else false
23389 </pre>
23390      */
23391         register : function(el, data){
23392             data = data || {};
23393             if(typeof el == "string"){
23394                 el = document.getElementById(el);
23395             }
23396             data.ddel = el;
23397             elements[getId(el)] = data;
23398             if(data.isHandle !== false){
23399                 handles[data.ddel.id] = data;
23400             }
23401             if(data.handles){
23402                 var hs = data.handles;
23403                 for(var i = 0, len = hs.length; i < len; i++){
23404                         handles[getId(hs[i])] = data;
23405                 }
23406             }
23407         },
23408
23409     /**
23410      * Unregister a drag drop element
23411      * @param {String|HTMLElement}  element The id or DOM node to unregister
23412      */
23413         unregister : function(el){
23414             var id = getId(el, false);
23415             var data = elements[id];
23416             if(data){
23417                 delete elements[id];
23418                 if(data.handles){
23419                     var hs = data.handles;
23420                     for(var i = 0, len = hs.length; i < len; i++){
23421                         delete handles[getId(hs[i], false)];
23422                     }
23423                 }
23424             }
23425         },
23426
23427     /**
23428      * Returns the handle registered for a DOM Node by id
23429      * @param {String|HTMLElement} id The DOM node or id to look up
23430      * @return {Object} handle The custom handle data
23431      */
23432         getHandle : function(id){
23433             if(typeof id != "string"){ // must be element?
23434                 id = id.id;
23435             }
23436             return handles[id];
23437         },
23438
23439     /**
23440      * Returns the handle that is registered for the DOM node that is the target of the event
23441      * @param {Event} e The event
23442      * @return {Object} handle The custom handle data
23443      */
23444         getHandleFromEvent : function(e){
23445             var t = Roo.lib.Event.getTarget(e);
23446             return t ? handles[t.id] : null;
23447         },
23448
23449     /**
23450      * Returns a custom data object that is registered for a DOM node by id
23451      * @param {String|HTMLElement} id The DOM node or id to look up
23452      * @return {Object} data The custom data
23453      */
23454         getTarget : function(id){
23455             if(typeof id != "string"){ // must be element?
23456                 id = id.id;
23457             }
23458             return elements[id];
23459         },
23460
23461     /**
23462      * Returns a custom data object that is registered for the DOM node that is the target of the event
23463      * @param {Event} e The event
23464      * @return {Object} data The custom data
23465      */
23466         getTargetFromEvent : function(e){
23467             var t = Roo.lib.Event.getTarget(e);
23468             return t ? elements[t.id] || handles[t.id] : null;
23469         }
23470     };
23471 }();/*
23472  * Based on:
23473  * Ext JS Library 1.1.1
23474  * Copyright(c) 2006-2007, Ext JS, LLC.
23475  *
23476  * Originally Released Under LGPL - original licence link has changed is not relivant.
23477  *
23478  * Fork - LGPL
23479  * <script type="text/javascript">
23480  */
23481  
23482
23483 /**
23484  * @class Roo.dd.StatusProxy
23485  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
23486  * default drag proxy used by all Roo.dd components.
23487  * @constructor
23488  * @param {Object} config
23489  */
23490 Roo.dd.StatusProxy = function(config){
23491     Roo.apply(this, config);
23492     this.id = this.id || Roo.id();
23493     this.el = new Roo.Layer({
23494         dh: {
23495             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
23496                 {tag: "div", cls: "x-dd-drop-icon"},
23497                 {tag: "div", cls: "x-dd-drag-ghost"}
23498             ]
23499         }, 
23500         shadow: !config || config.shadow !== false
23501     });
23502     this.ghost = Roo.get(this.el.dom.childNodes[1]);
23503     this.dropStatus = this.dropNotAllowed;
23504 };
23505
23506 Roo.dd.StatusProxy.prototype = {
23507     /**
23508      * @cfg {String} dropAllowed
23509      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
23510      */
23511     dropAllowed : "x-dd-drop-ok",
23512     /**
23513      * @cfg {String} dropNotAllowed
23514      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
23515      */
23516     dropNotAllowed : "x-dd-drop-nodrop",
23517
23518     /**
23519      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
23520      * over the current target element.
23521      * @param {String} cssClass The css class for the new drop status indicator image
23522      */
23523     setStatus : function(cssClass){
23524         cssClass = cssClass || this.dropNotAllowed;
23525         if(this.dropStatus != cssClass){
23526             this.el.replaceClass(this.dropStatus, cssClass);
23527             this.dropStatus = cssClass;
23528         }
23529     },
23530
23531     /**
23532      * Resets the status indicator to the default dropNotAllowed value
23533      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23534      */
23535     reset : function(clearGhost){
23536         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23537         this.dropStatus = this.dropNotAllowed;
23538         if(clearGhost){
23539             this.ghost.update("");
23540         }
23541     },
23542
23543     /**
23544      * Updates the contents of the ghost element
23545      * @param {String} html The html that will replace the current innerHTML of the ghost element
23546      */
23547     update : function(html){
23548         if(typeof html == "string"){
23549             this.ghost.update(html);
23550         }else{
23551             this.ghost.update("");
23552             html.style.margin = "0";
23553             this.ghost.dom.appendChild(html);
23554         }
23555         // ensure float = none set?? cant remember why though.
23556         var el = this.ghost.dom.firstChild;
23557                 if(el){
23558                         Roo.fly(el).setStyle('float', 'none');
23559                 }
23560     },
23561     
23562     /**
23563      * Returns the underlying proxy {@link Roo.Layer}
23564      * @return {Roo.Layer} el
23565     */
23566     getEl : function(){
23567         return this.el;
23568     },
23569
23570     /**
23571      * Returns the ghost element
23572      * @return {Roo.Element} el
23573      */
23574     getGhost : function(){
23575         return this.ghost;
23576     },
23577
23578     /**
23579      * Hides the proxy
23580      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23581      */
23582     hide : function(clear){
23583         this.el.hide();
23584         if(clear){
23585             this.reset(true);
23586         }
23587     },
23588
23589     /**
23590      * Stops the repair animation if it's currently running
23591      */
23592     stop : function(){
23593         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23594             this.anim.stop();
23595         }
23596     },
23597
23598     /**
23599      * Displays this proxy
23600      */
23601     show : function(){
23602         this.el.show();
23603     },
23604
23605     /**
23606      * Force the Layer to sync its shadow and shim positions to the element
23607      */
23608     sync : function(){
23609         this.el.sync();
23610     },
23611
23612     /**
23613      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
23614      * invalid drop operation by the item being dragged.
23615      * @param {Array} xy The XY position of the element ([x, y])
23616      * @param {Function} callback The function to call after the repair is complete
23617      * @param {Object} scope The scope in which to execute the callback
23618      */
23619     repair : function(xy, callback, scope){
23620         this.callback = callback;
23621         this.scope = scope;
23622         if(xy && this.animRepair !== false){
23623             this.el.addClass("x-dd-drag-repair");
23624             this.el.hideUnders(true);
23625             this.anim = this.el.shift({
23626                 duration: this.repairDuration || .5,
23627                 easing: 'easeOut',
23628                 xy: xy,
23629                 stopFx: true,
23630                 callback: this.afterRepair,
23631                 scope: this
23632             });
23633         }else{
23634             this.afterRepair();
23635         }
23636     },
23637
23638     // private
23639     afterRepair : function(){
23640         this.hide(true);
23641         if(typeof this.callback == "function"){
23642             this.callback.call(this.scope || this);
23643         }
23644         this.callback = null;
23645         this.scope = null;
23646     }
23647 };/*
23648  * Based on:
23649  * Ext JS Library 1.1.1
23650  * Copyright(c) 2006-2007, Ext JS, LLC.
23651  *
23652  * Originally Released Under LGPL - original licence link has changed is not relivant.
23653  *
23654  * Fork - LGPL
23655  * <script type="text/javascript">
23656  */
23657
23658 /**
23659  * @class Roo.dd.DragSource
23660  * @extends Roo.dd.DDProxy
23661  * A simple class that provides the basic implementation needed to make any element draggable.
23662  * @constructor
23663  * @param {String/HTMLElement/Element} el The container element
23664  * @param {Object} config
23665  */
23666 Roo.dd.DragSource = function(el, config){
23667     this.el = Roo.get(el);
23668     this.dragData = {};
23669     
23670     Roo.apply(this, config);
23671     
23672     if(!this.proxy){
23673         this.proxy = new Roo.dd.StatusProxy();
23674     }
23675
23676     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23677           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23678     
23679     this.dragging = false;
23680 };
23681
23682 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23683     /**
23684      * @cfg {String} dropAllowed
23685      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23686      */
23687     dropAllowed : "x-dd-drop-ok",
23688     /**
23689      * @cfg {String} dropNotAllowed
23690      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23691      */
23692     dropNotAllowed : "x-dd-drop-nodrop",
23693
23694     /**
23695      * Returns the data object associated with this drag source
23696      * @return {Object} data An object containing arbitrary data
23697      */
23698     getDragData : function(e){
23699         return this.dragData;
23700     },
23701
23702     // private
23703     onDragEnter : function(e, id){
23704         var target = Roo.dd.DragDropMgr.getDDById(id);
23705         this.cachedTarget = target;
23706         if(this.beforeDragEnter(target, e, id) !== false){
23707             if(target.isNotifyTarget){
23708                 var status = target.notifyEnter(this, e, this.dragData);
23709                 this.proxy.setStatus(status);
23710             }else{
23711                 this.proxy.setStatus(this.dropAllowed);
23712             }
23713             
23714             if(this.afterDragEnter){
23715                 /**
23716                  * An empty function by default, but provided so that you can perform a custom action
23717                  * when the dragged item enters the drop target by providing an implementation.
23718                  * @param {Roo.dd.DragDrop} target The drop target
23719                  * @param {Event} e The event object
23720                  * @param {String} id The id of the dragged element
23721                  * @method afterDragEnter
23722                  */
23723                 this.afterDragEnter(target, e, id);
23724             }
23725         }
23726     },
23727
23728     /**
23729      * An empty function by default, but provided so that you can perform a custom action
23730      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23731      * @param {Roo.dd.DragDrop} target The drop target
23732      * @param {Event} e The event object
23733      * @param {String} id The id of the dragged element
23734      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23735      */
23736     beforeDragEnter : function(target, e, id){
23737         return true;
23738     },
23739
23740     // private
23741     alignElWithMouse: function() {
23742         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23743         this.proxy.sync();
23744     },
23745
23746     // private
23747     onDragOver : function(e, id){
23748         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23749         if(this.beforeDragOver(target, e, id) !== false){
23750             if(target.isNotifyTarget){
23751                 var status = target.notifyOver(this, e, this.dragData);
23752                 this.proxy.setStatus(status);
23753             }
23754
23755             if(this.afterDragOver){
23756                 /**
23757                  * An empty function by default, but provided so that you can perform a custom action
23758                  * while the dragged item is over the drop target by providing an implementation.
23759                  * @param {Roo.dd.DragDrop} target The drop target
23760                  * @param {Event} e The event object
23761                  * @param {String} id The id of the dragged element
23762                  * @method afterDragOver
23763                  */
23764                 this.afterDragOver(target, e, id);
23765             }
23766         }
23767     },
23768
23769     /**
23770      * An empty function by default, but provided so that you can perform a custom action
23771      * while the dragged item is over the drop target and optionally cancel the onDragOver.
23772      * @param {Roo.dd.DragDrop} target The drop target
23773      * @param {Event} e The event object
23774      * @param {String} id The id of the dragged element
23775      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23776      */
23777     beforeDragOver : function(target, e, id){
23778         return true;
23779     },
23780
23781     // private
23782     onDragOut : function(e, id){
23783         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23784         if(this.beforeDragOut(target, e, id) !== false){
23785             if(target.isNotifyTarget){
23786                 target.notifyOut(this, e, this.dragData);
23787             }
23788             this.proxy.reset();
23789             if(this.afterDragOut){
23790                 /**
23791                  * An empty function by default, but provided so that you can perform a custom action
23792                  * after the dragged item is dragged out of the target without dropping.
23793                  * @param {Roo.dd.DragDrop} target The drop target
23794                  * @param {Event} e The event object
23795                  * @param {String} id The id of the dragged element
23796                  * @method afterDragOut
23797                  */
23798                 this.afterDragOut(target, e, id);
23799             }
23800         }
23801         this.cachedTarget = null;
23802     },
23803
23804     /**
23805      * An empty function by default, but provided so that you can perform a custom action before the dragged
23806      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23807      * @param {Roo.dd.DragDrop} target The drop target
23808      * @param {Event} e The event object
23809      * @param {String} id The id of the dragged element
23810      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23811      */
23812     beforeDragOut : function(target, e, id){
23813         return true;
23814     },
23815     
23816     // private
23817     onDragDrop : function(e, id){
23818         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23819         if(this.beforeDragDrop(target, e, id) !== false){
23820             if(target.isNotifyTarget){
23821                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23822                     this.onValidDrop(target, e, id);
23823                 }else{
23824                     this.onInvalidDrop(target, e, id);
23825                 }
23826             }else{
23827                 this.onValidDrop(target, e, id);
23828             }
23829             
23830             if(this.afterDragDrop){
23831                 /**
23832                  * An empty function by default, but provided so that you can perform a custom action
23833                  * after a valid drag drop has occurred by providing an implementation.
23834                  * @param {Roo.dd.DragDrop} target The drop target
23835                  * @param {Event} e The event object
23836                  * @param {String} id The id of the dropped element
23837                  * @method afterDragDrop
23838                  */
23839                 this.afterDragDrop(target, e, id);
23840             }
23841         }
23842         delete this.cachedTarget;
23843     },
23844
23845     /**
23846      * An empty function by default, but provided so that you can perform a custom action before the dragged
23847      * item is dropped onto the target and optionally cancel the onDragDrop.
23848      * @param {Roo.dd.DragDrop} target The drop target
23849      * @param {Event} e The event object
23850      * @param {String} id The id of the dragged element
23851      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23852      */
23853     beforeDragDrop : function(target, e, id){
23854         return true;
23855     },
23856
23857     // private
23858     onValidDrop : function(target, e, id){
23859         this.hideProxy();
23860         if(this.afterValidDrop){
23861             /**
23862              * An empty function by default, but provided so that you can perform a custom action
23863              * after a valid drop has occurred by providing an implementation.
23864              * @param {Object} target The target DD 
23865              * @param {Event} e The event object
23866              * @param {String} id The id of the dropped element
23867              * @method afterInvalidDrop
23868              */
23869             this.afterValidDrop(target, e, id);
23870         }
23871     },
23872
23873     // private
23874     getRepairXY : function(e, data){
23875         return this.el.getXY();  
23876     },
23877
23878     // private
23879     onInvalidDrop : function(target, e, id){
23880         this.beforeInvalidDrop(target, e, id);
23881         if(this.cachedTarget){
23882             if(this.cachedTarget.isNotifyTarget){
23883                 this.cachedTarget.notifyOut(this, e, this.dragData);
23884             }
23885             this.cacheTarget = null;
23886         }
23887         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23888
23889         if(this.afterInvalidDrop){
23890             /**
23891              * An empty function by default, but provided so that you can perform a custom action
23892              * after an invalid drop has occurred by providing an implementation.
23893              * @param {Event} e The event object
23894              * @param {String} id The id of the dropped element
23895              * @method afterInvalidDrop
23896              */
23897             this.afterInvalidDrop(e, id);
23898         }
23899     },
23900
23901     // private
23902     afterRepair : function(){
23903         if(Roo.enableFx){
23904             this.el.highlight(this.hlColor || "c3daf9");
23905         }
23906         this.dragging = false;
23907     },
23908
23909     /**
23910      * An empty function by default, but provided so that you can perform a custom action after an invalid
23911      * drop has occurred.
23912      * @param {Roo.dd.DragDrop} target The drop target
23913      * @param {Event} e The event object
23914      * @param {String} id The id of the dragged element
23915      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23916      */
23917     beforeInvalidDrop : function(target, e, id){
23918         return true;
23919     },
23920
23921     // private
23922     handleMouseDown : function(e){
23923         if(this.dragging) {
23924             return;
23925         }
23926         var data = this.getDragData(e);
23927         if(data && this.onBeforeDrag(data, e) !== false){
23928             this.dragData = data;
23929             this.proxy.stop();
23930             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23931         } 
23932     },
23933
23934     /**
23935      * An empty function by default, but provided so that you can perform a custom action before the initial
23936      * drag event begins and optionally cancel it.
23937      * @param {Object} data An object containing arbitrary data to be shared with drop targets
23938      * @param {Event} e The event object
23939      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23940      */
23941     onBeforeDrag : function(data, e){
23942         return true;
23943     },
23944
23945     /**
23946      * An empty function by default, but provided so that you can perform a custom action once the initial
23947      * drag event has begun.  The drag cannot be canceled from this function.
23948      * @param {Number} x The x position of the click on the dragged object
23949      * @param {Number} y The y position of the click on the dragged object
23950      */
23951     onStartDrag : Roo.emptyFn,
23952
23953     // private - YUI override
23954     startDrag : function(x, y){
23955         this.proxy.reset();
23956         this.dragging = true;
23957         this.proxy.update("");
23958         this.onInitDrag(x, y);
23959         this.proxy.show();
23960     },
23961
23962     // private
23963     onInitDrag : function(x, y){
23964         var clone = this.el.dom.cloneNode(true);
23965         clone.id = Roo.id(); // prevent duplicate ids
23966         this.proxy.update(clone);
23967         this.onStartDrag(x, y);
23968         return true;
23969     },
23970
23971     /**
23972      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23973      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23974      */
23975     getProxy : function(){
23976         return this.proxy;  
23977     },
23978
23979     /**
23980      * Hides the drag source's {@link Roo.dd.StatusProxy}
23981      */
23982     hideProxy : function(){
23983         this.proxy.hide();  
23984         this.proxy.reset(true);
23985         this.dragging = false;
23986     },
23987
23988     // private
23989     triggerCacheRefresh : function(){
23990         Roo.dd.DDM.refreshCache(this.groups);
23991     },
23992
23993     // private - override to prevent hiding
23994     b4EndDrag: function(e) {
23995     },
23996
23997     // private - override to prevent moving
23998     endDrag : function(e){
23999         this.onEndDrag(this.dragData, e);
24000     },
24001
24002     // private
24003     onEndDrag : function(data, e){
24004     },
24005     
24006     // private - pin to cursor
24007     autoOffset : function(x, y) {
24008         this.setDelta(-12, -20);
24009     }    
24010 });/*
24011  * Based on:
24012  * Ext JS Library 1.1.1
24013  * Copyright(c) 2006-2007, Ext JS, LLC.
24014  *
24015  * Originally Released Under LGPL - original licence link has changed is not relivant.
24016  *
24017  * Fork - LGPL
24018  * <script type="text/javascript">
24019  */
24020
24021
24022 /**
24023  * @class Roo.dd.DropTarget
24024  * @extends Roo.dd.DDTarget
24025  * A simple class that provides the basic implementation needed to make any element a drop target that can have
24026  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
24027  * @constructor
24028  * @param {String/HTMLElement/Element} el The container element
24029  * @param {Object} config
24030  */
24031 Roo.dd.DropTarget = function(el, config){
24032     this.el = Roo.get(el);
24033     
24034     var listeners = false; ;
24035     if (config && config.listeners) {
24036         listeners= config.listeners;
24037         delete config.listeners;
24038     }
24039     Roo.apply(this, config);
24040     
24041     if(this.containerScroll){
24042         Roo.dd.ScrollManager.register(this.el);
24043     }
24044     this.addEvents( {
24045          /**
24046          * @scope Roo.dd.DropTarget
24047          */
24048          
24049          /**
24050          * @event enter
24051          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
24052          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
24053          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
24054          * 
24055          * IMPORTANT : it should set  this.valid to true|false
24056          * 
24057          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24058          * @param {Event} e The event
24059          * @param {Object} data An object containing arbitrary data supplied by the drag source
24060          */
24061         "enter" : true,
24062         
24063          /**
24064          * @event over
24065          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
24066          * This method will be called on every mouse movement while the drag source is over the drop target.
24067          * This default implementation simply returns the dropAllowed config value.
24068          * 
24069          * IMPORTANT : it should set  this.valid to true|false
24070          * 
24071          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24072          * @param {Event} e The event
24073          * @param {Object} data An object containing arbitrary data supplied by the drag source
24074          
24075          */
24076         "over" : true,
24077         /**
24078          * @event out
24079          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
24080          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
24081          * overClass (if any) from the drop element.
24082          * 
24083          * 
24084          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24085          * @param {Event} e The event
24086          * @param {Object} data An object containing arbitrary data supplied by the drag source
24087          */
24088          "out" : true,
24089          
24090         /**
24091          * @event drop
24092          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
24093          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
24094          * implementation that does something to process the drop event and returns true so that the drag source's
24095          * repair action does not run.
24096          * 
24097          * IMPORTANT : it should set this.success
24098          * 
24099          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24100          * @param {Event} e The event
24101          * @param {Object} data An object containing arbitrary data supplied by the drag source
24102         */
24103          "drop" : true
24104     });
24105             
24106      
24107     Roo.dd.DropTarget.superclass.constructor.call(  this, 
24108         this.el.dom, 
24109         this.ddGroup || this.group,
24110         {
24111             isTarget: true,
24112             listeners : listeners || {} 
24113            
24114         
24115         }
24116     );
24117
24118 };
24119
24120 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
24121     /**
24122      * @cfg {String} overClass
24123      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
24124      */
24125      /**
24126      * @cfg {String} ddGroup
24127      * The drag drop group to handle drop events for
24128      */
24129      
24130     /**
24131      * @cfg {String} dropAllowed
24132      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
24133      */
24134     dropAllowed : "x-dd-drop-ok",
24135     /**
24136      * @cfg {String} dropNotAllowed
24137      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
24138      */
24139     dropNotAllowed : "x-dd-drop-nodrop",
24140     /**
24141      * @cfg {boolean} success
24142      * set this after drop listener.. 
24143      */
24144     success : false,
24145     /**
24146      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
24147      * if the drop point is valid for over/enter..
24148      */
24149     valid : false,
24150     // private
24151     isTarget : true,
24152
24153     // private
24154     isNotifyTarget : true,
24155     
24156     /**
24157      * @hide
24158      */
24159     notifyEnter : function(dd, e, data)
24160     {
24161         this.valid = true;
24162         this.fireEvent('enter', dd, e, data);
24163         if(this.overClass){
24164             this.el.addClass(this.overClass);
24165         }
24166         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24167             this.valid ? this.dropAllowed : this.dropNotAllowed
24168         );
24169     },
24170
24171     /**
24172      * @hide
24173      */
24174     notifyOver : function(dd, e, data)
24175     {
24176         this.valid = true;
24177         this.fireEvent('over', dd, e, data);
24178         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
24179             this.valid ? this.dropAllowed : this.dropNotAllowed
24180         );
24181     },
24182
24183     /**
24184      * @hide
24185      */
24186     notifyOut : function(dd, e, data)
24187     {
24188         this.fireEvent('out', dd, e, data);
24189         if(this.overClass){
24190             this.el.removeClass(this.overClass);
24191         }
24192     },
24193
24194     /**
24195      * @hide
24196      */
24197     notifyDrop : function(dd, e, data)
24198     {
24199         this.success = false;
24200         this.fireEvent('drop', dd, e, data);
24201         return this.success;
24202     }
24203 });/*
24204  * Based on:
24205  * Ext JS Library 1.1.1
24206  * Copyright(c) 2006-2007, Ext JS, LLC.
24207  *
24208  * Originally Released Under LGPL - original licence link has changed is not relivant.
24209  *
24210  * Fork - LGPL
24211  * <script type="text/javascript">
24212  */
24213
24214
24215 /**
24216  * @class Roo.dd.DragZone
24217  * @extends Roo.dd.DragSource
24218  * This class provides a container DD instance that proxies for multiple child node sources.<br />
24219  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
24220  * @constructor
24221  * @param {String/HTMLElement/Element} el The container element
24222  * @param {Object} config
24223  */
24224 Roo.dd.DragZone = function(el, config){
24225     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
24226     if(this.containerScroll){
24227         Roo.dd.ScrollManager.register(this.el);
24228     }
24229 };
24230
24231 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
24232     /**
24233      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
24234      * for auto scrolling during drag operations.
24235      */
24236     /**
24237      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
24238      * method after a failed drop (defaults to "c3daf9" - light blue)
24239      */
24240
24241     /**
24242      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
24243      * for a valid target to drag based on the mouse down. Override this method
24244      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
24245      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
24246      * @param {EventObject} e The mouse down event
24247      * @return {Object} The dragData
24248      */
24249     getDragData : function(e){
24250         return Roo.dd.Registry.getHandleFromEvent(e);
24251     },
24252     
24253     /**
24254      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
24255      * this.dragData.ddel
24256      * @param {Number} x The x position of the click on the dragged object
24257      * @param {Number} y The y position of the click on the dragged object
24258      * @return {Boolean} true to continue the drag, false to cancel
24259      */
24260     onInitDrag : function(x, y){
24261         this.proxy.update(this.dragData.ddel.cloneNode(true));
24262         this.onStartDrag(x, y);
24263         return true;
24264     },
24265     
24266     /**
24267      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
24268      */
24269     afterRepair : function(){
24270         if(Roo.enableFx){
24271             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
24272         }
24273         this.dragging = false;
24274     },
24275
24276     /**
24277      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
24278      * the XY of this.dragData.ddel
24279      * @param {EventObject} e The mouse up event
24280      * @return {Array} The xy location (e.g. [100, 200])
24281      */
24282     getRepairXY : function(e){
24283         return Roo.Element.fly(this.dragData.ddel).getXY();  
24284     }
24285 });/*
24286  * Based on:
24287  * Ext JS Library 1.1.1
24288  * Copyright(c) 2006-2007, Ext JS, LLC.
24289  *
24290  * Originally Released Under LGPL - original licence link has changed is not relivant.
24291  *
24292  * Fork - LGPL
24293  * <script type="text/javascript">
24294  */
24295 /**
24296  * @class Roo.dd.DropZone
24297  * @extends Roo.dd.DropTarget
24298  * This class provides a container DD instance that proxies for multiple child node targets.<br />
24299  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
24300  * @constructor
24301  * @param {String/HTMLElement/Element} el The container element
24302  * @param {Object} config
24303  */
24304 Roo.dd.DropZone = function(el, config){
24305     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
24306 };
24307
24308 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
24309     /**
24310      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
24311      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
24312      * provide your own custom lookup.
24313      * @param {Event} e The event
24314      * @return {Object} data The custom data
24315      */
24316     getTargetFromEvent : function(e){
24317         return Roo.dd.Registry.getTargetFromEvent(e);
24318     },
24319
24320     /**
24321      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
24322      * that it has registered.  This method has no default implementation and should be overridden to provide
24323      * node-specific processing if necessary.
24324      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
24325      * {@link #getTargetFromEvent} for this node)
24326      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24327      * @param {Event} e The event
24328      * @param {Object} data An object containing arbitrary data supplied by the drag source
24329      */
24330     onNodeEnter : function(n, dd, e, data){
24331         
24332     },
24333
24334     /**
24335      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
24336      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
24337      * overridden to provide the proper feedback.
24338      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24339      * {@link #getTargetFromEvent} for this node)
24340      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24341      * @param {Event} e The event
24342      * @param {Object} data An object containing arbitrary data supplied by the drag source
24343      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24344      * underlying {@link Roo.dd.StatusProxy} can be updated
24345      */
24346     onNodeOver : function(n, dd, e, data){
24347         return this.dropAllowed;
24348     },
24349
24350     /**
24351      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
24352      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
24353      * node-specific processing if necessary.
24354      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24355      * {@link #getTargetFromEvent} for this node)
24356      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24357      * @param {Event} e The event
24358      * @param {Object} data An object containing arbitrary data supplied by the drag source
24359      */
24360     onNodeOut : function(n, dd, e, data){
24361         
24362     },
24363
24364     /**
24365      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
24366      * the drop node.  The default implementation returns false, so it should be overridden to provide the
24367      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
24368      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
24369      * {@link #getTargetFromEvent} for this node)
24370      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24371      * @param {Event} e The event
24372      * @param {Object} data An object containing arbitrary data supplied by the drag source
24373      * @return {Boolean} True if the drop was valid, else false
24374      */
24375     onNodeDrop : function(n, dd, e, data){
24376         return false;
24377     },
24378
24379     /**
24380      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
24381      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
24382      * it should be overridden to provide the proper feedback if necessary.
24383      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24384      * @param {Event} e The event
24385      * @param {Object} data An object containing arbitrary data supplied by the drag source
24386      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24387      * underlying {@link Roo.dd.StatusProxy} can be updated
24388      */
24389     onContainerOver : function(dd, e, data){
24390         return this.dropNotAllowed;
24391     },
24392
24393     /**
24394      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
24395      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
24396      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
24397      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
24398      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24399      * @param {Event} e The event
24400      * @param {Object} data An object containing arbitrary data supplied by the drag source
24401      * @return {Boolean} True if the drop was valid, else false
24402      */
24403     onContainerDrop : function(dd, e, data){
24404         return false;
24405     },
24406
24407     /**
24408      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
24409      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
24410      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
24411      * you should override this method and provide a custom implementation.
24412      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24413      * @param {Event} e The event
24414      * @param {Object} data An object containing arbitrary data supplied by the drag source
24415      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24416      * underlying {@link Roo.dd.StatusProxy} can be updated
24417      */
24418     notifyEnter : function(dd, e, data){
24419         return this.dropNotAllowed;
24420     },
24421
24422     /**
24423      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
24424      * This method will be called on every mouse movement while the drag source is over the drop zone.
24425      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
24426      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
24427      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
24428      * registered node, it will call {@link #onContainerOver}.
24429      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24430      * @param {Event} e The event
24431      * @param {Object} data An object containing arbitrary data supplied by the drag source
24432      * @return {String} status The CSS class that communicates the drop status back to the source so that the
24433      * underlying {@link Roo.dd.StatusProxy} can be updated
24434      */
24435     notifyOver : function(dd, e, data){
24436         var n = this.getTargetFromEvent(e);
24437         if(!n){ // not over valid drop target
24438             if(this.lastOverNode){
24439                 this.onNodeOut(this.lastOverNode, dd, e, data);
24440                 this.lastOverNode = null;
24441             }
24442             return this.onContainerOver(dd, e, data);
24443         }
24444         if(this.lastOverNode != n){
24445             if(this.lastOverNode){
24446                 this.onNodeOut(this.lastOverNode, dd, e, data);
24447             }
24448             this.onNodeEnter(n, dd, e, data);
24449             this.lastOverNode = n;
24450         }
24451         return this.onNodeOver(n, dd, e, data);
24452     },
24453
24454     /**
24455      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
24456      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
24457      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
24458      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
24459      * @param {Event} e The event
24460      * @param {Object} data An object containing arbitrary data supplied by the drag zone
24461      */
24462     notifyOut : function(dd, e, data){
24463         if(this.lastOverNode){
24464             this.onNodeOut(this.lastOverNode, dd, e, data);
24465             this.lastOverNode = null;
24466         }
24467     },
24468
24469     /**
24470      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
24471      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
24472      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
24473      * otherwise it will call {@link #onContainerDrop}.
24474      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
24475      * @param {Event} e The event
24476      * @param {Object} data An object containing arbitrary data supplied by the drag source
24477      * @return {Boolean} True if the drop was valid, else false
24478      */
24479     notifyDrop : function(dd, e, data){
24480         if(this.lastOverNode){
24481             this.onNodeOut(this.lastOverNode, dd, e, data);
24482             this.lastOverNode = null;
24483         }
24484         var n = this.getTargetFromEvent(e);
24485         return n ?
24486             this.onNodeDrop(n, dd, e, data) :
24487             this.onContainerDrop(dd, e, data);
24488     },
24489
24490     // private
24491     triggerCacheRefresh : function(){
24492         Roo.dd.DDM.refreshCache(this.groups);
24493     }  
24494 });