roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
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             if(window.location.href.indexOf("localhost") == -1) {
347                 return;
348             }
349             
350             console.log(s);
351         },
352         /**
353          * 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.
354          * @param {Object} o
355          * @return {String}
356          */
357         urlEncode : function(o){
358             if(!o){
359                 return "";
360             }
361             var buf = [];
362             for(var key in o){
363                 var ov = o[key], k = Roo.encodeURIComponent(key);
364                 var type = typeof ov;
365                 if(type == 'undefined'){
366                     buf.push(k, "=&");
367                 }else if(type != "function" && type != "object"){
368                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
369                 }else if(ov instanceof Array){
370                     if (ov.length) {
371                             for(var i = 0, len = ov.length; i < len; i++) {
372                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
373                             }
374                         } else {
375                             buf.push(k, "=&");
376                         }
377                 }
378             }
379             buf.pop();
380             return buf.join("");
381         },
382          /**
383          * Safe version of encodeURIComponent
384          * @param {String} data 
385          * @return {String} 
386          */
387         
388         encodeURIComponent : function (data)
389         {
390             try {
391                 return encodeURIComponent(data);
392             } catch(e) {} // should be an uri encode error.
393             
394             if (data == '' || data == null){
395                return '';
396             }
397             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
398             function nibble_to_hex(nibble){
399                 var chars = '0123456789ABCDEF';
400                 return chars.charAt(nibble);
401             }
402             data = data.toString();
403             var buffer = '';
404             for(var i=0; i<data.length; i++){
405                 var c = data.charCodeAt(i);
406                 var bs = new Array();
407                 if (c > 0x10000){
408                         // 4 bytes
409                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
410                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
411                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
412                     bs[3] = 0x80 | (c & 0x3F);
413                 }else if (c > 0x800){
414                          // 3 bytes
415                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
416                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
417                     bs[2] = 0x80 | (c & 0x3F);
418                 }else if (c > 0x80){
419                        // 2 bytes
420                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
421                     bs[1] = 0x80 | (c & 0x3F);
422                 }else{
423                         // 1 byte
424                     bs[0] = c;
425                 }
426                 for(var j=0; j<bs.length; j++){
427                     var b = bs[j];
428                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
429                             + nibble_to_hex(b &0x0F);
430                     buffer += '%'+hex;
431                }
432             }
433             return buffer;    
434              
435         },
436
437         /**
438          * 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]}.
439          * @param {String} string
440          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
441          * @return {Object} A literal with members
442          */
443         urlDecode : function(string, overwrite){
444             if(!string || !string.length){
445                 return {};
446             }
447             var obj = {};
448             var pairs = string.split('&');
449             var pair, name, value;
450             for(var i = 0, len = pairs.length; i < len; i++){
451                 pair = pairs[i].split('=');
452                 name = decodeURIComponent(pair[0]);
453                 value = decodeURIComponent(pair[1]);
454                 if(overwrite !== true){
455                     if(typeof obj[name] == "undefined"){
456                         obj[name] = value;
457                     }else if(typeof obj[name] == "string"){
458                         obj[name] = [obj[name]];
459                         obj[name].push(value);
460                     }else{
461                         obj[name].push(value);
462                     }
463                 }else{
464                     obj[name] = value;
465                 }
466             }
467             return obj;
468         },
469
470         /**
471          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
472          * passed array is not really an array, your function is called once with it.
473          * The supplied function is called with (Object item, Number index, Array allItems).
474          * @param {Array/NodeList/Mixed} array
475          * @param {Function} fn
476          * @param {Object} scope
477          */
478         each : function(array, fn, scope){
479             if(typeof array.length == "undefined" || typeof array == "string"){
480                 array = [array];
481             }
482             for(var i = 0, len = array.length; i < len; i++){
483                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484             }
485         },
486
487         // deprecated
488         combine : function(){
489             var as = arguments, l = as.length, r = [];
490             for(var i = 0; i < l; i++){
491                 var a = as[i];
492                 if(a instanceof Array){
493                     r = r.concat(a);
494                 }else if(a.length !== undefined && !a.substr){
495                     r = r.concat(Array.prototype.slice.call(a, 0));
496                 }else{
497                     r.push(a);
498                 }
499             }
500             return r;
501         },
502
503         /**
504          * Escapes the passed string for use in a regular expression
505          * @param {String} str
506          * @return {String}
507          */
508         escapeRe : function(s) {
509             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
510         },
511
512         // internal
513         callback : function(cb, scope, args, delay){
514             if(typeof cb == "function"){
515                 if(delay){
516                     cb.defer(delay, scope, args || []);
517                 }else{
518                     cb.apply(scope, args || []);
519                 }
520             }
521         },
522
523         /**
524          * Return the dom node for the passed string (id), dom node, or Roo.Element
525          * @param {String/HTMLElement/Roo.Element} el
526          * @return HTMLElement
527          */
528         getDom : function(el){
529             if(!el){
530                 return null;
531             }
532             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
533         },
534
535         /**
536         * Shorthand for {@link Roo.ComponentMgr#get}
537         * @param {String} id
538         * @return Roo.Component
539         */
540         getCmp : function(id){
541             return Roo.ComponentMgr.get(id);
542         },
543          
544         num : function(v, defaultValue){
545             if(typeof v != 'number'){
546                 return defaultValue;
547             }
548             return v;
549         },
550
551         destroy : function(){
552             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
553                 var as = a[i];
554                 if(as){
555                     if(as.dom){
556                         as.removeAllListeners();
557                         as.remove();
558                         continue;
559                     }
560                     if(typeof as.purgeListeners == 'function'){
561                         as.purgeListeners();
562                     }
563                     if(typeof as.destroy == 'function'){
564                         as.destroy();
565                     }
566                 }
567             }
568         },
569
570         // inpired by a similar function in mootools library
571         /**
572          * Returns the type of object that is passed in. If the object passed in is null or undefined it
573          * return false otherwise it returns one of the following values:<ul>
574          * <li><b>string</b>: If the object passed is a string</li>
575          * <li><b>number</b>: If the object passed is a number</li>
576          * <li><b>boolean</b>: If the object passed is a boolean value</li>
577          * <li><b>function</b>: If the object passed is a function reference</li>
578          * <li><b>object</b>: If the object passed is an object</li>
579          * <li><b>array</b>: If the object passed is an array</li>
580          * <li><b>regexp</b>: If the object passed is a regular expression</li>
581          * <li><b>element</b>: If the object passed is a DOM Element</li>
582          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
583          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
584          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
585          * @param {Mixed} object
586          * @return {String}
587          */
588         type : function(o){
589             if(o === undefined || o === null){
590                 return false;
591             }
592             if(o.htmlElement){
593                 return 'element';
594             }
595             var t = typeof o;
596             if(t == 'object' && o.nodeName) {
597                 switch(o.nodeType) {
598                     case 1: return 'element';
599                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
600                 }
601             }
602             if(t == 'object' || t == 'function') {
603                 switch(o.constructor) {
604                     case Array: return 'array';
605                     case RegExp: return 'regexp';
606                 }
607                 if(typeof o.length == 'number' && typeof o.item == 'function') {
608                     return 'nodelist';
609                 }
610             }
611             return t;
612         },
613
614         /**
615          * Returns true if the passed value is null, undefined or an empty string (optional).
616          * @param {Mixed} value The value to test
617          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
618          * @return {Boolean}
619          */
620         isEmpty : function(v, allowBlank){
621             return v === null || v === undefined || (!allowBlank ? v === '' : false);
622         },
623         
624         /** @type Boolean */
625         isOpera : isOpera,
626         /** @type Boolean */
627         isSafari : isSafari,
628         /** @type Boolean */
629         isFirefox : isFirefox,
630         /** @type Boolean */
631         isIE : isIE,
632         /** @type Boolean */
633         isIE7 : isIE7,
634         /** @type Boolean */
635         isIE11 : isIE11,
636         /** @type Boolean */
637         isEdge : isEdge,
638         /** @type Boolean */
639         isGecko : isGecko,
640         /** @type Boolean */
641         isBorderBox : isBorderBox,
642         /** @type Boolean */
643         isWindows : isWindows,
644         /** @type Boolean */
645         isLinux : isLinux,
646         /** @type Boolean */
647         isMac : isMac,
648         /** @type Boolean */
649         isIOS : isIOS,
650         /** @type Boolean */
651         isAndroid : isAndroid,
652         /** @type Boolean */
653         isTouch : isTouch,
654
655         /**
656          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
657          * you may want to set this to true.
658          * @type Boolean
659          */
660         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661         
662         
663                 
664         /**
665          * Selects a single element as a Roo Element
666          * This is about as close as you can get to jQuery's $('do crazy stuff')
667          * @param {String} selector The selector/xpath query
668          * @param {Node} root (optional) The start of the query (defaults to document).
669          * @return {Roo.Element}
670          */
671         selectNode : function(selector, root) 
672         {
673             var node = Roo.DomQuery.selectNode(selector,root);
674             return node ? Roo.get(node) : new Roo.Element(false);
675         }
676         
677     });
678
679
680 })();
681
682 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
683                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
684                 "Roo.app", "Roo.ux",
685                 "Roo.bootstrap",
686                 "Roo.bootstrap.dash");
687 /*
688  * Based on:
689  * Ext JS Library 1.1.1
690  * Copyright(c) 2006-2007, Ext JS, LLC.
691  *
692  * Originally Released Under LGPL - original licence link has changed is not relivant.
693  *
694  * Fork - LGPL
695  * <script type="text/javascript">
696  */
697
698 (function() {    
699     // wrappedn so fnCleanup is not in global scope...
700     if(Roo.isIE) {
701         function fnCleanUp() {
702             var p = Function.prototype;
703             delete p.createSequence;
704             delete p.defer;
705             delete p.createDelegate;
706             delete p.createCallback;
707             delete p.createInterceptor;
708
709             window.detachEvent("onunload", fnCleanUp);
710         }
711         window.attachEvent("onunload", fnCleanUp);
712     }
713 })();
714
715
716 /**
717  * @class Function
718  * These functions are available on every Function object (any JavaScript function).
719  */
720 Roo.apply(Function.prototype, {
721      /**
722      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
723      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
724      * Will create a function that is bound to those 2 args.
725      * @return {Function} The new function
726     */
727     createCallback : function(/*args...*/){
728         // make args available, in function below
729         var args = arguments;
730         var method = this;
731         return function() {
732             return method.apply(window, args);
733         };
734     },
735
736     /**
737      * Creates a delegate (callback) that sets the scope to obj.
738      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
739      * Will create a function that is automatically scoped to this.
740      * @param {Object} obj (optional) The object for which the scope is set
741      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
742      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
743      *                                             if a number the args are inserted at the specified position
744      * @return {Function} The new function
745      */
746     createDelegate : function(obj, args, appendArgs){
747         var method = this;
748         return function() {
749             var callArgs = args || arguments;
750             if(appendArgs === true){
751                 callArgs = Array.prototype.slice.call(arguments, 0);
752                 callArgs = callArgs.concat(args);
753             }else if(typeof appendArgs == "number"){
754                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
755                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
756                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
757             }
758             return method.apply(obj || window, callArgs);
759         };
760     },
761
762     /**
763      * Calls this function after the number of millseconds specified.
764      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
765      * @param {Object} obj (optional) The object for which the scope is set
766      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
767      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
768      *                                             if a number the args are inserted at the specified position
769      * @return {Number} The timeout id that can be used with clearTimeout
770      */
771     defer : function(millis, obj, args, appendArgs){
772         var fn = this.createDelegate(obj, args, appendArgs);
773         if(millis){
774             return setTimeout(fn, millis);
775         }
776         fn();
777         return 0;
778     },
779     /**
780      * Create a combined function call sequence of the original function + the passed function.
781      * The resulting function returns the results of the original function.
782      * The passed fcn is called with the parameters of the original function
783      * @param {Function} fcn The function to sequence
784      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
785      * @return {Function} The new function
786      */
787     createSequence : function(fcn, scope){
788         if(typeof fcn != "function"){
789             return this;
790         }
791         var method = this;
792         return function() {
793             var retval = method.apply(this || window, arguments);
794             fcn.apply(scope || this || window, arguments);
795             return retval;
796         };
797     },
798
799     /**
800      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
801      * The resulting function returns the results of the original function.
802      * The passed fcn is called with the parameters of the original function.
803      * @addon
804      * @param {Function} fcn The function to call before the original
805      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
806      * @return {Function} The new function
807      */
808     createInterceptor : function(fcn, scope){
809         if(typeof fcn != "function"){
810             return this;
811         }
812         var method = this;
813         return function() {
814             fcn.target = this;
815             fcn.method = method;
816             if(fcn.apply(scope || this || window, arguments) === false){
817                 return;
818             }
819             return method.apply(this || window, arguments);
820         };
821     }
822 });
823 /*
824  * Based on:
825  * Ext JS Library 1.1.1
826  * Copyright(c) 2006-2007, Ext JS, LLC.
827  *
828  * Originally Released Under LGPL - original licence link has changed is not relivant.
829  *
830  * Fork - LGPL
831  * <script type="text/javascript">
832  */
833
834 Roo.applyIf(String, {
835     
836     /** @scope String */
837     
838     /**
839      * Escapes the passed string for ' and \
840      * @param {String} string The string to escape
841      * @return {String} The escaped string
842      * @static
843      */
844     escape : function(string) {
845         return string.replace(/('|\\)/g, "\\$1");
846     },
847
848     /**
849      * Pads the left side of a string with a specified character.  This is especially useful
850      * for normalizing number and date strings.  Example usage:
851      * <pre><code>
852 var s = String.leftPad('123', 5, '0');
853 // s now contains the string: '00123'
854 </code></pre>
855      * @param {String} string The original string
856      * @param {Number} size The total length of the output string
857      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
858      * @return {String} The padded string
859      * @static
860      */
861     leftPad : function (val, size, ch) {
862         var result = new String(val);
863         if(ch === null || ch === undefined || ch === '') {
864             ch = " ";
865         }
866         while (result.length < size) {
867             result = ch + result;
868         }
869         return result;
870     },
871
872     /**
873      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
874      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
875      * <pre><code>
876 var cls = 'my-class', text = 'Some text';
877 var s = String.format('<div class="{0}">{1}</div>', cls, text);
878 // s now contains the string: '<div class="my-class">Some text</div>'
879 </code></pre>
880      * @param {String} string The tokenized string to be formatted
881      * @param {String} value1 The value to replace token {0}
882      * @param {String} value2 Etc...
883      * @return {String} The formatted string
884      * @static
885      */
886     format : function(format){
887         var args = Array.prototype.slice.call(arguments, 1);
888         return format.replace(/\{(\d+)\}/g, function(m, i){
889             return Roo.util.Format.htmlEncode(args[i]);
890         });
891     }
892   
893     
894 });
895
896 /**
897  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
898  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
899  * they are already different, the first value passed in is returned.  Note that this method returns the new value
900  * but does not change the current string.
901  * <pre><code>
902 // alternate sort directions
903 sort = sort.toggle('ASC', 'DESC');
904
905 // instead of conditional logic:
906 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
907 </code></pre>
908  * @param {String} value The value to compare to the current string
909  * @param {String} other The new value to use if the string already equals the first value passed in
910  * @return {String} The new value
911  */
912  
913 String.prototype.toggle = function(value, other){
914     return this == value ? other : value;
915 };
916
917
918 /**
919   * Remove invalid unicode characters from a string 
920   *
921   * @return {String} The clean string
922   */
923 String.prototype.unicodeClean = function () {
924     return this.replace(/[\s\S]/g,
925         function(character) {
926             if (character.charCodeAt()< 256) {
927               return character;
928            }
929            try {
930                 encodeURIComponent(character);
931            } catch(e) { 
932               return '';
933            }
934            return character;
935         }
936     );
937 };
938   
939 /*
940  * Based on:
941  * Ext JS Library 1.1.1
942  * Copyright(c) 2006-2007, Ext JS, LLC.
943  *
944  * Originally Released Under LGPL - original licence link has changed is not relivant.
945  *
946  * Fork - LGPL
947  * <script type="text/javascript">
948  */
949
950  /**
951  * @class Number
952  */
953 Roo.applyIf(Number.prototype, {
954     /**
955      * Checks whether or not the current number is within a desired range.  If the number is already within the
956      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
957      * exceeded.  Note that this method returns the constrained value but does not change the current number.
958      * @param {Number} min The minimum number in the range
959      * @param {Number} max The maximum number in the range
960      * @return {Number} The constrained value if outside the range, otherwise the current value
961      */
962     constrain : function(min, max){
963         return Math.min(Math.max(this, min), max);
964     }
965 });/*
966  * Based on:
967  * Ext JS Library 1.1.1
968  * Copyright(c) 2006-2007, Ext JS, LLC.
969  *
970  * Originally Released Under LGPL - original licence link has changed is not relivant.
971  *
972  * Fork - LGPL
973  * <script type="text/javascript">
974  */
975  /**
976  * @class Array
977  */
978 Roo.applyIf(Array.prototype, {
979     /**
980      * 
981      * Checks whether or not the specified object exists in the array.
982      * @param {Object} o The object to check for
983      * @return {Number} The index of o in the array (or -1 if it is not found)
984      */
985     indexOf : function(o){
986        for (var i = 0, len = this.length; i < len; i++){
987               if(this[i] == o) { return i; }
988        }
989            return -1;
990     },
991
992     /**
993      * Removes the specified object from the array.  If the object is not found nothing happens.
994      * @param {Object} o The object to remove
995      */
996     remove : function(o){
997        var index = this.indexOf(o);
998        if(index != -1){
999            this.splice(index, 1);
1000        }
1001     },
1002     /**
1003      * Map (JS 1.6 compatibility)
1004      * @param {Function} function  to call
1005      */
1006     map : function(fun )
1007     {
1008         var len = this.length >>> 0;
1009         if (typeof fun != "function") {
1010             throw new TypeError();
1011         }
1012         var res = new Array(len);
1013         var thisp = arguments[1];
1014         for (var i = 0; i < len; i++)
1015         {
1016             if (i in this) {
1017                 res[i] = fun.call(thisp, this[i], i, this);
1018             }
1019         }
1020
1021         return res;
1022     }
1023     
1024 });
1025
1026
1027  
1028 /*
1029  * Based on:
1030  * Ext JS Library 1.1.1
1031  * Copyright(c) 2006-2007, Ext JS, LLC.
1032  *
1033  * Originally Released Under LGPL - original licence link has changed is not relivant.
1034  *
1035  * Fork - LGPL
1036  * <script type="text/javascript">
1037  */
1038
1039 /**
1040  * @class Date
1041  *
1042  * The date parsing and format syntax is a subset of
1043  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1044  * supported will provide results equivalent to their PHP versions.
1045  *
1046  * Following is the list of all currently supported formats:
1047  *<pre>
1048 Sample date:
1049 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1050
1051 Format  Output      Description
1052 ------  ----------  --------------------------------------------------------------
1053   d      10         Day of the month, 2 digits with leading zeros
1054   D      Wed        A textual representation of a day, three letters
1055   j      10         Day of the month without leading zeros
1056   l      Wednesday  A full textual representation of the day of the week
1057   S      th         English ordinal day of month suffix, 2 chars (use with j)
1058   w      3          Numeric representation of the day of the week
1059   z      9          The julian date, or day of the year (0-365)
1060   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1061   F      January    A full textual representation of the month
1062   m      01         Numeric representation of a month, with leading zeros
1063   M      Jan        Month name abbreviation, three letters
1064   n      1          Numeric representation of a month, without leading zeros
1065   t      31         Number of days in the given month
1066   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1067   Y      2007       A full numeric representation of a year, 4 digits
1068   y      07         A two digit representation of a year
1069   a      pm         Lowercase Ante meridiem and Post meridiem
1070   A      PM         Uppercase Ante meridiem and Post meridiem
1071   g      3          12-hour format of an hour without leading zeros
1072   G      15         24-hour format of an hour without leading zeros
1073   h      03         12-hour format of an hour with leading zeros
1074   H      15         24-hour format of an hour with leading zeros
1075   i      05         Minutes with leading zeros
1076   s      01         Seconds, with leading zeros
1077   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1078   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1079   T      CST        Timezone setting of the machine running the code
1080   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1081 </pre>
1082  *
1083  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1084  * <pre><code>
1085 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1086 document.write(dt.format('Y-m-d'));                         //2007-01-10
1087 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1088 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
1089  </code></pre>
1090  *
1091  * Here are some standard date/time patterns that you might find helpful.  They
1092  * are not part of the source of Date.js, but to use them you can simply copy this
1093  * block of code into any script that is included after Date.js and they will also become
1094  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1095  * <pre><code>
1096 Date.patterns = {
1097     ISO8601Long:"Y-m-d H:i:s",
1098     ISO8601Short:"Y-m-d",
1099     ShortDate: "n/j/Y",
1100     LongDate: "l, F d, Y",
1101     FullDateTime: "l, F d, Y g:i:s A",
1102     MonthDay: "F d",
1103     ShortTime: "g:i A",
1104     LongTime: "g:i:s A",
1105     SortableDateTime: "Y-m-d\\TH:i:s",
1106     UniversalSortableDateTime: "Y-m-d H:i:sO",
1107     YearMonth: "F, Y"
1108 };
1109 </code></pre>
1110  *
1111  * Example usage:
1112  * <pre><code>
1113 var dt = new Date();
1114 document.write(dt.format(Date.patterns.ShortDate));
1115  </code></pre>
1116  */
1117
1118 /*
1119  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1120  * They generate precompiled functions from date formats instead of parsing and
1121  * processing the pattern every time you format a date.  These functions are available
1122  * on every Date object (any javascript function).
1123  *
1124  * The original article and download are here:
1125  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1126  *
1127  */
1128  
1129  
1130  // was in core
1131 /**
1132  Returns the number of milliseconds between this date and date
1133  @param {Date} date (optional) Defaults to now
1134  @return {Number} The diff in milliseconds
1135  @member Date getElapsed
1136  */
1137 Date.prototype.getElapsed = function(date) {
1138         return Math.abs((date || new Date()).getTime()-this.getTime());
1139 };
1140 // was in date file..
1141
1142
1143 // private
1144 Date.parseFunctions = {count:0};
1145 // private
1146 Date.parseRegexes = [];
1147 // private
1148 Date.formatFunctions = {count:0};
1149
1150 // private
1151 Date.prototype.dateFormat = function(format) {
1152     if (Date.formatFunctions[format] == null) {
1153         Date.createNewFormat(format);
1154     }
1155     var func = Date.formatFunctions[format];
1156     return this[func]();
1157 };
1158
1159
1160 /**
1161  * Formats a date given the supplied format string
1162  * @param {String} format The format string
1163  * @return {String} The formatted date
1164  * @method
1165  */
1166 Date.prototype.format = Date.prototype.dateFormat;
1167
1168 // private
1169 Date.createNewFormat = function(format) {
1170     var funcName = "format" + Date.formatFunctions.count++;
1171     Date.formatFunctions[format] = funcName;
1172     var code = "Date.prototype." + funcName + " = function(){return ";
1173     var special = false;
1174     var ch = '';
1175     for (var i = 0; i < format.length; ++i) {
1176         ch = format.charAt(i);
1177         if (!special && ch == "\\") {
1178             special = true;
1179         }
1180         else if (special) {
1181             special = false;
1182             code += "'" + String.escape(ch) + "' + ";
1183         }
1184         else {
1185             code += Date.getFormatCode(ch);
1186         }
1187     }
1188     /** eval:var:zzzzzzzzzzzzz */
1189     eval(code.substring(0, code.length - 3) + ";}");
1190 };
1191
1192 // private
1193 Date.getFormatCode = function(character) {
1194     switch (character) {
1195     case "d":
1196         return "String.leftPad(this.getDate(), 2, '0') + ";
1197     case "D":
1198         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1199     case "j":
1200         return "this.getDate() + ";
1201     case "l":
1202         return "Date.dayNames[this.getDay()] + ";
1203     case "S":
1204         return "this.getSuffix() + ";
1205     case "w":
1206         return "this.getDay() + ";
1207     case "z":
1208         return "this.getDayOfYear() + ";
1209     case "W":
1210         return "this.getWeekOfYear() + ";
1211     case "F":
1212         return "Date.monthNames[this.getMonth()] + ";
1213     case "m":
1214         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1215     case "M":
1216         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1217     case "n":
1218         return "(this.getMonth() + 1) + ";
1219     case "t":
1220         return "this.getDaysInMonth() + ";
1221     case "L":
1222         return "(this.isLeapYear() ? 1 : 0) + ";
1223     case "Y":
1224         return "this.getFullYear() + ";
1225     case "y":
1226         return "('' + this.getFullYear()).substring(2, 4) + ";
1227     case "a":
1228         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1229     case "A":
1230         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1231     case "g":
1232         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1233     case "G":
1234         return "this.getHours() + ";
1235     case "h":
1236         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1237     case "H":
1238         return "String.leftPad(this.getHours(), 2, '0') + ";
1239     case "i":
1240         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1241     case "s":
1242         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1243     case "O":
1244         return "this.getGMTOffset() + ";
1245     case "P":
1246         return "this.getGMTColonOffset() + ";
1247     case "T":
1248         return "this.getTimezone() + ";
1249     case "Z":
1250         return "(this.getTimezoneOffset() * -60) + ";
1251     default:
1252         return "'" + String.escape(character) + "' + ";
1253     }
1254 };
1255
1256 /**
1257  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1258  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1259  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1260  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1261  * string or the parse operation will fail.
1262  * Example Usage:
1263 <pre><code>
1264 //dt = Fri May 25 2007 (current date)
1265 var dt = new Date();
1266
1267 //dt = Thu May 25 2006 (today's month/day in 2006)
1268 dt = Date.parseDate("2006", "Y");
1269
1270 //dt = Sun Jan 15 2006 (all date parts specified)
1271 dt = Date.parseDate("2006-1-15", "Y-m-d");
1272
1273 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1274 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1275 </code></pre>
1276  * @param {String} input The unparsed date as a string
1277  * @param {String} format The format the date is in
1278  * @return {Date} The parsed date
1279  * @static
1280  */
1281 Date.parseDate = function(input, format) {
1282     if (Date.parseFunctions[format] == null) {
1283         Date.createParser(format);
1284     }
1285     var func = Date.parseFunctions[format];
1286     return Date[func](input);
1287 };
1288 /**
1289  * @private
1290  */
1291
1292 Date.createParser = function(format) {
1293     var funcName = "parse" + Date.parseFunctions.count++;
1294     var regexNum = Date.parseRegexes.length;
1295     var currentGroup = 1;
1296     Date.parseFunctions[format] = funcName;
1297
1298     var code = "Date." + funcName + " = function(input){\n"
1299         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1300         + "var d = new Date();\n"
1301         + "y = d.getFullYear();\n"
1302         + "m = d.getMonth();\n"
1303         + "d = d.getDate();\n"
1304         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1305         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1306         + "if (results && results.length > 0) {";
1307     var regex = "";
1308
1309     var special = false;
1310     var ch = '';
1311     for (var i = 0; i < format.length; ++i) {
1312         ch = format.charAt(i);
1313         if (!special && ch == "\\") {
1314             special = true;
1315         }
1316         else if (special) {
1317             special = false;
1318             regex += String.escape(ch);
1319         }
1320         else {
1321             var obj = Date.formatCodeToRegex(ch, currentGroup);
1322             currentGroup += obj.g;
1323             regex += obj.s;
1324             if (obj.g && obj.c) {
1325                 code += obj.c;
1326             }
1327         }
1328     }
1329
1330     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1331         + "{v = new Date(y, m, d, h, i, s);}\n"
1332         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1333         + "{v = new Date(y, m, d, h, i);}\n"
1334         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1335         + "{v = new Date(y, m, d, h);}\n"
1336         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1337         + "{v = new Date(y, m, d);}\n"
1338         + "else if (y >= 0 && m >= 0)\n"
1339         + "{v = new Date(y, m);}\n"
1340         + "else if (y >= 0)\n"
1341         + "{v = new Date(y);}\n"
1342         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1343         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1344         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1345         + ";}";
1346
1347     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1348     /** eval:var:zzzzzzzzzzzzz */
1349     eval(code);
1350 };
1351
1352 // private
1353 Date.formatCodeToRegex = function(character, currentGroup) {
1354     switch (character) {
1355     case "D":
1356         return {g:0,
1357         c:null,
1358         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1359     case "j":
1360         return {g:1,
1361             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1362             s:"(\\d{1,2})"}; // day of month without leading zeroes
1363     case "d":
1364         return {g:1,
1365             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1366             s:"(\\d{2})"}; // day of month with leading zeroes
1367     case "l":
1368         return {g:0,
1369             c:null,
1370             s:"(?:" + Date.dayNames.join("|") + ")"};
1371     case "S":
1372         return {g:0,
1373             c:null,
1374             s:"(?:st|nd|rd|th)"};
1375     case "w":
1376         return {g:0,
1377             c:null,
1378             s:"\\d"};
1379     case "z":
1380         return {g:0,
1381             c:null,
1382             s:"(?:\\d{1,3})"};
1383     case "W":
1384         return {g:0,
1385             c:null,
1386             s:"(?:\\d{2})"};
1387     case "F":
1388         return {g:1,
1389             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1390             s:"(" + Date.monthNames.join("|") + ")"};
1391     case "M":
1392         return {g:1,
1393             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1394             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1395     case "n":
1396         return {g:1,
1397             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1398             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1399     case "m":
1400         return {g:1,
1401             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1402             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1403     case "t":
1404         return {g:0,
1405             c:null,
1406             s:"\\d{1,2}"};
1407     case "L":
1408         return {g:0,
1409             c:null,
1410             s:"(?:1|0)"};
1411     case "Y":
1412         return {g:1,
1413             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1414             s:"(\\d{4})"};
1415     case "y":
1416         return {g:1,
1417             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1418                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1419             s:"(\\d{1,2})"};
1420     case "a":
1421         return {g:1,
1422             c:"if (results[" + currentGroup + "] == 'am') {\n"
1423                 + "if (h == 12) { h = 0; }\n"
1424                 + "} else { if (h < 12) { h += 12; }}",
1425             s:"(am|pm)"};
1426     case "A":
1427         return {g:1,
1428             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1429                 + "if (h == 12) { h = 0; }\n"
1430                 + "} else { if (h < 12) { h += 12; }}",
1431             s:"(AM|PM)"};
1432     case "g":
1433     case "G":
1434         return {g:1,
1435             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1436             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1437     case "h":
1438     case "H":
1439         return {g:1,
1440             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1441             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1442     case "i":
1443         return {g:1,
1444             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1445             s:"(\\d{2})"};
1446     case "s":
1447         return {g:1,
1448             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1449             s:"(\\d{2})"};
1450     case "O":
1451         return {g:1,
1452             c:[
1453                 "o = results[", currentGroup, "];\n",
1454                 "var sn = o.substring(0,1);\n", // get + / - sign
1455                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1456                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1457                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1458                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1459             ].join(""),
1460             s:"([+\-]\\d{2,4})"};
1461     
1462     
1463     case "P":
1464         return {g:1,
1465                 c:[
1466                    "o = results[", currentGroup, "];\n",
1467                    "var sn = o.substring(0,1);\n",
1468                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1469                    "var mn = o.substring(4,6) % 60;\n",
1470                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1471                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1472             ].join(""),
1473             s:"([+\-]\\d{4})"};
1474     case "T":
1475         return {g:0,
1476             c:null,
1477             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1478     case "Z":
1479         return {g:1,
1480             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1481                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1482             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1483     default:
1484         return {g:0,
1485             c:null,
1486             s:String.escape(character)};
1487     }
1488 };
1489
1490 /**
1491  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1492  * @return {String} The abbreviated timezone name (e.g. 'CST')
1493  */
1494 Date.prototype.getTimezone = function() {
1495     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1496 };
1497
1498 /**
1499  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1500  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1501  */
1502 Date.prototype.getGMTOffset = function() {
1503     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1504         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1505         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1506 };
1507
1508 /**
1509  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1510  * @return {String} 2-characters representing hours and 2-characters representing minutes
1511  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1512  */
1513 Date.prototype.getGMTColonOffset = function() {
1514         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1515                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1516                 + ":"
1517                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1518 }
1519
1520 /**
1521  * Get the numeric day number of the year, adjusted for leap year.
1522  * @return {Number} 0 through 364 (365 in leap years)
1523  */
1524 Date.prototype.getDayOfYear = function() {
1525     var num = 0;
1526     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1527     for (var i = 0; i < this.getMonth(); ++i) {
1528         num += Date.daysInMonth[i];
1529     }
1530     return num + this.getDate() - 1;
1531 };
1532
1533 /**
1534  * Get the string representation of the numeric week number of the year
1535  * (equivalent to the format specifier 'W').
1536  * @return {String} '00' through '52'
1537  */
1538 Date.prototype.getWeekOfYear = function() {
1539     // Skip to Thursday of this week
1540     var now = this.getDayOfYear() + (4 - this.getDay());
1541     // Find the first Thursday of the year
1542     var jan1 = new Date(this.getFullYear(), 0, 1);
1543     var then = (7 - jan1.getDay() + 4);
1544     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1545 };
1546
1547 /**
1548  * Whether or not the current date is in a leap year.
1549  * @return {Boolean} True if the current date is in a leap year, else false
1550  */
1551 Date.prototype.isLeapYear = function() {
1552     var year = this.getFullYear();
1553     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1554 };
1555
1556 /**
1557  * Get the first day of the current month, adjusted for leap year.  The returned value
1558  * is the numeric day index within the week (0-6) which can be used in conjunction with
1559  * the {@link #monthNames} array to retrieve the textual day name.
1560  * Example:
1561  *<pre><code>
1562 var dt = new Date('1/10/2007');
1563 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1564 </code></pre>
1565  * @return {Number} The day number (0-6)
1566  */
1567 Date.prototype.getFirstDayOfMonth = function() {
1568     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1569     return (day < 0) ? (day + 7) : day;
1570 };
1571
1572 /**
1573  * Get the last day of the current month, adjusted for leap year.  The returned value
1574  * is the numeric day index within the week (0-6) which can be used in conjunction with
1575  * the {@link #monthNames} array to retrieve the textual day name.
1576  * Example:
1577  *<pre><code>
1578 var dt = new Date('1/10/2007');
1579 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1580 </code></pre>
1581  * @return {Number} The day number (0-6)
1582  */
1583 Date.prototype.getLastDayOfMonth = function() {
1584     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1585     return (day < 0) ? (day + 7) : day;
1586 };
1587
1588
1589 /**
1590  * Get the first date of this date's month
1591  * @return {Date}
1592  */
1593 Date.prototype.getFirstDateOfMonth = function() {
1594     return new Date(this.getFullYear(), this.getMonth(), 1);
1595 };
1596
1597 /**
1598  * Get the last date of this date's month
1599  * @return {Date}
1600  */
1601 Date.prototype.getLastDateOfMonth = function() {
1602     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1603 };
1604 /**
1605  * Get the number of days in the current month, adjusted for leap year.
1606  * @return {Number} The number of days in the month
1607  */
1608 Date.prototype.getDaysInMonth = function() {
1609     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1610     return Date.daysInMonth[this.getMonth()];
1611 };
1612
1613 /**
1614  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1615  * @return {String} 'st, 'nd', 'rd' or 'th'
1616  */
1617 Date.prototype.getSuffix = function() {
1618     switch (this.getDate()) {
1619         case 1:
1620         case 21:
1621         case 31:
1622             return "st";
1623         case 2:
1624         case 22:
1625             return "nd";
1626         case 3:
1627         case 23:
1628             return "rd";
1629         default:
1630             return "th";
1631     }
1632 };
1633
1634 // private
1635 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1636
1637 /**
1638  * An array of textual month names.
1639  * Override these values for international dates, for example...
1640  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1641  * @type Array
1642  * @static
1643  */
1644 Date.monthNames =
1645    ["January",
1646     "February",
1647     "March",
1648     "April",
1649     "May",
1650     "June",
1651     "July",
1652     "August",
1653     "September",
1654     "October",
1655     "November",
1656     "December"];
1657
1658 /**
1659  * An array of textual day names.
1660  * Override these values for international dates, for example...
1661  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1662  * @type Array
1663  * @static
1664  */
1665 Date.dayNames =
1666    ["Sunday",
1667     "Monday",
1668     "Tuesday",
1669     "Wednesday",
1670     "Thursday",
1671     "Friday",
1672     "Saturday"];
1673
1674 // private
1675 Date.y2kYear = 50;
1676 // private
1677 Date.monthNumbers = {
1678     Jan:0,
1679     Feb:1,
1680     Mar:2,
1681     Apr:3,
1682     May:4,
1683     Jun:5,
1684     Jul:6,
1685     Aug:7,
1686     Sep:8,
1687     Oct:9,
1688     Nov:10,
1689     Dec:11};
1690
1691 /**
1692  * Creates and returns a new Date instance with the exact same date value as the called instance.
1693  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1694  * variable will also be changed.  When the intention is to create a new variable that will not
1695  * modify the original instance, you should create a clone.
1696  *
1697  * Example of correctly cloning a date:
1698  * <pre><code>
1699 //wrong way:
1700 var orig = new Date('10/1/2006');
1701 var copy = orig;
1702 copy.setDate(5);
1703 document.write(orig);  //returns 'Thu Oct 05 2006'!
1704
1705 //correct way:
1706 var orig = new Date('10/1/2006');
1707 var copy = orig.clone();
1708 copy.setDate(5);
1709 document.write(orig);  //returns 'Thu Oct 01 2006'
1710 </code></pre>
1711  * @return {Date} The new Date instance
1712  */
1713 Date.prototype.clone = function() {
1714         return new Date(this.getTime());
1715 };
1716
1717 /**
1718  * Clears any time information from this date
1719  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1720  @return {Date} this or the clone
1721  */
1722 Date.prototype.clearTime = function(clone){
1723     if(clone){
1724         return this.clone().clearTime();
1725     }
1726     this.setHours(0);
1727     this.setMinutes(0);
1728     this.setSeconds(0);
1729     this.setMilliseconds(0);
1730     return this;
1731 };
1732
1733 // private
1734 // safari setMonth is broken -- check that this is only donw once...
1735 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1736     Date.brokenSetMonth = Date.prototype.setMonth;
1737         Date.prototype.setMonth = function(num){
1738                 if(num <= -1){
1739                         var n = Math.ceil(-num);
1740                         var back_year = Math.ceil(n/12);
1741                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1742                         this.setFullYear(this.getFullYear() - back_year);
1743                         return Date.brokenSetMonth.call(this, month);
1744                 } else {
1745                         return Date.brokenSetMonth.apply(this, arguments);
1746                 }
1747         };
1748 }
1749
1750 /** Date interval constant 
1751 * @static 
1752 * @type String */
1753 Date.MILLI = "ms";
1754 /** Date interval constant 
1755 * @static 
1756 * @type String */
1757 Date.SECOND = "s";
1758 /** Date interval constant 
1759 * @static 
1760 * @type String */
1761 Date.MINUTE = "mi";
1762 /** Date interval constant 
1763 * @static 
1764 * @type String */
1765 Date.HOUR = "h";
1766 /** Date interval constant 
1767 * @static 
1768 * @type String */
1769 Date.DAY = "d";
1770 /** Date interval constant 
1771 * @static 
1772 * @type String */
1773 Date.MONTH = "mo";
1774 /** Date interval constant 
1775 * @static 
1776 * @type String */
1777 Date.YEAR = "y";
1778
1779 /**
1780  * Provides a convenient method of performing basic date arithmetic.  This method
1781  * does not modify the Date instance being called - it creates and returns
1782  * a new Date instance containing the resulting date value.
1783  *
1784  * Examples:
1785  * <pre><code>
1786 //Basic usage:
1787 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1788 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1789
1790 //Negative values will subtract correctly:
1791 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1792 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1793
1794 //You can even chain several calls together in one line!
1795 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1796 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1797  </code></pre>
1798  *
1799  * @param {String} interval   A valid date interval enum value
1800  * @param {Number} value      The amount to add to the current date
1801  * @return {Date} The new Date instance
1802  */
1803 Date.prototype.add = function(interval, value){
1804   var d = this.clone();
1805   if (!interval || value === 0) { return d; }
1806   switch(interval.toLowerCase()){
1807     case Date.MILLI:
1808       d.setMilliseconds(this.getMilliseconds() + value);
1809       break;
1810     case Date.SECOND:
1811       d.setSeconds(this.getSeconds() + value);
1812       break;
1813     case Date.MINUTE:
1814       d.setMinutes(this.getMinutes() + value);
1815       break;
1816     case Date.HOUR:
1817       d.setHours(this.getHours() + value);
1818       break;
1819     case Date.DAY:
1820       d.setDate(this.getDate() + value);
1821       break;
1822     case Date.MONTH:
1823       var day = this.getDate();
1824       if(day > 28){
1825           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1826       }
1827       d.setDate(day);
1828       d.setMonth(this.getMonth() + value);
1829       break;
1830     case Date.YEAR:
1831       d.setFullYear(this.getFullYear() + value);
1832       break;
1833   }
1834   return d;
1835 };
1836 /*
1837  * Based on:
1838  * Ext JS Library 1.1.1
1839  * Copyright(c) 2006-2007, Ext JS, LLC.
1840  *
1841  * Originally Released Under LGPL - original licence link has changed is not relivant.
1842  *
1843  * Fork - LGPL
1844  * <script type="text/javascript">
1845  */
1846
1847 /**
1848  * @class Roo.lib.Dom
1849  * @static
1850  * 
1851  * Dom utils (from YIU afaik)
1852  * 
1853  **/
1854 Roo.lib.Dom = {
1855     /**
1856      * Get the view width
1857      * @param {Boolean} full True will get the full document, otherwise it's the view width
1858      * @return {Number} The width
1859      */
1860      
1861     getViewWidth : function(full) {
1862         return full ? this.getDocumentWidth() : this.getViewportWidth();
1863     },
1864     /**
1865      * Get the view height
1866      * @param {Boolean} full True will get the full document, otherwise it's the view height
1867      * @return {Number} The height
1868      */
1869     getViewHeight : function(full) {
1870         return full ? this.getDocumentHeight() : this.getViewportHeight();
1871     },
1872
1873     getDocumentHeight: function() {
1874         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1875         return Math.max(scrollHeight, this.getViewportHeight());
1876     },
1877
1878     getDocumentWidth: function() {
1879         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1880         return Math.max(scrollWidth, this.getViewportWidth());
1881     },
1882
1883     getViewportHeight: function() {
1884         var height = self.innerHeight;
1885         var mode = document.compatMode;
1886
1887         if ((mode || Roo.isIE) && !Roo.isOpera) {
1888             height = (mode == "CSS1Compat") ?
1889                      document.documentElement.clientHeight :
1890                      document.body.clientHeight;
1891         }
1892
1893         return height;
1894     },
1895
1896     getViewportWidth: function() {
1897         var width = self.innerWidth;
1898         var mode = document.compatMode;
1899
1900         if (mode || Roo.isIE) {
1901             width = (mode == "CSS1Compat") ?
1902                     document.documentElement.clientWidth :
1903                     document.body.clientWidth;
1904         }
1905         return width;
1906     },
1907
1908     isAncestor : function(p, c) {
1909         p = Roo.getDom(p);
1910         c = Roo.getDom(c);
1911         if (!p || !c) {
1912             return false;
1913         }
1914
1915         if (p.contains && !Roo.isSafari) {
1916             return p.contains(c);
1917         } else if (p.compareDocumentPosition) {
1918             return !!(p.compareDocumentPosition(c) & 16);
1919         } else {
1920             var parent = c.parentNode;
1921             while (parent) {
1922                 if (parent == p) {
1923                     return true;
1924                 }
1925                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1926                     return false;
1927                 }
1928                 parent = parent.parentNode;
1929             }
1930             return false;
1931         }
1932     },
1933
1934     getRegion : function(el) {
1935         return Roo.lib.Region.getRegion(el);
1936     },
1937
1938     getY : function(el) {
1939         return this.getXY(el)[1];
1940     },
1941
1942     getX : function(el) {
1943         return this.getXY(el)[0];
1944     },
1945
1946     getXY : function(el) {
1947         var p, pe, b, scroll, bd = document.body;
1948         el = Roo.getDom(el);
1949         var fly = Roo.lib.AnimBase.fly;
1950         if (el.getBoundingClientRect) {
1951             b = el.getBoundingClientRect();
1952             scroll = fly(document).getScroll();
1953             return [b.left + scroll.left, b.top + scroll.top];
1954         }
1955         var x = 0, y = 0;
1956
1957         p = el;
1958
1959         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1960
1961         while (p) {
1962
1963             x += p.offsetLeft;
1964             y += p.offsetTop;
1965
1966             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1967                 hasAbsolute = true;
1968             }
1969
1970             if (Roo.isGecko) {
1971                 pe = fly(p);
1972
1973                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1974                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1975
1976
1977                 x += bl;
1978                 y += bt;
1979
1980
1981                 if (p != el && pe.getStyle('overflow') != 'visible') {
1982                     x += bl;
1983                     y += bt;
1984                 }
1985             }
1986             p = p.offsetParent;
1987         }
1988
1989         if (Roo.isSafari && hasAbsolute) {
1990             x -= bd.offsetLeft;
1991             y -= bd.offsetTop;
1992         }
1993
1994         if (Roo.isGecko && !hasAbsolute) {
1995             var dbd = fly(bd);
1996             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1997             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1998         }
1999
2000         p = el.parentNode;
2001         while (p && p != bd) {
2002             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2003                 x -= p.scrollLeft;
2004                 y -= p.scrollTop;
2005             }
2006             p = p.parentNode;
2007         }
2008         return [x, y];
2009     },
2010  
2011   
2012
2013
2014     setXY : function(el, xy) {
2015         el = Roo.fly(el, '_setXY');
2016         el.position();
2017         var pts = el.translatePoints(xy);
2018         if (xy[0] !== false) {
2019             el.dom.style.left = pts.left + "px";
2020         }
2021         if (xy[1] !== false) {
2022             el.dom.style.top = pts.top + "px";
2023         }
2024     },
2025
2026     setX : function(el, x) {
2027         this.setXY(el, [x, false]);
2028     },
2029
2030     setY : function(el, y) {
2031         this.setXY(el, [false, y]);
2032     }
2033 };
2034 /*
2035  * Portions of this file are based on pieces of Yahoo User Interface Library
2036  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2037  * YUI licensed under the BSD License:
2038  * http://developer.yahoo.net/yui/license.txt
2039  * <script type="text/javascript">
2040  *
2041  */
2042
2043 Roo.lib.Event = function() {
2044     var loadComplete = false;
2045     var listeners = [];
2046     var unloadListeners = [];
2047     var retryCount = 0;
2048     var onAvailStack = [];
2049     var counter = 0;
2050     var lastError = null;
2051
2052     return {
2053         POLL_RETRYS: 200,
2054         POLL_INTERVAL: 20,
2055         EL: 0,
2056         TYPE: 1,
2057         FN: 2,
2058         WFN: 3,
2059         OBJ: 3,
2060         ADJ_SCOPE: 4,
2061         _interval: null,
2062
2063         startInterval: function() {
2064             if (!this._interval) {
2065                 var self = this;
2066                 var callback = function() {
2067                     self._tryPreloadAttach();
2068                 };
2069                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2070
2071             }
2072         },
2073
2074         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2075             onAvailStack.push({ id:         p_id,
2076                 fn:         p_fn,
2077                 obj:        p_obj,
2078                 override:   p_override,
2079                 checkReady: false    });
2080
2081             retryCount = this.POLL_RETRYS;
2082             this.startInterval();
2083         },
2084
2085
2086         addListener: function(el, eventName, fn) {
2087             el = Roo.getDom(el);
2088             if (!el || !fn) {
2089                 return false;
2090             }
2091
2092             if ("unload" == eventName) {
2093                 unloadListeners[unloadListeners.length] =
2094                 [el, eventName, fn];
2095                 return true;
2096             }
2097
2098             var wrappedFn = function(e) {
2099                 return fn(Roo.lib.Event.getEvent(e));
2100             };
2101
2102             var li = [el, eventName, fn, wrappedFn];
2103
2104             var index = listeners.length;
2105             listeners[index] = li;
2106
2107             this.doAdd(el, eventName, wrappedFn, false);
2108             return true;
2109
2110         },
2111
2112
2113         removeListener: function(el, eventName, fn) {
2114             var i, len;
2115
2116             el = Roo.getDom(el);
2117
2118             if(!fn) {
2119                 return this.purgeElement(el, false, eventName);
2120             }
2121
2122
2123             if ("unload" == eventName) {
2124
2125                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2126                     var li = unloadListeners[i];
2127                     if (li &&
2128                         li[0] == el &&
2129                         li[1] == eventName &&
2130                         li[2] == fn) {
2131                         unloadListeners.splice(i, 1);
2132                         return true;
2133                     }
2134                 }
2135
2136                 return false;
2137             }
2138
2139             var cacheItem = null;
2140
2141
2142             var index = arguments[3];
2143
2144             if ("undefined" == typeof index) {
2145                 index = this._getCacheIndex(el, eventName, fn);
2146             }
2147
2148             if (index >= 0) {
2149                 cacheItem = listeners[index];
2150             }
2151
2152             if (!el || !cacheItem) {
2153                 return false;
2154             }
2155
2156             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2157
2158             delete listeners[index][this.WFN];
2159             delete listeners[index][this.FN];
2160             listeners.splice(index, 1);
2161
2162             return true;
2163
2164         },
2165
2166
2167         getTarget: function(ev, resolveTextNode) {
2168             ev = ev.browserEvent || ev;
2169             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2170             var t = ev.target || ev.srcElement;
2171             return this.resolveTextNode(t);
2172         },
2173
2174
2175         resolveTextNode: function(node) {
2176             if (Roo.isSafari && node && 3 == node.nodeType) {
2177                 return node.parentNode;
2178             } else {
2179                 return node;
2180             }
2181         },
2182
2183
2184         getPageX: function(ev) {
2185             ev = ev.browserEvent || ev;
2186             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2187             var x = ev.pageX;
2188             if (!x && 0 !== x) {
2189                 x = ev.clientX || 0;
2190
2191                 if (Roo.isIE) {
2192                     x += this.getScroll()[1];
2193                 }
2194             }
2195
2196             return x;
2197         },
2198
2199
2200         getPageY: function(ev) {
2201             ev = ev.browserEvent || ev;
2202             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2203             var y = ev.pageY;
2204             if (!y && 0 !== y) {
2205                 y = ev.clientY || 0;
2206
2207                 if (Roo.isIE) {
2208                     y += this.getScroll()[0];
2209                 }
2210             }
2211
2212
2213             return y;
2214         },
2215
2216
2217         getXY: function(ev) {
2218             ev = ev.browserEvent || ev;
2219             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2220             return [this.getPageX(ev), this.getPageY(ev)];
2221         },
2222
2223
2224         getRelatedTarget: function(ev) {
2225             ev = ev.browserEvent || ev;
2226             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2227             var t = ev.relatedTarget;
2228             if (!t) {
2229                 if (ev.type == "mouseout") {
2230                     t = ev.toElement;
2231                 } else if (ev.type == "mouseover") {
2232                     t = ev.fromElement;
2233                 }
2234             }
2235
2236             return this.resolveTextNode(t);
2237         },
2238
2239
2240         getTime: function(ev) {
2241             ev = ev.browserEvent || ev;
2242             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2243             if (!ev.time) {
2244                 var t = new Date().getTime();
2245                 try {
2246                     ev.time = t;
2247                 } catch(ex) {
2248                     this.lastError = ex;
2249                     return t;
2250                 }
2251             }
2252
2253             return ev.time;
2254         },
2255
2256
2257         stopEvent: function(ev) {
2258             this.stopPropagation(ev);
2259             this.preventDefault(ev);
2260         },
2261
2262
2263         stopPropagation: function(ev) {
2264             ev = ev.browserEvent || ev;
2265             if (ev.stopPropagation) {
2266                 ev.stopPropagation();
2267             } else {
2268                 ev.cancelBubble = true;
2269             }
2270         },
2271
2272
2273         preventDefault: function(ev) {
2274             ev = ev.browserEvent || ev;
2275             if(ev.preventDefault) {
2276                 ev.preventDefault();
2277             } else {
2278                 ev.returnValue = false;
2279             }
2280         },
2281
2282
2283         getEvent: function(e) {
2284             var ev = e || window.event;
2285             if (!ev) {
2286                 var c = this.getEvent.caller;
2287                 while (c) {
2288                     ev = c.arguments[0];
2289                     if (ev && Event == ev.constructor) {
2290                         break;
2291                     }
2292                     c = c.caller;
2293                 }
2294             }
2295             return ev;
2296         },
2297
2298
2299         getCharCode: function(ev) {
2300             ev = ev.browserEvent || ev;
2301             return ev.charCode || ev.keyCode || 0;
2302         },
2303
2304
2305         _getCacheIndex: function(el, eventName, fn) {
2306             for (var i = 0,len = listeners.length; i < len; ++i) {
2307                 var li = listeners[i];
2308                 if (li &&
2309                     li[this.FN] == fn &&
2310                     li[this.EL] == el &&
2311                     li[this.TYPE] == eventName) {
2312                     return i;
2313                 }
2314             }
2315
2316             return -1;
2317         },
2318
2319
2320         elCache: {},
2321
2322
2323         getEl: function(id) {
2324             return document.getElementById(id);
2325         },
2326
2327
2328         clearCache: function() {
2329         },
2330
2331
2332         _load: function(e) {
2333             loadComplete = true;
2334             var EU = Roo.lib.Event;
2335
2336
2337             if (Roo.isIE) {
2338                 EU.doRemove(window, "load", EU._load);
2339             }
2340         },
2341
2342
2343         _tryPreloadAttach: function() {
2344
2345             if (this.locked) {
2346                 return false;
2347             }
2348
2349             this.locked = true;
2350
2351
2352             var tryAgain = !loadComplete;
2353             if (!tryAgain) {
2354                 tryAgain = (retryCount > 0);
2355             }
2356
2357
2358             var notAvail = [];
2359             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2360                 var item = onAvailStack[i];
2361                 if (item) {
2362                     var el = this.getEl(item.id);
2363
2364                     if (el) {
2365                         if (!item.checkReady ||
2366                             loadComplete ||
2367                             el.nextSibling ||
2368                             (document && document.body)) {
2369
2370                             var scope = el;
2371                             if (item.override) {
2372                                 if (item.override === true) {
2373                                     scope = item.obj;
2374                                 } else {
2375                                     scope = item.override;
2376                                 }
2377                             }
2378                             item.fn.call(scope, item.obj);
2379                             onAvailStack[i] = null;
2380                         }
2381                     } else {
2382                         notAvail.push(item);
2383                     }
2384                 }
2385             }
2386
2387             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2388
2389             if (tryAgain) {
2390
2391                 this.startInterval();
2392             } else {
2393                 clearInterval(this._interval);
2394                 this._interval = null;
2395             }
2396
2397             this.locked = false;
2398
2399             return true;
2400
2401         },
2402
2403
2404         purgeElement: function(el, recurse, eventName) {
2405             var elListeners = this.getListeners(el, eventName);
2406             if (elListeners) {
2407                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2408                     var l = elListeners[i];
2409                     this.removeListener(el, l.type, l.fn);
2410                 }
2411             }
2412
2413             if (recurse && el && el.childNodes) {
2414                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2415                     this.purgeElement(el.childNodes[i], recurse, eventName);
2416                 }
2417             }
2418         },
2419
2420
2421         getListeners: function(el, eventName) {
2422             var results = [], searchLists;
2423             if (!eventName) {
2424                 searchLists = [listeners, unloadListeners];
2425             } else if (eventName == "unload") {
2426                 searchLists = [unloadListeners];
2427             } else {
2428                 searchLists = [listeners];
2429             }
2430
2431             for (var j = 0; j < searchLists.length; ++j) {
2432                 var searchList = searchLists[j];
2433                 if (searchList && searchList.length > 0) {
2434                     for (var i = 0,len = searchList.length; i < len; ++i) {
2435                         var l = searchList[i];
2436                         if (l && l[this.EL] === el &&
2437                             (!eventName || eventName === l[this.TYPE])) {
2438                             results.push({
2439                                 type:   l[this.TYPE],
2440                                 fn:     l[this.FN],
2441                                 obj:    l[this.OBJ],
2442                                 adjust: l[this.ADJ_SCOPE],
2443                                 index:  i
2444                             });
2445                         }
2446                     }
2447                 }
2448             }
2449
2450             return (results.length) ? results : null;
2451         },
2452
2453
2454         _unload: function(e) {
2455
2456             var EU = Roo.lib.Event, i, j, l, len, index;
2457
2458             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2459                 l = unloadListeners[i];
2460                 if (l) {
2461                     var scope = window;
2462                     if (l[EU.ADJ_SCOPE]) {
2463                         if (l[EU.ADJ_SCOPE] === true) {
2464                             scope = l[EU.OBJ];
2465                         } else {
2466                             scope = l[EU.ADJ_SCOPE];
2467                         }
2468                     }
2469                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2470                     unloadListeners[i] = null;
2471                     l = null;
2472                     scope = null;
2473                 }
2474             }
2475
2476             unloadListeners = null;
2477
2478             if (listeners && listeners.length > 0) {
2479                 j = listeners.length;
2480                 while (j) {
2481                     index = j - 1;
2482                     l = listeners[index];
2483                     if (l) {
2484                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2485                                 l[EU.FN], index);
2486                     }
2487                     j = j - 1;
2488                 }
2489                 l = null;
2490
2491                 EU.clearCache();
2492             }
2493
2494             EU.doRemove(window, "unload", EU._unload);
2495
2496         },
2497
2498
2499         getScroll: function() {
2500             var dd = document.documentElement, db = document.body;
2501             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2502                 return [dd.scrollTop, dd.scrollLeft];
2503             } else if (db) {
2504                 return [db.scrollTop, db.scrollLeft];
2505             } else {
2506                 return [0, 0];
2507             }
2508         },
2509
2510
2511         doAdd: function () {
2512             if (window.addEventListener) {
2513                 return function(el, eventName, fn, capture) {
2514                     el.addEventListener(eventName, fn, (capture));
2515                 };
2516             } else if (window.attachEvent) {
2517                 return function(el, eventName, fn, capture) {
2518                     el.attachEvent("on" + eventName, fn);
2519                 };
2520             } else {
2521                 return function() {
2522                 };
2523             }
2524         }(),
2525
2526
2527         doRemove: function() {
2528             if (window.removeEventListener) {
2529                 return function (el, eventName, fn, capture) {
2530                     el.removeEventListener(eventName, fn, (capture));
2531                 };
2532             } else if (window.detachEvent) {
2533                 return function (el, eventName, fn) {
2534                     el.detachEvent("on" + eventName, fn);
2535                 };
2536             } else {
2537                 return function() {
2538                 };
2539             }
2540         }()
2541     };
2542     
2543 }();
2544 (function() {     
2545    
2546     var E = Roo.lib.Event;
2547     E.on = E.addListener;
2548     E.un = E.removeListener;
2549
2550     if (document && document.body) {
2551         E._load();
2552     } else {
2553         E.doAdd(window, "load", E._load);
2554     }
2555     E.doAdd(window, "unload", E._unload);
2556     E._tryPreloadAttach();
2557 })();
2558
2559 /*
2560  * Portions of this file are based on pieces of Yahoo User Interface Library
2561  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2562  * YUI licensed under the BSD License:
2563  * http://developer.yahoo.net/yui/license.txt
2564  * <script type="text/javascript">
2565  *
2566  */
2567
2568 (function() {
2569     /**
2570      * @class Roo.lib.Ajax
2571      *
2572      */
2573     Roo.lib.Ajax = {
2574         /**
2575          * @static 
2576          */
2577         request : function(method, uri, cb, data, options) {
2578             if(options){
2579                 var hs = options.headers;
2580                 if(hs){
2581                     for(var h in hs){
2582                         if(hs.hasOwnProperty(h)){
2583                             this.initHeader(h, hs[h], false);
2584                         }
2585                     }
2586                 }
2587                 if(options.xmlData){
2588                     this.initHeader('Content-Type', 'text/xml', false);
2589                     method = 'POST';
2590                     data = options.xmlData;
2591                 }
2592             }
2593
2594             return this.asyncRequest(method, uri, cb, data);
2595         },
2596
2597         serializeForm : function(form) {
2598             if(typeof form == 'string') {
2599                 form = (document.getElementById(form) || document.forms[form]);
2600             }
2601
2602             var el, name, val, disabled, data = '', hasSubmit = false;
2603             for (var i = 0; i < form.elements.length; i++) {
2604                 el = form.elements[i];
2605                 disabled = form.elements[i].disabled;
2606                 name = form.elements[i].name;
2607                 val = form.elements[i].value;
2608
2609                 if (!disabled && name){
2610                     switch (el.type)
2611                             {
2612                         case 'select-one':
2613                         case 'select-multiple':
2614                             for (var j = 0; j < el.options.length; j++) {
2615                                 if (el.options[j].selected) {
2616                                     if (Roo.isIE) {
2617                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2618                                     }
2619                                     else {
2620                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2621                                     }
2622                                 }
2623                             }
2624                             break;
2625                         case 'radio':
2626                         case 'checkbox':
2627                             if (el.checked) {
2628                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2629                             }
2630                             break;
2631                         case 'file':
2632
2633                         case undefined:
2634
2635                         case 'reset':
2636
2637                         case 'button':
2638
2639                             break;
2640                         case 'submit':
2641                             if(hasSubmit == false) {
2642                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2643                                 hasSubmit = true;
2644                             }
2645                             break;
2646                         default:
2647                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2648                             break;
2649                     }
2650                 }
2651             }
2652             data = data.substr(0, data.length - 1);
2653             return data;
2654         },
2655
2656         headers:{},
2657
2658         hasHeaders:false,
2659
2660         useDefaultHeader:true,
2661
2662         defaultPostHeader:'application/x-www-form-urlencoded',
2663
2664         useDefaultXhrHeader:true,
2665
2666         defaultXhrHeader:'XMLHttpRequest',
2667
2668         hasDefaultHeaders:true,
2669
2670         defaultHeaders:{},
2671
2672         poll:{},
2673
2674         timeout:{},
2675
2676         pollInterval:50,
2677
2678         transactionId:0,
2679
2680         setProgId:function(id)
2681         {
2682             this.activeX.unshift(id);
2683         },
2684
2685         setDefaultPostHeader:function(b)
2686         {
2687             this.useDefaultHeader = b;
2688         },
2689
2690         setDefaultXhrHeader:function(b)
2691         {
2692             this.useDefaultXhrHeader = b;
2693         },
2694
2695         setPollingInterval:function(i)
2696         {
2697             if (typeof i == 'number' && isFinite(i)) {
2698                 this.pollInterval = i;
2699             }
2700         },
2701
2702         createXhrObject:function(transactionId)
2703         {
2704             var obj,http;
2705             try
2706             {
2707
2708                 http = new XMLHttpRequest();
2709
2710                 obj = { conn:http, tId:transactionId };
2711             }
2712             catch(e)
2713             {
2714                 for (var i = 0; i < this.activeX.length; ++i) {
2715                     try
2716                     {
2717
2718                         http = new ActiveXObject(this.activeX[i]);
2719
2720                         obj = { conn:http, tId:transactionId };
2721                         break;
2722                     }
2723                     catch(e) {
2724                     }
2725                 }
2726             }
2727             finally
2728             {
2729                 return obj;
2730             }
2731         },
2732
2733         getConnectionObject:function()
2734         {
2735             var o;
2736             var tId = this.transactionId;
2737
2738             try
2739             {
2740                 o = this.createXhrObject(tId);
2741                 if (o) {
2742                     this.transactionId++;
2743                 }
2744             }
2745             catch(e) {
2746             }
2747             finally
2748             {
2749                 return o;
2750             }
2751         },
2752
2753         asyncRequest:function(method, uri, callback, postData)
2754         {
2755             var o = this.getConnectionObject();
2756
2757             if (!o) {
2758                 return null;
2759             }
2760             else {
2761                 o.conn.open(method, uri, true);
2762
2763                 if (this.useDefaultXhrHeader) {
2764                     if (!this.defaultHeaders['X-Requested-With']) {
2765                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2766                     }
2767                 }
2768
2769                 if(postData && this.useDefaultHeader){
2770                     this.initHeader('Content-Type', this.defaultPostHeader);
2771                 }
2772
2773                  if (this.hasDefaultHeaders || this.hasHeaders) {
2774                     this.setHeader(o);
2775                 }
2776
2777                 this.handleReadyState(o, callback);
2778                 o.conn.send(postData || null);
2779
2780                 return o;
2781             }
2782         },
2783
2784         handleReadyState:function(o, callback)
2785         {
2786             var oConn = this;
2787
2788             if (callback && callback.timeout) {
2789                 
2790                 this.timeout[o.tId] = window.setTimeout(function() {
2791                     oConn.abort(o, callback, true);
2792                 }, callback.timeout);
2793             }
2794
2795             this.poll[o.tId] = window.setInterval(
2796                     function() {
2797                         if (o.conn && o.conn.readyState == 4) {
2798                             window.clearInterval(oConn.poll[o.tId]);
2799                             delete oConn.poll[o.tId];
2800
2801                             if(callback && callback.timeout) {
2802                                 window.clearTimeout(oConn.timeout[o.tId]);
2803                                 delete oConn.timeout[o.tId];
2804                             }
2805
2806                             oConn.handleTransactionResponse(o, callback);
2807                         }
2808                     }
2809                     , this.pollInterval);
2810         },
2811
2812         handleTransactionResponse:function(o, callback, isAbort)
2813         {
2814
2815             if (!callback) {
2816                 this.releaseObject(o);
2817                 return;
2818             }
2819
2820             var httpStatus, responseObject;
2821
2822             try
2823             {
2824                 if (o.conn.status !== undefined && o.conn.status != 0) {
2825                     httpStatus = o.conn.status;
2826                 }
2827                 else {
2828                     httpStatus = 13030;
2829                 }
2830             }
2831             catch(e) {
2832
2833
2834                 httpStatus = 13030;
2835             }
2836
2837             if (httpStatus >= 200 && httpStatus < 300) {
2838                 responseObject = this.createResponseObject(o, callback.argument);
2839                 if (callback.success) {
2840                     if (!callback.scope) {
2841                         callback.success(responseObject);
2842                     }
2843                     else {
2844
2845
2846                         callback.success.apply(callback.scope, [responseObject]);
2847                     }
2848                 }
2849             }
2850             else {
2851                 switch (httpStatus) {
2852
2853                     case 12002:
2854                     case 12029:
2855                     case 12030:
2856                     case 12031:
2857                     case 12152:
2858                     case 13030:
2859                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2860                         if (callback.failure) {
2861                             if (!callback.scope) {
2862                                 callback.failure(responseObject);
2863                             }
2864                             else {
2865                                 callback.failure.apply(callback.scope, [responseObject]);
2866                             }
2867                         }
2868                         break;
2869                     default:
2870                         responseObject = this.createResponseObject(o, callback.argument);
2871                         if (callback.failure) {
2872                             if (!callback.scope) {
2873                                 callback.failure(responseObject);
2874                             }
2875                             else {
2876                                 callback.failure.apply(callback.scope, [responseObject]);
2877                             }
2878                         }
2879                 }
2880             }
2881
2882             this.releaseObject(o);
2883             responseObject = null;
2884         },
2885
2886         createResponseObject:function(o, callbackArg)
2887         {
2888             var obj = {};
2889             var headerObj = {};
2890
2891             try
2892             {
2893                 var headerStr = o.conn.getAllResponseHeaders();
2894                 var header = headerStr.split('\n');
2895                 for (var i = 0; i < header.length; i++) {
2896                     var delimitPos = header[i].indexOf(':');
2897                     if (delimitPos != -1) {
2898                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2899                     }
2900                 }
2901             }
2902             catch(e) {
2903             }
2904
2905             obj.tId = o.tId;
2906             obj.status = o.conn.status;
2907             obj.statusText = o.conn.statusText;
2908             obj.getResponseHeader = headerObj;
2909             obj.getAllResponseHeaders = headerStr;
2910             obj.responseText = o.conn.responseText;
2911             obj.responseXML = o.conn.responseXML;
2912
2913             if (typeof callbackArg !== undefined) {
2914                 obj.argument = callbackArg;
2915             }
2916
2917             return obj;
2918         },
2919
2920         createExceptionObject:function(tId, callbackArg, isAbort)
2921         {
2922             var COMM_CODE = 0;
2923             var COMM_ERROR = 'communication failure';
2924             var ABORT_CODE = -1;
2925             var ABORT_ERROR = 'transaction aborted';
2926
2927             var obj = {};
2928
2929             obj.tId = tId;
2930             if (isAbort) {
2931                 obj.status = ABORT_CODE;
2932                 obj.statusText = ABORT_ERROR;
2933             }
2934             else {
2935                 obj.status = COMM_CODE;
2936                 obj.statusText = COMM_ERROR;
2937             }
2938
2939             if (callbackArg) {
2940                 obj.argument = callbackArg;
2941             }
2942
2943             return obj;
2944         },
2945
2946         initHeader:function(label, value, isDefault)
2947         {
2948             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2949
2950             if (headerObj[label] === undefined) {
2951                 headerObj[label] = value;
2952             }
2953             else {
2954
2955
2956                 headerObj[label] = value + "," + headerObj[label];
2957             }
2958
2959             if (isDefault) {
2960                 this.hasDefaultHeaders = true;
2961             }
2962             else {
2963                 this.hasHeaders = true;
2964             }
2965         },
2966
2967
2968         setHeader:function(o)
2969         {
2970             if (this.hasDefaultHeaders) {
2971                 for (var prop in this.defaultHeaders) {
2972                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2973                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2974                     }
2975                 }
2976             }
2977
2978             if (this.hasHeaders) {
2979                 for (var prop in this.headers) {
2980                     if (this.headers.hasOwnProperty(prop)) {
2981                         o.conn.setRequestHeader(prop, this.headers[prop]);
2982                     }
2983                 }
2984                 this.headers = {};
2985                 this.hasHeaders = false;
2986             }
2987         },
2988
2989         resetDefaultHeaders:function() {
2990             delete this.defaultHeaders;
2991             this.defaultHeaders = {};
2992             this.hasDefaultHeaders = false;
2993         },
2994
2995         abort:function(o, callback, isTimeout)
2996         {
2997             if(this.isCallInProgress(o)) {
2998                 o.conn.abort();
2999                 window.clearInterval(this.poll[o.tId]);
3000                 delete this.poll[o.tId];
3001                 if (isTimeout) {
3002                     delete this.timeout[o.tId];
3003                 }
3004
3005                 this.handleTransactionResponse(o, callback, true);
3006
3007                 return true;
3008             }
3009             else {
3010                 return false;
3011             }
3012         },
3013
3014
3015         isCallInProgress:function(o)
3016         {
3017             if (o && o.conn) {
3018                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3019             }
3020             else {
3021
3022                 return false;
3023             }
3024         },
3025
3026
3027         releaseObject:function(o)
3028         {
3029
3030             o.conn = null;
3031
3032             o = null;
3033         },
3034
3035         activeX:[
3036         'MSXML2.XMLHTTP.3.0',
3037         'MSXML2.XMLHTTP',
3038         'Microsoft.XMLHTTP'
3039         ]
3040
3041
3042     };
3043 })();/*
3044  * Portions of this file are based on pieces of Yahoo User Interface Library
3045  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3046  * YUI licensed under the BSD License:
3047  * http://developer.yahoo.net/yui/license.txt
3048  * <script type="text/javascript">
3049  *
3050  */
3051
3052 Roo.lib.Region = function(t, r, b, l) {
3053     this.top = t;
3054     this[1] = t;
3055     this.right = r;
3056     this.bottom = b;
3057     this.left = l;
3058     this[0] = l;
3059 };
3060
3061
3062 Roo.lib.Region.prototype = {
3063     contains : function(region) {
3064         return ( region.left >= this.left &&
3065                  region.right <= this.right &&
3066                  region.top >= this.top &&
3067                  region.bottom <= this.bottom    );
3068
3069     },
3070
3071     getArea : function() {
3072         return ( (this.bottom - this.top) * (this.right - this.left) );
3073     },
3074
3075     intersect : function(region) {
3076         var t = Math.max(this.top, region.top);
3077         var r = Math.min(this.right, region.right);
3078         var b = Math.min(this.bottom, region.bottom);
3079         var l = Math.max(this.left, region.left);
3080
3081         if (b >= t && r >= l) {
3082             return new Roo.lib.Region(t, r, b, l);
3083         } else {
3084             return null;
3085         }
3086     },
3087     union : function(region) {
3088         var t = Math.min(this.top, region.top);
3089         var r = Math.max(this.right, region.right);
3090         var b = Math.max(this.bottom, region.bottom);
3091         var l = Math.min(this.left, region.left);
3092
3093         return new Roo.lib.Region(t, r, b, l);
3094     },
3095
3096     adjust : function(t, l, b, r) {
3097         this.top += t;
3098         this.left += l;
3099         this.right += r;
3100         this.bottom += b;
3101         return this;
3102     }
3103 };
3104
3105 Roo.lib.Region.getRegion = function(el) {
3106     var p = Roo.lib.Dom.getXY(el);
3107
3108     var t = p[1];
3109     var r = p[0] + el.offsetWidth;
3110     var b = p[1] + el.offsetHeight;
3111     var l = p[0];
3112
3113     return new Roo.lib.Region(t, r, b, l);
3114 };
3115 /*
3116  * Portions of this file are based on pieces of Yahoo User Interface Library
3117  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3118  * YUI licensed under the BSD License:
3119  * http://developer.yahoo.net/yui/license.txt
3120  * <script type="text/javascript">
3121  *
3122  */
3123 //@@dep Roo.lib.Region
3124
3125
3126 Roo.lib.Point = function(x, y) {
3127     if (x instanceof Array) {
3128         y = x[1];
3129         x = x[0];
3130     }
3131     this.x = this.right = this.left = this[0] = x;
3132     this.y = this.top = this.bottom = this[1] = y;
3133 };
3134
3135 Roo.lib.Point.prototype = new Roo.lib.Region();
3136 /*
3137  * Portions of this file are based on pieces of Yahoo User Interface Library
3138  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139  * YUI licensed under the BSD License:
3140  * http://developer.yahoo.net/yui/license.txt
3141  * <script type="text/javascript">
3142  *
3143  */
3144  
3145 (function() {   
3146
3147     Roo.lib.Anim = {
3148         scroll : function(el, args, duration, easing, cb, scope) {
3149             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3150         },
3151
3152         motion : function(el, args, duration, easing, cb, scope) {
3153             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3154         },
3155
3156         color : function(el, args, duration, easing, cb, scope) {
3157             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3158         },
3159
3160         run : function(el, args, duration, easing, cb, scope, type) {
3161             type = type || Roo.lib.AnimBase;
3162             if (typeof easing == "string") {
3163                 easing = Roo.lib.Easing[easing];
3164             }
3165             var anim = new type(el, args, duration, easing);
3166             anim.animateX(function() {
3167                 Roo.callback(cb, scope);
3168             });
3169             return anim;
3170         }
3171     };
3172 })();/*
3173  * Portions of this file are based on pieces of Yahoo User Interface Library
3174  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3175  * YUI licensed under the BSD License:
3176  * http://developer.yahoo.net/yui/license.txt
3177  * <script type="text/javascript">
3178  *
3179  */
3180
3181 (function() {    
3182     var libFlyweight;
3183     
3184     function fly(el) {
3185         if (!libFlyweight) {
3186             libFlyweight = new Roo.Element.Flyweight();
3187         }
3188         libFlyweight.dom = el;
3189         return libFlyweight;
3190     }
3191
3192     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3193     
3194    
3195     
3196     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3197         if (el) {
3198             this.init(el, attributes, duration, method);
3199         }
3200     };
3201
3202     Roo.lib.AnimBase.fly = fly;
3203     
3204     
3205     
3206     Roo.lib.AnimBase.prototype = {
3207
3208         toString: function() {
3209             var el = this.getEl();
3210             var id = el.id || el.tagName;
3211             return ("Anim " + id);
3212         },
3213
3214         patterns: {
3215             noNegatives:        /width|height|opacity|padding/i,
3216             offsetAttribute:  /^((width|height)|(top|left))$/,
3217             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3218             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3219         },
3220
3221
3222         doMethod: function(attr, start, end) {
3223             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3224         },
3225
3226
3227         setAttribute: function(attr, val, unit) {
3228             if (this.patterns.noNegatives.test(attr)) {
3229                 val = (val > 0) ? val : 0;
3230             }
3231
3232             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3233         },
3234
3235
3236         getAttribute: function(attr) {
3237             var el = this.getEl();
3238             var val = fly(el).getStyle(attr);
3239
3240             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3241                 return parseFloat(val);
3242             }
3243
3244             var a = this.patterns.offsetAttribute.exec(attr) || [];
3245             var pos = !!( a[3] );
3246             var box = !!( a[2] );
3247
3248
3249             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3250                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3251             } else {
3252                 val = 0;
3253             }
3254
3255             return val;
3256         },
3257
3258
3259         getDefaultUnit: function(attr) {
3260             if (this.patterns.defaultUnit.test(attr)) {
3261                 return 'px';
3262             }
3263
3264             return '';
3265         },
3266
3267         animateX : function(callback, scope) {
3268             var f = function() {
3269                 this.onComplete.removeListener(f);
3270                 if (typeof callback == "function") {
3271                     callback.call(scope || this, this);
3272                 }
3273             };
3274             this.onComplete.addListener(f, this);
3275             this.animate();
3276         },
3277
3278
3279         setRuntimeAttribute: function(attr) {
3280             var start;
3281             var end;
3282             var attributes = this.attributes;
3283
3284             this.runtimeAttributes[attr] = {};
3285
3286             var isset = function(prop) {
3287                 return (typeof prop !== 'undefined');
3288             };
3289
3290             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3291                 return false;
3292             }
3293
3294             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3295
3296
3297             if (isset(attributes[attr]['to'])) {
3298                 end = attributes[attr]['to'];
3299             } else if (isset(attributes[attr]['by'])) {
3300                 if (start.constructor == Array) {
3301                     end = [];
3302                     for (var i = 0, len = start.length; i < len; ++i) {
3303                         end[i] = start[i] + attributes[attr]['by'][i];
3304                     }
3305                 } else {
3306                     end = start + attributes[attr]['by'];
3307                 }
3308             }
3309
3310             this.runtimeAttributes[attr].start = start;
3311             this.runtimeAttributes[attr].end = end;
3312
3313
3314             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3315         },
3316
3317
3318         init: function(el, attributes, duration, method) {
3319
3320             var isAnimated = false;
3321
3322
3323             var startTime = null;
3324
3325
3326             var actualFrames = 0;
3327
3328
3329             el = Roo.getDom(el);
3330
3331
3332             this.attributes = attributes || {};
3333
3334
3335             this.duration = duration || 1;
3336
3337
3338             this.method = method || Roo.lib.Easing.easeNone;
3339
3340
3341             this.useSeconds = true;
3342
3343
3344             this.currentFrame = 0;
3345
3346
3347             this.totalFrames = Roo.lib.AnimMgr.fps;
3348
3349
3350             this.getEl = function() {
3351                 return el;
3352             };
3353
3354
3355             this.isAnimated = function() {
3356                 return isAnimated;
3357             };
3358
3359
3360             this.getStartTime = function() {
3361                 return startTime;
3362             };
3363
3364             this.runtimeAttributes = {};
3365
3366
3367             this.animate = function() {
3368                 if (this.isAnimated()) {
3369                     return false;
3370                 }
3371
3372                 this.currentFrame = 0;
3373
3374                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3375
3376                 Roo.lib.AnimMgr.registerElement(this);
3377             };
3378
3379
3380             this.stop = function(finish) {
3381                 if (finish) {
3382                     this.currentFrame = this.totalFrames;
3383                     this._onTween.fire();
3384                 }
3385                 Roo.lib.AnimMgr.stop(this);
3386             };
3387
3388             var onStart = function() {
3389                 this.onStart.fire();
3390
3391                 this.runtimeAttributes = {};
3392                 for (var attr in this.attributes) {
3393                     this.setRuntimeAttribute(attr);
3394                 }
3395
3396                 isAnimated = true;
3397                 actualFrames = 0;
3398                 startTime = new Date();
3399             };
3400
3401
3402             var onTween = function() {
3403                 var data = {
3404                     duration: new Date() - this.getStartTime(),
3405                     currentFrame: this.currentFrame
3406                 };
3407
3408                 data.toString = function() {
3409                     return (
3410                             'duration: ' + data.duration +
3411                             ', currentFrame: ' + data.currentFrame
3412                             );
3413                 };
3414
3415                 this.onTween.fire(data);
3416
3417                 var runtimeAttributes = this.runtimeAttributes;
3418
3419                 for (var attr in runtimeAttributes) {
3420                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3421                 }
3422
3423                 actualFrames += 1;
3424             };
3425
3426             var onComplete = function() {
3427                 var actual_duration = (new Date() - startTime) / 1000 ;
3428
3429                 var data = {
3430                     duration: actual_duration,
3431                     frames: actualFrames,
3432                     fps: actualFrames / actual_duration
3433                 };
3434
3435                 data.toString = function() {
3436                     return (
3437                             'duration: ' + data.duration +
3438                             ', frames: ' + data.frames +
3439                             ', fps: ' + data.fps
3440                             );
3441                 };
3442
3443                 isAnimated = false;
3444                 actualFrames = 0;
3445                 this.onComplete.fire(data);
3446             };
3447
3448
3449             this._onStart = new Roo.util.Event(this);
3450             this.onStart = new Roo.util.Event(this);
3451             this.onTween = new Roo.util.Event(this);
3452             this._onTween = new Roo.util.Event(this);
3453             this.onComplete = new Roo.util.Event(this);
3454             this._onComplete = new Roo.util.Event(this);
3455             this._onStart.addListener(onStart);
3456             this._onTween.addListener(onTween);
3457             this._onComplete.addListener(onComplete);
3458         }
3459     };
3460 })();
3461 /*
3462  * Portions of this file are based on pieces of Yahoo User Interface Library
3463  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3464  * YUI licensed under the BSD License:
3465  * http://developer.yahoo.net/yui/license.txt
3466  * <script type="text/javascript">
3467  *
3468  */
3469
3470 Roo.lib.AnimMgr = new function() {
3471
3472     var thread = null;
3473
3474
3475     var queue = [];
3476
3477
3478     var tweenCount = 0;
3479
3480
3481     this.fps = 1000;
3482
3483
3484     this.delay = 1;
3485
3486
3487     this.registerElement = function(tween) {
3488         queue[queue.length] = tween;
3489         tweenCount += 1;
3490         tween._onStart.fire();
3491         this.start();
3492     };
3493
3494
3495     this.unRegister = function(tween, index) {
3496         tween._onComplete.fire();
3497         index = index || getIndex(tween);
3498         if (index != -1) {
3499             queue.splice(index, 1);
3500         }
3501
3502         tweenCount -= 1;
3503         if (tweenCount <= 0) {
3504             this.stop();
3505         }
3506     };
3507
3508
3509     this.start = function() {
3510         if (thread === null) {
3511             thread = setInterval(this.run, this.delay);
3512         }
3513     };
3514
3515
3516     this.stop = function(tween) {
3517         if (!tween) {
3518             clearInterval(thread);
3519
3520             for (var i = 0, len = queue.length; i < len; ++i) {
3521                 if (queue[0].isAnimated()) {
3522                     this.unRegister(queue[0], 0);
3523                 }
3524             }
3525
3526             queue = [];
3527             thread = null;
3528             tweenCount = 0;
3529         }
3530         else {
3531             this.unRegister(tween);
3532         }
3533     };
3534
3535
3536     this.run = function() {
3537         for (var i = 0, len = queue.length; i < len; ++i) {
3538             var tween = queue[i];
3539             if (!tween || !tween.isAnimated()) {
3540                 continue;
3541             }
3542
3543             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3544             {
3545                 tween.currentFrame += 1;
3546
3547                 if (tween.useSeconds) {
3548                     correctFrame(tween);
3549                 }
3550                 tween._onTween.fire();
3551             }
3552             else {
3553                 Roo.lib.AnimMgr.stop(tween, i);
3554             }
3555         }
3556     };
3557
3558     var getIndex = function(anim) {
3559         for (var i = 0, len = queue.length; i < len; ++i) {
3560             if (queue[i] == anim) {
3561                 return i;
3562             }
3563         }
3564         return -1;
3565     };
3566
3567
3568     var correctFrame = function(tween) {
3569         var frames = tween.totalFrames;
3570         var frame = tween.currentFrame;
3571         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3572         var elapsed = (new Date() - tween.getStartTime());
3573         var tweak = 0;
3574
3575         if (elapsed < tween.duration * 1000) {
3576             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3577         } else {
3578             tweak = frames - (frame + 1);
3579         }
3580         if (tweak > 0 && isFinite(tweak)) {
3581             if (tween.currentFrame + tweak >= frames) {
3582                 tweak = frames - (frame + 1);
3583             }
3584
3585             tween.currentFrame += tweak;
3586         }
3587     };
3588 };
3589
3590     /*
3591  * Portions of this file are based on pieces of Yahoo User Interface Library
3592  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3593  * YUI licensed under the BSD License:
3594  * http://developer.yahoo.net/yui/license.txt
3595  * <script type="text/javascript">
3596  *
3597  */
3598 Roo.lib.Bezier = new function() {
3599
3600         this.getPosition = function(points, t) {
3601             var n = points.length;
3602             var tmp = [];
3603
3604             for (var i = 0; i < n; ++i) {
3605                 tmp[i] = [points[i][0], points[i][1]];
3606             }
3607
3608             for (var j = 1; j < n; ++j) {
3609                 for (i = 0; i < n - j; ++i) {
3610                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3611                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3612                 }
3613             }
3614
3615             return [ tmp[0][0], tmp[0][1] ];
3616
3617         };
3618     };/*
3619  * Portions of this file are based on pieces of Yahoo User Interface Library
3620  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3621  * YUI licensed under the BSD License:
3622  * http://developer.yahoo.net/yui/license.txt
3623  * <script type="text/javascript">
3624  *
3625  */
3626 (function() {
3627
3628     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3629         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3630     };
3631
3632     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3633
3634     var fly = Roo.lib.AnimBase.fly;
3635     var Y = Roo.lib;
3636     var superclass = Y.ColorAnim.superclass;
3637     var proto = Y.ColorAnim.prototype;
3638
3639     proto.toString = function() {
3640         var el = this.getEl();
3641         var id = el.id || el.tagName;
3642         return ("ColorAnim " + id);
3643     };
3644
3645     proto.patterns.color = /color$/i;
3646     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3647     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3648     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3649     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3650
3651
3652     proto.parseColor = function(s) {
3653         if (s.length == 3) {
3654             return s;
3655         }
3656
3657         var c = this.patterns.hex.exec(s);
3658         if (c && c.length == 4) {
3659             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3660         }
3661
3662         c = this.patterns.rgb.exec(s);
3663         if (c && c.length == 4) {
3664             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3665         }
3666
3667         c = this.patterns.hex3.exec(s);
3668         if (c && c.length == 4) {
3669             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3670         }
3671
3672         return null;
3673     };
3674     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3675     proto.getAttribute = function(attr) {
3676         var el = this.getEl();
3677         if (this.patterns.color.test(attr)) {
3678             var val = fly(el).getStyle(attr);
3679
3680             if (this.patterns.transparent.test(val)) {
3681                 var parent = el.parentNode;
3682                 val = fly(parent).getStyle(attr);
3683
3684                 while (parent && this.patterns.transparent.test(val)) {
3685                     parent = parent.parentNode;
3686                     val = fly(parent).getStyle(attr);
3687                     if (parent.tagName.toUpperCase() == 'HTML') {
3688                         val = '#fff';
3689                     }
3690                 }
3691             }
3692         } else {
3693             val = superclass.getAttribute.call(this, attr);
3694         }
3695
3696         return val;
3697     };
3698     proto.getAttribute = function(attr) {
3699         var el = this.getEl();
3700         if (this.patterns.color.test(attr)) {
3701             var val = fly(el).getStyle(attr);
3702
3703             if (this.patterns.transparent.test(val)) {
3704                 var parent = el.parentNode;
3705                 val = fly(parent).getStyle(attr);
3706
3707                 while (parent && this.patterns.transparent.test(val)) {
3708                     parent = parent.parentNode;
3709                     val = fly(parent).getStyle(attr);
3710                     if (parent.tagName.toUpperCase() == 'HTML') {
3711                         val = '#fff';
3712                     }
3713                 }
3714             }
3715         } else {
3716             val = superclass.getAttribute.call(this, attr);
3717         }
3718
3719         return val;
3720     };
3721
3722     proto.doMethod = function(attr, start, end) {
3723         var val;
3724
3725         if (this.patterns.color.test(attr)) {
3726             val = [];
3727             for (var i = 0, len = start.length; i < len; ++i) {
3728                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3729             }
3730
3731             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3732         }
3733         else {
3734             val = superclass.doMethod.call(this, attr, start, end);
3735         }
3736
3737         return val;
3738     };
3739
3740     proto.setRuntimeAttribute = function(attr) {
3741         superclass.setRuntimeAttribute.call(this, attr);
3742
3743         if (this.patterns.color.test(attr)) {
3744             var attributes = this.attributes;
3745             var start = this.parseColor(this.runtimeAttributes[attr].start);
3746             var end = this.parseColor(this.runtimeAttributes[attr].end);
3747
3748             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3749                 end = this.parseColor(attributes[attr].by);
3750
3751                 for (var i = 0, len = start.length; i < len; ++i) {
3752                     end[i] = start[i] + end[i];
3753                 }
3754             }
3755
3756             this.runtimeAttributes[attr].start = start;
3757             this.runtimeAttributes[attr].end = end;
3758         }
3759     };
3760 })();
3761
3762 /*
3763  * Portions of this file are based on pieces of Yahoo User Interface Library
3764  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3765  * YUI licensed under the BSD License:
3766  * http://developer.yahoo.net/yui/license.txt
3767  * <script type="text/javascript">
3768  *
3769  */
3770 Roo.lib.Easing = {
3771
3772
3773     easeNone: function (t, b, c, d) {
3774         return c * t / d + b;
3775     },
3776
3777
3778     easeIn: function (t, b, c, d) {
3779         return c * (t /= d) * t + b;
3780     },
3781
3782
3783     easeOut: function (t, b, c, d) {
3784         return -c * (t /= d) * (t - 2) + b;
3785     },
3786
3787
3788     easeBoth: function (t, b, c, d) {
3789         if ((t /= d / 2) < 1) {
3790             return c / 2 * t * t + b;
3791         }
3792
3793         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3794     },
3795
3796
3797     easeInStrong: function (t, b, c, d) {
3798         return c * (t /= d) * t * t * t + b;
3799     },
3800
3801
3802     easeOutStrong: function (t, b, c, d) {
3803         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3804     },
3805
3806
3807     easeBothStrong: function (t, b, c, d) {
3808         if ((t /= d / 2) < 1) {
3809             return c / 2 * t * t * t * t + b;
3810         }
3811
3812         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3813     },
3814
3815
3816
3817     elasticIn: function (t, b, c, d, a, p) {
3818         if (t == 0) {
3819             return b;
3820         }
3821         if ((t /= d) == 1) {
3822             return b + c;
3823         }
3824         if (!p) {
3825             p = d * .3;
3826         }
3827
3828         if (!a || a < Math.abs(c)) {
3829             a = c;
3830             var s = p / 4;
3831         }
3832         else {
3833             var s = p / (2 * Math.PI) * Math.asin(c / a);
3834         }
3835
3836         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3837     },
3838
3839
3840     elasticOut: function (t, b, c, d, a, p) {
3841         if (t == 0) {
3842             return b;
3843         }
3844         if ((t /= d) == 1) {
3845             return b + c;
3846         }
3847         if (!p) {
3848             p = d * .3;
3849         }
3850
3851         if (!a || a < Math.abs(c)) {
3852             a = c;
3853             var s = p / 4;
3854         }
3855         else {
3856             var s = p / (2 * Math.PI) * Math.asin(c / a);
3857         }
3858
3859         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3860     },
3861
3862
3863     elasticBoth: function (t, b, c, d, a, p) {
3864         if (t == 0) {
3865             return b;
3866         }
3867
3868         if ((t /= d / 2) == 2) {
3869             return b + c;
3870         }
3871
3872         if (!p) {
3873             p = d * (.3 * 1.5);
3874         }
3875
3876         if (!a || a < Math.abs(c)) {
3877             a = c;
3878             var s = p / 4;
3879         }
3880         else {
3881             var s = p / (2 * Math.PI) * Math.asin(c / a);
3882         }
3883
3884         if (t < 1) {
3885             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3886                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3887         }
3888         return a * Math.pow(2, -10 * (t -= 1)) *
3889                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3890     },
3891
3892
3893
3894     backIn: function (t, b, c, d, s) {
3895         if (typeof s == 'undefined') {
3896             s = 1.70158;
3897         }
3898         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3899     },
3900
3901
3902     backOut: function (t, b, c, d, s) {
3903         if (typeof s == 'undefined') {
3904             s = 1.70158;
3905         }
3906         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3907     },
3908
3909
3910     backBoth: function (t, b, c, d, s) {
3911         if (typeof s == 'undefined') {
3912             s = 1.70158;
3913         }
3914
3915         if ((t /= d / 2 ) < 1) {
3916             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3917         }
3918         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3919     },
3920
3921
3922     bounceIn: function (t, b, c, d) {
3923         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3924     },
3925
3926
3927     bounceOut: function (t, b, c, d) {
3928         if ((t /= d) < (1 / 2.75)) {
3929             return c * (7.5625 * t * t) + b;
3930         } else if (t < (2 / 2.75)) {
3931             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3932         } else if (t < (2.5 / 2.75)) {
3933             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3934         }
3935         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3936     },
3937
3938
3939     bounceBoth: function (t, b, c, d) {
3940         if (t < d / 2) {
3941             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3942         }
3943         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3944     }
3945 };/*
3946  * Portions of this file are based on pieces of Yahoo User Interface Library
3947  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3948  * YUI licensed under the BSD License:
3949  * http://developer.yahoo.net/yui/license.txt
3950  * <script type="text/javascript">
3951  *
3952  */
3953     (function() {
3954         Roo.lib.Motion = function(el, attributes, duration, method) {
3955             if (el) {
3956                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3957             }
3958         };
3959
3960         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3961
3962
3963         var Y = Roo.lib;
3964         var superclass = Y.Motion.superclass;
3965         var proto = Y.Motion.prototype;
3966
3967         proto.toString = function() {
3968             var el = this.getEl();
3969             var id = el.id || el.tagName;
3970             return ("Motion " + id);
3971         };
3972
3973         proto.patterns.points = /^points$/i;
3974
3975         proto.setAttribute = function(attr, val, unit) {
3976             if (this.patterns.points.test(attr)) {
3977                 unit = unit || 'px';
3978                 superclass.setAttribute.call(this, 'left', val[0], unit);
3979                 superclass.setAttribute.call(this, 'top', val[1], unit);
3980             } else {
3981                 superclass.setAttribute.call(this, attr, val, unit);
3982             }
3983         };
3984
3985         proto.getAttribute = function(attr) {
3986             if (this.patterns.points.test(attr)) {
3987                 var val = [
3988                         superclass.getAttribute.call(this, 'left'),
3989                         superclass.getAttribute.call(this, 'top')
3990                         ];
3991             } else {
3992                 val = superclass.getAttribute.call(this, attr);
3993             }
3994
3995             return val;
3996         };
3997
3998         proto.doMethod = function(attr, start, end) {
3999             var val = null;
4000
4001             if (this.patterns.points.test(attr)) {
4002                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4003                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4004             } else {
4005                 val = superclass.doMethod.call(this, attr, start, end);
4006             }
4007             return val;
4008         };
4009
4010         proto.setRuntimeAttribute = function(attr) {
4011             if (this.patterns.points.test(attr)) {
4012                 var el = this.getEl();
4013                 var attributes = this.attributes;
4014                 var start;
4015                 var control = attributes['points']['control'] || [];
4016                 var end;
4017                 var i, len;
4018
4019                 if (control.length > 0 && !(control[0] instanceof Array)) {
4020                     control = [control];
4021                 } else {
4022                     var tmp = [];
4023                     for (i = 0,len = control.length; i < len; ++i) {
4024                         tmp[i] = control[i];
4025                     }
4026                     control = tmp;
4027                 }
4028
4029                 Roo.fly(el).position();
4030
4031                 if (isset(attributes['points']['from'])) {
4032                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4033                 }
4034                 else {
4035                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4036                 }
4037
4038                 start = this.getAttribute('points');
4039
4040
4041                 if (isset(attributes['points']['to'])) {
4042                     end = translateValues.call(this, attributes['points']['to'], start);
4043
4044                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4045                     for (i = 0,len = control.length; i < len; ++i) {
4046                         control[i] = translateValues.call(this, control[i], start);
4047                     }
4048
4049
4050                 } else if (isset(attributes['points']['by'])) {
4051                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4052
4053                     for (i = 0,len = control.length; i < len; ++i) {
4054                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4055                     }
4056                 }
4057
4058                 this.runtimeAttributes[attr] = [start];
4059
4060                 if (control.length > 0) {
4061                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4062                 }
4063
4064                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4065             }
4066             else {
4067                 superclass.setRuntimeAttribute.call(this, attr);
4068             }
4069         };
4070
4071         var translateValues = function(val, start) {
4072             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4073             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4074
4075             return val;
4076         };
4077
4078         var isset = function(prop) {
4079             return (typeof prop !== 'undefined');
4080         };
4081     })();
4082 /*
4083  * Portions of this file are based on pieces of Yahoo User Interface Library
4084  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4085  * YUI licensed under the BSD License:
4086  * http://developer.yahoo.net/yui/license.txt
4087  * <script type="text/javascript">
4088  *
4089  */
4090     (function() {
4091         Roo.lib.Scroll = function(el, attributes, duration, method) {
4092             if (el) {
4093                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4094             }
4095         };
4096
4097         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4098
4099
4100         var Y = Roo.lib;
4101         var superclass = Y.Scroll.superclass;
4102         var proto = Y.Scroll.prototype;
4103
4104         proto.toString = function() {
4105             var el = this.getEl();
4106             var id = el.id || el.tagName;
4107             return ("Scroll " + id);
4108         };
4109
4110         proto.doMethod = function(attr, start, end) {
4111             var val = null;
4112
4113             if (attr == 'scroll') {
4114                 val = [
4115                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4116                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4117                         ];
4118
4119             } else {
4120                 val = superclass.doMethod.call(this, attr, start, end);
4121             }
4122             return val;
4123         };
4124
4125         proto.getAttribute = function(attr) {
4126             var val = null;
4127             var el = this.getEl();
4128
4129             if (attr == 'scroll') {
4130                 val = [ el.scrollLeft, el.scrollTop ];
4131             } else {
4132                 val = superclass.getAttribute.call(this, attr);
4133             }
4134
4135             return val;
4136         };
4137
4138         proto.setAttribute = function(attr, val, unit) {
4139             var el = this.getEl();
4140
4141             if (attr == 'scroll') {
4142                 el.scrollLeft = val[0];
4143                 el.scrollTop = val[1];
4144             } else {
4145                 superclass.setAttribute.call(this, attr, val, unit);
4146             }
4147         };
4148     })();
4149 /*
4150  * Based on:
4151  * Ext JS Library 1.1.1
4152  * Copyright(c) 2006-2007, Ext JS, LLC.
4153  *
4154  * Originally Released Under LGPL - original licence link has changed is not relivant.
4155  *
4156  * Fork - LGPL
4157  * <script type="text/javascript">
4158  */
4159
4160
4161 // nasty IE9 hack - what a pile of crap that is..
4162
4163  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4164     Range.prototype.createContextualFragment = function (html) {
4165         var doc = window.document;
4166         var container = doc.createElement("div");
4167         container.innerHTML = html;
4168         var frag = doc.createDocumentFragment(), n;
4169         while ((n = container.firstChild)) {
4170             frag.appendChild(n);
4171         }
4172         return frag;
4173     };
4174 }
4175
4176 /**
4177  * @class Roo.DomHelper
4178  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4179  * 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>.
4180  * @singleton
4181  */
4182 Roo.DomHelper = function(){
4183     var tempTableEl = null;
4184     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4185     var tableRe = /^table|tbody|tr|td$/i;
4186     var xmlns = {};
4187     // build as innerHTML where available
4188     /** @ignore */
4189     var createHtml = function(o){
4190         if(typeof o == 'string'){
4191             return o;
4192         }
4193         var b = "";
4194         if(!o.tag){
4195             o.tag = "div";
4196         }
4197         b += "<" + o.tag;
4198         for(var attr in o){
4199             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4200             if(attr == "style"){
4201                 var s = o["style"];
4202                 if(typeof s == "function"){
4203                     s = s.call();
4204                 }
4205                 if(typeof s == "string"){
4206                     b += ' style="' + s + '"';
4207                 }else if(typeof s == "object"){
4208                     b += ' style="';
4209                     for(var key in s){
4210                         if(typeof s[key] != "function"){
4211                             b += key + ":" + s[key] + ";";
4212                         }
4213                     }
4214                     b += '"';
4215                 }
4216             }else{
4217                 if(attr == "cls"){
4218                     b += ' class="' + o["cls"] + '"';
4219                 }else if(attr == "htmlFor"){
4220                     b += ' for="' + o["htmlFor"] + '"';
4221                 }else{
4222                     b += " " + attr + '="' + o[attr] + '"';
4223                 }
4224             }
4225         }
4226         if(emptyTags.test(o.tag)){
4227             b += "/>";
4228         }else{
4229             b += ">";
4230             var cn = o.children || o.cn;
4231             if(cn){
4232                 //http://bugs.kde.org/show_bug.cgi?id=71506
4233                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4234                     for(var i = 0, len = cn.length; i < len; i++) {
4235                         b += createHtml(cn[i], b);
4236                     }
4237                 }else{
4238                     b += createHtml(cn, b);
4239                 }
4240             }
4241             if(o.html){
4242                 b += o.html;
4243             }
4244             b += "</" + o.tag + ">";
4245         }
4246         return b;
4247     };
4248
4249     // build as dom
4250     /** @ignore */
4251     var createDom = function(o, parentNode){
4252          
4253         // defininition craeted..
4254         var ns = false;
4255         if (o.ns && o.ns != 'html') {
4256                
4257             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4258                 xmlns[o.ns] = o.xmlns;
4259                 ns = o.xmlns;
4260             }
4261             if (typeof(xmlns[o.ns]) == 'undefined') {
4262                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4263             }
4264             ns = xmlns[o.ns];
4265         }
4266         
4267         
4268         if (typeof(o) == 'string') {
4269             return parentNode.appendChild(document.createTextNode(o));
4270         }
4271         o.tag = o.tag || div;
4272         if (o.ns && Roo.isIE) {
4273             ns = false;
4274             o.tag = o.ns + ':' + o.tag;
4275             
4276         }
4277         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4278         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4279         for(var attr in o){
4280             
4281             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4282                     attr == "style" || typeof o[attr] == "function") { continue; }
4283                     
4284             if(attr=="cls" && Roo.isIE){
4285                 el.className = o["cls"];
4286             }else{
4287                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4288                 else { 
4289                     el[attr] = o[attr];
4290                 }
4291             }
4292         }
4293         Roo.DomHelper.applyStyles(el, o.style);
4294         var cn = o.children || o.cn;
4295         if(cn){
4296             //http://bugs.kde.org/show_bug.cgi?id=71506
4297              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4298                 for(var i = 0, len = cn.length; i < len; i++) {
4299                     createDom(cn[i], el);
4300                 }
4301             }else{
4302                 createDom(cn, el);
4303             }
4304         }
4305         if(o.html){
4306             el.innerHTML = o.html;
4307         }
4308         if(parentNode){
4309            parentNode.appendChild(el);
4310         }
4311         return el;
4312     };
4313
4314     var ieTable = function(depth, s, h, e){
4315         tempTableEl.innerHTML = [s, h, e].join('');
4316         var i = -1, el = tempTableEl;
4317         while(++i < depth){
4318             el = el.firstChild;
4319         }
4320         return el;
4321     };
4322
4323     // kill repeat to save bytes
4324     var ts = '<table>',
4325         te = '</table>',
4326         tbs = ts+'<tbody>',
4327         tbe = '</tbody>'+te,
4328         trs = tbs + '<tr>',
4329         tre = '</tr>'+tbe;
4330
4331     /**
4332      * @ignore
4333      * Nasty code for IE's broken table implementation
4334      */
4335     var insertIntoTable = function(tag, where, el, html){
4336         if(!tempTableEl){
4337             tempTableEl = document.createElement('div');
4338         }
4339         var node;
4340         var before = null;
4341         if(tag == 'td'){
4342             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4343                 return;
4344             }
4345             if(where == 'beforebegin'){
4346                 before = el;
4347                 el = el.parentNode;
4348             } else{
4349                 before = el.nextSibling;
4350                 el = el.parentNode;
4351             }
4352             node = ieTable(4, trs, html, tre);
4353         }
4354         else if(tag == 'tr'){
4355             if(where == 'beforebegin'){
4356                 before = el;
4357                 el = el.parentNode;
4358                 node = ieTable(3, tbs, html, tbe);
4359             } else if(where == 'afterend'){
4360                 before = el.nextSibling;
4361                 el = el.parentNode;
4362                 node = ieTable(3, tbs, html, tbe);
4363             } else{ // INTO a TR
4364                 if(where == 'afterbegin'){
4365                     before = el.firstChild;
4366                 }
4367                 node = ieTable(4, trs, html, tre);
4368             }
4369         } else if(tag == 'tbody'){
4370             if(where == 'beforebegin'){
4371                 before = el;
4372                 el = el.parentNode;
4373                 node = ieTable(2, ts, html, te);
4374             } else if(where == 'afterend'){
4375                 before = el.nextSibling;
4376                 el = el.parentNode;
4377                 node = ieTable(2, ts, html, te);
4378             } else{
4379                 if(where == 'afterbegin'){
4380                     before = el.firstChild;
4381                 }
4382                 node = ieTable(3, tbs, html, tbe);
4383             }
4384         } else{ // TABLE
4385             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4386                 return;
4387             }
4388             if(where == 'afterbegin'){
4389                 before = el.firstChild;
4390             }
4391             node = ieTable(2, ts, html, te);
4392         }
4393         el.insertBefore(node, before);
4394         return node;
4395     };
4396
4397     return {
4398     /** True to force the use of DOM instead of html fragments @type Boolean */
4399     useDom : false,
4400
4401     /**
4402      * Returns the markup for the passed Element(s) config
4403      * @param {Object} o The Dom object spec (and children)
4404      * @return {String}
4405      */
4406     markup : function(o){
4407         return createHtml(o);
4408     },
4409
4410     /**
4411      * Applies a style specification to an element
4412      * @param {String/HTMLElement} el The element to apply styles to
4413      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4414      * a function which returns such a specification.
4415      */
4416     applyStyles : function(el, styles){
4417         if(styles){
4418            el = Roo.fly(el);
4419            if(typeof styles == "string"){
4420                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4421                var matches;
4422                while ((matches = re.exec(styles)) != null){
4423                    el.setStyle(matches[1], matches[2]);
4424                }
4425            }else if (typeof styles == "object"){
4426                for (var style in styles){
4427                   el.setStyle(style, styles[style]);
4428                }
4429            }else if (typeof styles == "function"){
4430                 Roo.DomHelper.applyStyles(el, styles.call());
4431            }
4432         }
4433     },
4434
4435     /**
4436      * Inserts an HTML fragment into the Dom
4437      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4438      * @param {HTMLElement} el The context element
4439      * @param {String} html The HTML fragmenet
4440      * @return {HTMLElement} The new node
4441      */
4442     insertHtml : function(where, el, html){
4443         where = where.toLowerCase();
4444         if(el.insertAdjacentHTML){
4445             if(tableRe.test(el.tagName)){
4446                 var rs;
4447                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4448                     return rs;
4449                 }
4450             }
4451             switch(where){
4452                 case "beforebegin":
4453                     el.insertAdjacentHTML('BeforeBegin', html);
4454                     return el.previousSibling;
4455                 case "afterbegin":
4456                     el.insertAdjacentHTML('AfterBegin', html);
4457                     return el.firstChild;
4458                 case "beforeend":
4459                     el.insertAdjacentHTML('BeforeEnd', html);
4460                     return el.lastChild;
4461                 case "afterend":
4462                     el.insertAdjacentHTML('AfterEnd', html);
4463                     return el.nextSibling;
4464             }
4465             throw 'Illegal insertion point -> "' + where + '"';
4466         }
4467         var range = el.ownerDocument.createRange();
4468         var frag;
4469         switch(where){
4470              case "beforebegin":
4471                 range.setStartBefore(el);
4472                 frag = range.createContextualFragment(html);
4473                 el.parentNode.insertBefore(frag, el);
4474                 return el.previousSibling;
4475              case "afterbegin":
4476                 if(el.firstChild){
4477                     range.setStartBefore(el.firstChild);
4478                     frag = range.createContextualFragment(html);
4479                     el.insertBefore(frag, el.firstChild);
4480                     return el.firstChild;
4481                 }else{
4482                     el.innerHTML = html;
4483                     return el.firstChild;
4484                 }
4485             case "beforeend":
4486                 if(el.lastChild){
4487                     range.setStartAfter(el.lastChild);
4488                     frag = range.createContextualFragment(html);
4489                     el.appendChild(frag);
4490                     return el.lastChild;
4491                 }else{
4492                     el.innerHTML = html;
4493                     return el.lastChild;
4494                 }
4495             case "afterend":
4496                 range.setStartAfter(el);
4497                 frag = range.createContextualFragment(html);
4498                 el.parentNode.insertBefore(frag, el.nextSibling);
4499                 return el.nextSibling;
4500             }
4501             throw 'Illegal insertion point -> "' + where + '"';
4502     },
4503
4504     /**
4505      * Creates new Dom element(s) and inserts them before el
4506      * @param {String/HTMLElement/Element} el The context element
4507      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4508      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4509      * @return {HTMLElement/Roo.Element} The new node
4510      */
4511     insertBefore : function(el, o, returnElement){
4512         return this.doInsert(el, o, returnElement, "beforeBegin");
4513     },
4514
4515     /**
4516      * Creates new Dom element(s) and inserts them after el
4517      * @param {String/HTMLElement/Element} el The context element
4518      * @param {Object} o The Dom object spec (and children)
4519      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520      * @return {HTMLElement/Roo.Element} The new node
4521      */
4522     insertAfter : function(el, o, returnElement){
4523         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4524     },
4525
4526     /**
4527      * Creates new Dom element(s) and inserts them as the first child of el
4528      * @param {String/HTMLElement/Element} el The context element
4529      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531      * @return {HTMLElement/Roo.Element} The new node
4532      */
4533     insertFirst : function(el, o, returnElement){
4534         return this.doInsert(el, o, returnElement, "afterBegin");
4535     },
4536
4537     // private
4538     doInsert : function(el, o, returnElement, pos, sibling){
4539         el = Roo.getDom(el);
4540         var newNode;
4541         if(this.useDom || o.ns){
4542             newNode = createDom(o, null);
4543             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4544         }else{
4545             var html = createHtml(o);
4546             newNode = this.insertHtml(pos, el, html);
4547         }
4548         return returnElement ? Roo.get(newNode, true) : newNode;
4549     },
4550
4551     /**
4552      * Creates new Dom element(s) and appends them to el
4553      * @param {String/HTMLElement/Element} el The context element
4554      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4555      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4556      * @return {HTMLElement/Roo.Element} The new node
4557      */
4558     append : function(el, o, returnElement){
4559         el = Roo.getDom(el);
4560         var newNode;
4561         if(this.useDom || o.ns){
4562             newNode = createDom(o, null);
4563             el.appendChild(newNode);
4564         }else{
4565             var html = createHtml(o);
4566             newNode = this.insertHtml("beforeEnd", el, html);
4567         }
4568         return returnElement ? Roo.get(newNode, true) : newNode;
4569     },
4570
4571     /**
4572      * Creates new Dom element(s) and overwrites the contents of el with them
4573      * @param {String/HTMLElement/Element} el The context element
4574      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4575      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4576      * @return {HTMLElement/Roo.Element} The new node
4577      */
4578     overwrite : function(el, o, returnElement){
4579         el = Roo.getDom(el);
4580         if (o.ns) {
4581           
4582             while (el.childNodes.length) {
4583                 el.removeChild(el.firstChild);
4584             }
4585             createDom(o, el);
4586         } else {
4587             el.innerHTML = createHtml(o);   
4588         }
4589         
4590         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4591     },
4592
4593     /**
4594      * Creates a new Roo.DomHelper.Template from the Dom object spec
4595      * @param {Object} o The Dom object spec (and children)
4596      * @return {Roo.DomHelper.Template} The new template
4597      */
4598     createTemplate : function(o){
4599         var html = createHtml(o);
4600         return new Roo.Template(html);
4601     }
4602     };
4603 }();
4604 /*
4605  * Based on:
4606  * Ext JS Library 1.1.1
4607  * Copyright(c) 2006-2007, Ext JS, LLC.
4608  *
4609  * Originally Released Under LGPL - original licence link has changed is not relivant.
4610  *
4611  * Fork - LGPL
4612  * <script type="text/javascript">
4613  */
4614  
4615 /**
4616 * @class Roo.Template
4617 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4618 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4619 * Usage:
4620 <pre><code>
4621 var t = new Roo.Template({
4622     html :  '&lt;div name="{id}"&gt;' + 
4623         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4624         '&lt;/div&gt;',
4625     myformat: function (value, allValues) {
4626         return 'XX' + value;
4627     }
4628 });
4629 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4630 </code></pre>
4631 * For more information see this blog post with examples:
4632 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4633      - Create Elements using DOM, HTML fragments and Templates</a>. 
4634 * @constructor
4635 * @param {Object} cfg - Configuration object.
4636 */
4637 Roo.Template = function(cfg){
4638     // BC!
4639     if(cfg instanceof Array){
4640         cfg = cfg.join("");
4641     }else if(arguments.length > 1){
4642         cfg = Array.prototype.join.call(arguments, "");
4643     }
4644     
4645     
4646     if (typeof(cfg) == 'object') {
4647         Roo.apply(this,cfg)
4648     } else {
4649         // bc
4650         this.html = cfg;
4651     }
4652     if (this.url) {
4653         this.load();
4654     }
4655     
4656 };
4657 Roo.Template.prototype = {
4658     
4659     /**
4660      * @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..
4661      *                    it should be fixed so that template is observable...
4662      */
4663     url : false,
4664     /**
4665      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4666      */
4667     html : '',
4668     /**
4669      * Returns an HTML fragment of this template with the specified values applied.
4670      * @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'})
4671      * @return {String} The HTML fragment
4672      */
4673     applyTemplate : function(values){
4674         try {
4675            
4676             if(this.compiled){
4677                 return this.compiled(values);
4678             }
4679             var useF = this.disableFormats !== true;
4680             var fm = Roo.util.Format, tpl = this;
4681             var fn = function(m, name, format, args){
4682                 if(format && useF){
4683                     if(format.substr(0, 5) == "this."){
4684                         return tpl.call(format.substr(5), values[name], values);
4685                     }else{
4686                         if(args){
4687                             // quoted values are required for strings in compiled templates, 
4688                             // but for non compiled we need to strip them
4689                             // quoted reversed for jsmin
4690                             var re = /^\s*['"](.*)["']\s*$/;
4691                             args = args.split(',');
4692                             for(var i = 0, len = args.length; i < len; i++){
4693                                 args[i] = args[i].replace(re, "$1");
4694                             }
4695                             args = [values[name]].concat(args);
4696                         }else{
4697                             args = [values[name]];
4698                         }
4699                         return fm[format].apply(fm, args);
4700                     }
4701                 }else{
4702                     return values[name] !== undefined ? values[name] : "";
4703                 }
4704             };
4705             return this.html.replace(this.re, fn);
4706         } catch (e) {
4707             Roo.log(e);
4708             throw e;
4709         }
4710          
4711     },
4712     
4713     loading : false,
4714       
4715     load : function ()
4716     {
4717          
4718         if (this.loading) {
4719             return;
4720         }
4721         var _t = this;
4722         
4723         this.loading = true;
4724         this.compiled = false;
4725         
4726         var cx = new Roo.data.Connection();
4727         cx.request({
4728             url : this.url,
4729             method : 'GET',
4730             success : function (response) {
4731                 _t.loading = false;
4732                 _t.html = response.responseText;
4733                 _t.url = false;
4734                 _t.compile();
4735              },
4736             failure : function(response) {
4737                 Roo.log("Template failed to load from " + _t.url);
4738                 _t.loading = false;
4739             }
4740         });
4741     },
4742
4743     /**
4744      * Sets the HTML used as the template and optionally compiles it.
4745      * @param {String} html
4746      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4747      * @return {Roo.Template} this
4748      */
4749     set : function(html, compile){
4750         this.html = html;
4751         this.compiled = null;
4752         if(compile){
4753             this.compile();
4754         }
4755         return this;
4756     },
4757     
4758     /**
4759      * True to disable format functions (defaults to false)
4760      * @type Boolean
4761      */
4762     disableFormats : false,
4763     
4764     /**
4765     * The regular expression used to match template variables 
4766     * @type RegExp
4767     * @property 
4768     */
4769     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4770     
4771     /**
4772      * Compiles the template into an internal function, eliminating the RegEx overhead.
4773      * @return {Roo.Template} this
4774      */
4775     compile : function(){
4776         var fm = Roo.util.Format;
4777         var useF = this.disableFormats !== true;
4778         var sep = Roo.isGecko ? "+" : ",";
4779         var fn = function(m, name, format, args){
4780             if(format && useF){
4781                 args = args ? ',' + args : "";
4782                 if(format.substr(0, 5) != "this."){
4783                     format = "fm." + format + '(';
4784                 }else{
4785                     format = 'this.call("'+ format.substr(5) + '", ';
4786                     args = ", values";
4787                 }
4788             }else{
4789                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4790             }
4791             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4792         };
4793         var body;
4794         // branched to use + in gecko and [].join() in others
4795         if(Roo.isGecko){
4796             body = "this.compiled = function(values){ return '" +
4797                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4798                     "';};";
4799         }else{
4800             body = ["this.compiled = function(values){ return ['"];
4801             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4802             body.push("'].join('');};");
4803             body = body.join('');
4804         }
4805         /**
4806          * eval:var:values
4807          * eval:var:fm
4808          */
4809         eval(body);
4810         return this;
4811     },
4812     
4813     // private function used to call members
4814     call : function(fnName, value, allValues){
4815         return this[fnName](value, allValues);
4816     },
4817     
4818     /**
4819      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4820      * @param {String/HTMLElement/Roo.Element} el The context element
4821      * @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'})
4822      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823      * @return {HTMLElement/Roo.Element} The new node or Element
4824      */
4825     insertFirst: function(el, values, returnElement){
4826         return this.doInsert('afterBegin', el, values, returnElement);
4827     },
4828
4829     /**
4830      * Applies the supplied values to the template and inserts the new node(s) before el.
4831      * @param {String/HTMLElement/Roo.Element} el The context element
4832      * @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'})
4833      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4834      * @return {HTMLElement/Roo.Element} The new node or Element
4835      */
4836     insertBefore: function(el, values, returnElement){
4837         return this.doInsert('beforeBegin', el, values, returnElement);
4838     },
4839
4840     /**
4841      * Applies the supplied values to the template and inserts the new node(s) after el.
4842      * @param {String/HTMLElement/Roo.Element} el The context element
4843      * @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'})
4844      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4845      * @return {HTMLElement/Roo.Element} The new node or Element
4846      */
4847     insertAfter : function(el, values, returnElement){
4848         return this.doInsert('afterEnd', el, values, returnElement);
4849     },
4850     
4851     /**
4852      * Applies the supplied values to the template and appends the new node(s) to el.
4853      * @param {String/HTMLElement/Roo.Element} el The context element
4854      * @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'})
4855      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4856      * @return {HTMLElement/Roo.Element} The new node or Element
4857      */
4858     append : function(el, values, returnElement){
4859         return this.doInsert('beforeEnd', el, values, returnElement);
4860     },
4861
4862     doInsert : function(where, el, values, returnEl){
4863         el = Roo.getDom(el);
4864         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4865         return returnEl ? Roo.get(newNode, true) : newNode;
4866     },
4867
4868     /**
4869      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4870      * @param {String/HTMLElement/Roo.Element} el The context element
4871      * @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'})
4872      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4873      * @return {HTMLElement/Roo.Element} The new node or Element
4874      */
4875     overwrite : function(el, values, returnElement){
4876         el = Roo.getDom(el);
4877         el.innerHTML = this.applyTemplate(values);
4878         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4879     }
4880 };
4881 /**
4882  * Alias for {@link #applyTemplate}
4883  * @method
4884  */
4885 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4886
4887 // backwards compat
4888 Roo.DomHelper.Template = Roo.Template;
4889
4890 /**
4891  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4892  * @param {String/HTMLElement} el A DOM element or its id
4893  * @returns {Roo.Template} The created template
4894  * @static
4895  */
4896 Roo.Template.from = function(el){
4897     el = Roo.getDom(el);
4898     return new Roo.Template(el.value || el.innerHTML);
4899 };/*
4900  * Based on:
4901  * Ext JS Library 1.1.1
4902  * Copyright(c) 2006-2007, Ext JS, LLC.
4903  *
4904  * Originally Released Under LGPL - original licence link has changed is not relivant.
4905  *
4906  * Fork - LGPL
4907  * <script type="text/javascript">
4908  */
4909  
4910
4911 /*
4912  * This is code is also distributed under MIT license for use
4913  * with jQuery and prototype JavaScript libraries.
4914  */
4915 /**
4916  * @class Roo.DomQuery
4917 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).
4918 <p>
4919 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>
4920
4921 <p>
4922 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.
4923 </p>
4924 <h4>Element Selectors:</h4>
4925 <ul class="list">
4926     <li> <b>*</b> any element</li>
4927     <li> <b>E</b> an element with the tag E</li>
4928     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4929     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4930     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4931     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4932 </ul>
4933 <h4>Attribute Selectors:</h4>
4934 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4935 <ul class="list">
4936     <li> <b>E[foo]</b> has an attribute "foo"</li>
4937     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4938     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4939     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4940     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4941     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4942     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4943 </ul>
4944 <h4>Pseudo Classes:</h4>
4945 <ul class="list">
4946     <li> <b>E:first-child</b> E is the first child of its parent</li>
4947     <li> <b>E:last-child</b> E is the last child of its parent</li>
4948     <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>
4949     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4950     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4951     <li> <b>E:only-child</b> E is the only child of its parent</li>
4952     <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>
4953     <li> <b>E:first</b> the first E in the resultset</li>
4954     <li> <b>E:last</b> the last E in the resultset</li>
4955     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4956     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4957     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4958     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4959     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4960     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4961     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4962     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4963     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4964 </ul>
4965 <h4>CSS Value Selectors:</h4>
4966 <ul class="list">
4967     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4968     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4969     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4970     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4971     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4972     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4973 </ul>
4974  * @singleton
4975  */
4976 Roo.DomQuery = function(){
4977     var cache = {}, simpleCache = {}, valueCache = {};
4978     var nonSpace = /\S/;
4979     var trimRe = /^\s+|\s+$/g;
4980     var tplRe = /\{(\d+)\}/g;
4981     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4982     var tagTokenRe = /^(#)?([\w-\*]+)/;
4983     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4984
4985     function child(p, index){
4986         var i = 0;
4987         var n = p.firstChild;
4988         while(n){
4989             if(n.nodeType == 1){
4990                if(++i == index){
4991                    return n;
4992                }
4993             }
4994             n = n.nextSibling;
4995         }
4996         return null;
4997     };
4998
4999     function next(n){
5000         while((n = n.nextSibling) && n.nodeType != 1);
5001         return n;
5002     };
5003
5004     function prev(n){
5005         while((n = n.previousSibling) && n.nodeType != 1);
5006         return n;
5007     };
5008
5009     function children(d){
5010         var n = d.firstChild, ni = -1;
5011             while(n){
5012                 var nx = n.nextSibling;
5013                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5014                     d.removeChild(n);
5015                 }else{
5016                     n.nodeIndex = ++ni;
5017                 }
5018                 n = nx;
5019             }
5020             return this;
5021         };
5022
5023     function byClassName(c, a, v){
5024         if(!v){
5025             return c;
5026         }
5027         var r = [], ri = -1, cn;
5028         for(var i = 0, ci; ci = c[i]; i++){
5029             if((' '+ci.className+' ').indexOf(v) != -1){
5030                 r[++ri] = ci;
5031             }
5032         }
5033         return r;
5034     };
5035
5036     function attrValue(n, attr){
5037         if(!n.tagName && typeof n.length != "undefined"){
5038             n = n[0];
5039         }
5040         if(!n){
5041             return null;
5042         }
5043         if(attr == "for"){
5044             return n.htmlFor;
5045         }
5046         if(attr == "class" || attr == "className"){
5047             return n.className;
5048         }
5049         return n.getAttribute(attr) || n[attr];
5050
5051     };
5052
5053     function getNodes(ns, mode, tagName){
5054         var result = [], ri = -1, cs;
5055         if(!ns){
5056             return result;
5057         }
5058         tagName = tagName || "*";
5059         if(typeof ns.getElementsByTagName != "undefined"){
5060             ns = [ns];
5061         }
5062         if(!mode){
5063             for(var i = 0, ni; ni = ns[i]; i++){
5064                 cs = ni.getElementsByTagName(tagName);
5065                 for(var j = 0, ci; ci = cs[j]; j++){
5066                     result[++ri] = ci;
5067                 }
5068             }
5069         }else if(mode == "/" || mode == ">"){
5070             var utag = tagName.toUpperCase();
5071             for(var i = 0, ni, cn; ni = ns[i]; i++){
5072                 cn = ni.children || ni.childNodes;
5073                 for(var j = 0, cj; cj = cn[j]; j++){
5074                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5075                         result[++ri] = cj;
5076                     }
5077                 }
5078             }
5079         }else if(mode == "+"){
5080             var utag = tagName.toUpperCase();
5081             for(var i = 0, n; n = ns[i]; i++){
5082                 while((n = n.nextSibling) && n.nodeType != 1);
5083                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5084                     result[++ri] = n;
5085                 }
5086             }
5087         }else if(mode == "~"){
5088             for(var i = 0, n; n = ns[i]; i++){
5089                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5090                 if(n){
5091                     result[++ri] = n;
5092                 }
5093             }
5094         }
5095         return result;
5096     };
5097
5098     function concat(a, b){
5099         if(b.slice){
5100             return a.concat(b);
5101         }
5102         for(var i = 0, l = b.length; i < l; i++){
5103             a[a.length] = b[i];
5104         }
5105         return a;
5106     }
5107
5108     function byTag(cs, tagName){
5109         if(cs.tagName || cs == document){
5110             cs = [cs];
5111         }
5112         if(!tagName){
5113             return cs;
5114         }
5115         var r = [], ri = -1;
5116         tagName = tagName.toLowerCase();
5117         for(var i = 0, ci; ci = cs[i]; i++){
5118             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5119                 r[++ri] = ci;
5120             }
5121         }
5122         return r;
5123     };
5124
5125     function byId(cs, attr, id){
5126         if(cs.tagName || cs == document){
5127             cs = [cs];
5128         }
5129         if(!id){
5130             return cs;
5131         }
5132         var r = [], ri = -1;
5133         for(var i = 0,ci; ci = cs[i]; i++){
5134             if(ci && ci.id == id){
5135                 r[++ri] = ci;
5136                 return r;
5137             }
5138         }
5139         return r;
5140     };
5141
5142     function byAttribute(cs, attr, value, op, custom){
5143         var r = [], ri = -1, st = custom=="{";
5144         var f = Roo.DomQuery.operators[op];
5145         for(var i = 0, ci; ci = cs[i]; i++){
5146             var a;
5147             if(st){
5148                 a = Roo.DomQuery.getStyle(ci, attr);
5149             }
5150             else if(attr == "class" || attr == "className"){
5151                 a = ci.className;
5152             }else if(attr == "for"){
5153                 a = ci.htmlFor;
5154             }else if(attr == "href"){
5155                 a = ci.getAttribute("href", 2);
5156             }else{
5157                 a = ci.getAttribute(attr);
5158             }
5159             if((f && f(a, value)) || (!f && a)){
5160                 r[++ri] = ci;
5161             }
5162         }
5163         return r;
5164     };
5165
5166     function byPseudo(cs, name, value){
5167         return Roo.DomQuery.pseudos[name](cs, value);
5168     };
5169
5170     // This is for IE MSXML which does not support expandos.
5171     // IE runs the same speed using setAttribute, however FF slows way down
5172     // and Safari completely fails so they need to continue to use expandos.
5173     var isIE = window.ActiveXObject ? true : false;
5174
5175     // this eval is stop the compressor from
5176     // renaming the variable to something shorter
5177     
5178     /** eval:var:batch */
5179     var batch = 30803; 
5180
5181     var key = 30803;
5182
5183     function nodupIEXml(cs){
5184         var d = ++key;
5185         cs[0].setAttribute("_nodup", d);
5186         var r = [cs[0]];
5187         for(var i = 1, len = cs.length; i < len; i++){
5188             var c = cs[i];
5189             if(!c.getAttribute("_nodup") != d){
5190                 c.setAttribute("_nodup", d);
5191                 r[r.length] = c;
5192             }
5193         }
5194         for(var i = 0, len = cs.length; i < len; i++){
5195             cs[i].removeAttribute("_nodup");
5196         }
5197         return r;
5198     }
5199
5200     function nodup(cs){
5201         if(!cs){
5202             return [];
5203         }
5204         var len = cs.length, c, i, r = cs, cj, ri = -1;
5205         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5206             return cs;
5207         }
5208         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5209             return nodupIEXml(cs);
5210         }
5211         var d = ++key;
5212         cs[0]._nodup = d;
5213         for(i = 1; c = cs[i]; i++){
5214             if(c._nodup != d){
5215                 c._nodup = d;
5216             }else{
5217                 r = [];
5218                 for(var j = 0; j < i; j++){
5219                     r[++ri] = cs[j];
5220                 }
5221                 for(j = i+1; cj = cs[j]; j++){
5222                     if(cj._nodup != d){
5223                         cj._nodup = d;
5224                         r[++ri] = cj;
5225                     }
5226                 }
5227                 return r;
5228             }
5229         }
5230         return r;
5231     }
5232
5233     function quickDiffIEXml(c1, c2){
5234         var d = ++key;
5235         for(var i = 0, len = c1.length; i < len; i++){
5236             c1[i].setAttribute("_qdiff", d);
5237         }
5238         var r = [];
5239         for(var i = 0, len = c2.length; i < len; i++){
5240             if(c2[i].getAttribute("_qdiff") != d){
5241                 r[r.length] = c2[i];
5242             }
5243         }
5244         for(var i = 0, len = c1.length; i < len; i++){
5245            c1[i].removeAttribute("_qdiff");
5246         }
5247         return r;
5248     }
5249
5250     function quickDiff(c1, c2){
5251         var len1 = c1.length;
5252         if(!len1){
5253             return c2;
5254         }
5255         if(isIE && c1[0].selectSingleNode){
5256             return quickDiffIEXml(c1, c2);
5257         }
5258         var d = ++key;
5259         for(var i = 0; i < len1; i++){
5260             c1[i]._qdiff = d;
5261         }
5262         var r = [];
5263         for(var i = 0, len = c2.length; i < len; i++){
5264             if(c2[i]._qdiff != d){
5265                 r[r.length] = c2[i];
5266             }
5267         }
5268         return r;
5269     }
5270
5271     function quickId(ns, mode, root, id){
5272         if(ns == root){
5273            var d = root.ownerDocument || root;
5274            return d.getElementById(id);
5275         }
5276         ns = getNodes(ns, mode, "*");
5277         return byId(ns, null, id);
5278     }
5279
5280     return {
5281         getStyle : function(el, name){
5282             return Roo.fly(el).getStyle(name);
5283         },
5284         /**
5285          * Compiles a selector/xpath query into a reusable function. The returned function
5286          * takes one parameter "root" (optional), which is the context node from where the query should start.
5287          * @param {String} selector The selector/xpath query
5288          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5289          * @return {Function}
5290          */
5291         compile : function(path, type){
5292             type = type || "select";
5293             
5294             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5295             var q = path, mode, lq;
5296             var tk = Roo.DomQuery.matchers;
5297             var tklen = tk.length;
5298             var mm;
5299
5300             // accept leading mode switch
5301             var lmode = q.match(modeRe);
5302             if(lmode && lmode[1]){
5303                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5304                 q = q.replace(lmode[1], "");
5305             }
5306             // strip leading slashes
5307             while(path.substr(0, 1)=="/"){
5308                 path = path.substr(1);
5309             }
5310
5311             while(q && lq != q){
5312                 lq = q;
5313                 var tm = q.match(tagTokenRe);
5314                 if(type == "select"){
5315                     if(tm){
5316                         if(tm[1] == "#"){
5317                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5318                         }else{
5319                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5320                         }
5321                         q = q.replace(tm[0], "");
5322                     }else if(q.substr(0, 1) != '@'){
5323                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5324                     }
5325                 }else{
5326                     if(tm){
5327                         if(tm[1] == "#"){
5328                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5329                         }else{
5330                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5331                         }
5332                         q = q.replace(tm[0], "");
5333                     }
5334                 }
5335                 while(!(mm = q.match(modeRe))){
5336                     var matched = false;
5337                     for(var j = 0; j < tklen; j++){
5338                         var t = tk[j];
5339                         var m = q.match(t.re);
5340                         if(m){
5341                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5342                                                     return m[i];
5343                                                 });
5344                             q = q.replace(m[0], "");
5345                             matched = true;
5346                             break;
5347                         }
5348                     }
5349                     // prevent infinite loop on bad selector
5350                     if(!matched){
5351                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5352                     }
5353                 }
5354                 if(mm[1]){
5355                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5356                     q = q.replace(mm[1], "");
5357                 }
5358             }
5359             fn[fn.length] = "return nodup(n);\n}";
5360             
5361              /** 
5362               * list of variables that need from compression as they are used by eval.
5363              *  eval:var:batch 
5364              *  eval:var:nodup
5365              *  eval:var:byTag
5366              *  eval:var:ById
5367              *  eval:var:getNodes
5368              *  eval:var:quickId
5369              *  eval:var:mode
5370              *  eval:var:root
5371              *  eval:var:n
5372              *  eval:var:byClassName
5373              *  eval:var:byPseudo
5374              *  eval:var:byAttribute
5375              *  eval:var:attrValue
5376              * 
5377              **/ 
5378             eval(fn.join(""));
5379             return f;
5380         },
5381
5382         /**
5383          * Selects a group of elements.
5384          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5385          * @param {Node} root (optional) The start of the query (defaults to document).
5386          * @return {Array}
5387          */
5388         select : function(path, root, type){
5389             if(!root || root == document){
5390                 root = document;
5391             }
5392             if(typeof root == "string"){
5393                 root = document.getElementById(root);
5394             }
5395             var paths = path.split(",");
5396             var results = [];
5397             for(var i = 0, len = paths.length; i < len; i++){
5398                 var p = paths[i].replace(trimRe, "");
5399                 if(!cache[p]){
5400                     cache[p] = Roo.DomQuery.compile(p);
5401                     if(!cache[p]){
5402                         throw p + " is not a valid selector";
5403                     }
5404                 }
5405                 var result = cache[p](root);
5406                 if(result && result != document){
5407                     results = results.concat(result);
5408                 }
5409             }
5410             if(paths.length > 1){
5411                 return nodup(results);
5412             }
5413             return results;
5414         },
5415
5416         /**
5417          * Selects a single element.
5418          * @param {String} selector The selector/xpath query
5419          * @param {Node} root (optional) The start of the query (defaults to document).
5420          * @return {Element}
5421          */
5422         selectNode : function(path, root){
5423             return Roo.DomQuery.select(path, root)[0];
5424         },
5425
5426         /**
5427          * Selects the value of a node, optionally replacing null with the defaultValue.
5428          * @param {String} selector The selector/xpath query
5429          * @param {Node} root (optional) The start of the query (defaults to document).
5430          * @param {String} defaultValue
5431          */
5432         selectValue : function(path, root, defaultValue){
5433             path = path.replace(trimRe, "");
5434             if(!valueCache[path]){
5435                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5436             }
5437             var n = valueCache[path](root);
5438             n = n[0] ? n[0] : n;
5439             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5440             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5441         },
5442
5443         /**
5444          * Selects the value of a node, parsing integers and floats.
5445          * @param {String} selector The selector/xpath query
5446          * @param {Node} root (optional) The start of the query (defaults to document).
5447          * @param {Number} defaultValue
5448          * @return {Number}
5449          */
5450         selectNumber : function(path, root, defaultValue){
5451             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5452             return parseFloat(v);
5453         },
5454
5455         /**
5456          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5457          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5458          * @param {String} selector The simple selector to test
5459          * @return {Boolean}
5460          */
5461         is : function(el, ss){
5462             if(typeof el == "string"){
5463                 el = document.getElementById(el);
5464             }
5465             var isArray = (el instanceof Array);
5466             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5467             return isArray ? (result.length == el.length) : (result.length > 0);
5468         },
5469
5470         /**
5471          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5472          * @param {Array} el An array of elements to filter
5473          * @param {String} selector The simple selector to test
5474          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5475          * the selector instead of the ones that match
5476          * @return {Array}
5477          */
5478         filter : function(els, ss, nonMatches){
5479             ss = ss.replace(trimRe, "");
5480             if(!simpleCache[ss]){
5481                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5482             }
5483             var result = simpleCache[ss](els);
5484             return nonMatches ? quickDiff(result, els) : result;
5485         },
5486
5487         /**
5488          * Collection of matching regular expressions and code snippets.
5489          */
5490         matchers : [{
5491                 re: /^\.([\w-]+)/,
5492                 select: 'n = byClassName(n, null, " {1} ");'
5493             }, {
5494                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5495                 select: 'n = byPseudo(n, "{1}", "{2}");'
5496             },{
5497                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5498                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5499             }, {
5500                 re: /^#([\w-]+)/,
5501                 select: 'n = byId(n, null, "{1}");'
5502             },{
5503                 re: /^@([\w-]+)/,
5504                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5505             }
5506         ],
5507
5508         /**
5509          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5510          * 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;.
5511          */
5512         operators : {
5513             "=" : function(a, v){
5514                 return a == v;
5515             },
5516             "!=" : function(a, v){
5517                 return a != v;
5518             },
5519             "^=" : function(a, v){
5520                 return a && a.substr(0, v.length) == v;
5521             },
5522             "$=" : function(a, v){
5523                 return a && a.substr(a.length-v.length) == v;
5524             },
5525             "*=" : function(a, v){
5526                 return a && a.indexOf(v) !== -1;
5527             },
5528             "%=" : function(a, v){
5529                 return (a % v) == 0;
5530             },
5531             "|=" : function(a, v){
5532                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5533             },
5534             "~=" : function(a, v){
5535                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5536             }
5537         },
5538
5539         /**
5540          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5541          * and the argument (if any) supplied in the selector.
5542          */
5543         pseudos : {
5544             "first-child" : function(c){
5545                 var r = [], ri = -1, n;
5546                 for(var i = 0, ci; ci = n = c[i]; i++){
5547                     while((n = n.previousSibling) && n.nodeType != 1);
5548                     if(!n){
5549                         r[++ri] = ci;
5550                     }
5551                 }
5552                 return r;
5553             },
5554
5555             "last-child" : function(c){
5556                 var r = [], ri = -1, n;
5557                 for(var i = 0, ci; ci = n = c[i]; i++){
5558                     while((n = n.nextSibling) && n.nodeType != 1);
5559                     if(!n){
5560                         r[++ri] = ci;
5561                     }
5562                 }
5563                 return r;
5564             },
5565
5566             "nth-child" : function(c, a) {
5567                 var r = [], ri = -1;
5568                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5569                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5570                 for(var i = 0, n; n = c[i]; i++){
5571                     var pn = n.parentNode;
5572                     if (batch != pn._batch) {
5573                         var j = 0;
5574                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5575                             if(cn.nodeType == 1){
5576                                cn.nodeIndex = ++j;
5577                             }
5578                         }
5579                         pn._batch = batch;
5580                     }
5581                     if (f == 1) {
5582                         if (l == 0 || n.nodeIndex == l){
5583                             r[++ri] = n;
5584                         }
5585                     } else if ((n.nodeIndex + l) % f == 0){
5586                         r[++ri] = n;
5587                     }
5588                 }
5589
5590                 return r;
5591             },
5592
5593             "only-child" : function(c){
5594                 var r = [], ri = -1;;
5595                 for(var i = 0, ci; ci = c[i]; i++){
5596                     if(!prev(ci) && !next(ci)){
5597                         r[++ri] = ci;
5598                     }
5599                 }
5600                 return r;
5601             },
5602
5603             "empty" : function(c){
5604                 var r = [], ri = -1;
5605                 for(var i = 0, ci; ci = c[i]; i++){
5606                     var cns = ci.childNodes, j = 0, cn, empty = true;
5607                     while(cn = cns[j]){
5608                         ++j;
5609                         if(cn.nodeType == 1 || cn.nodeType == 3){
5610                             empty = false;
5611                             break;
5612                         }
5613                     }
5614                     if(empty){
5615                         r[++ri] = ci;
5616                     }
5617                 }
5618                 return r;
5619             },
5620
5621             "contains" : function(c, v){
5622                 var r = [], ri = -1;
5623                 for(var i = 0, ci; ci = c[i]; i++){
5624                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5625                         r[++ri] = ci;
5626                     }
5627                 }
5628                 return r;
5629             },
5630
5631             "nodeValue" : function(c, v){
5632                 var r = [], ri = -1;
5633                 for(var i = 0, ci; ci = c[i]; i++){
5634                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5635                         r[++ri] = ci;
5636                     }
5637                 }
5638                 return r;
5639             },
5640
5641             "checked" : function(c){
5642                 var r = [], ri = -1;
5643                 for(var i = 0, ci; ci = c[i]; i++){
5644                     if(ci.checked == true){
5645                         r[++ri] = ci;
5646                     }
5647                 }
5648                 return r;
5649             },
5650
5651             "not" : function(c, ss){
5652                 return Roo.DomQuery.filter(c, ss, true);
5653             },
5654
5655             "odd" : function(c){
5656                 return this["nth-child"](c, "odd");
5657             },
5658
5659             "even" : function(c){
5660                 return this["nth-child"](c, "even");
5661             },
5662
5663             "nth" : function(c, a){
5664                 return c[a-1] || [];
5665             },
5666
5667             "first" : function(c){
5668                 return c[0] || [];
5669             },
5670
5671             "last" : function(c){
5672                 return c[c.length-1] || [];
5673             },
5674
5675             "has" : function(c, ss){
5676                 var s = Roo.DomQuery.select;
5677                 var r = [], ri = -1;
5678                 for(var i = 0, ci; ci = c[i]; i++){
5679                     if(s(ss, ci).length > 0){
5680                         r[++ri] = ci;
5681                     }
5682                 }
5683                 return r;
5684             },
5685
5686             "next" : function(c, ss){
5687                 var is = Roo.DomQuery.is;
5688                 var r = [], ri = -1;
5689                 for(var i = 0, ci; ci = c[i]; i++){
5690                     var n = next(ci);
5691                     if(n && is(n, ss)){
5692                         r[++ri] = ci;
5693                     }
5694                 }
5695                 return r;
5696             },
5697
5698             "prev" : function(c, ss){
5699                 var is = Roo.DomQuery.is;
5700                 var r = [], ri = -1;
5701                 for(var i = 0, ci; ci = c[i]; i++){
5702                     var n = prev(ci);
5703                     if(n && is(n, ss)){
5704                         r[++ri] = ci;
5705                     }
5706                 }
5707                 return r;
5708             }
5709         }
5710     };
5711 }();
5712
5713 /**
5714  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5715  * @param {String} path The selector/xpath query
5716  * @param {Node} root (optional) The start of the query (defaults to document).
5717  * @return {Array}
5718  * @member Roo
5719  * @method query
5720  */
5721 Roo.query = Roo.DomQuery.select;
5722 /*
5723  * Based on:
5724  * Ext JS Library 1.1.1
5725  * Copyright(c) 2006-2007, Ext JS, LLC.
5726  *
5727  * Originally Released Under LGPL - original licence link has changed is not relivant.
5728  *
5729  * Fork - LGPL
5730  * <script type="text/javascript">
5731  */
5732
5733 /**
5734  * @class Roo.util.Observable
5735  * Base class that provides a common interface for publishing events. Subclasses are expected to
5736  * to have a property "events" with all the events defined.<br>
5737  * For example:
5738  * <pre><code>
5739  Employee = function(name){
5740     this.name = name;
5741     this.addEvents({
5742         "fired" : true,
5743         "quit" : true
5744     });
5745  }
5746  Roo.extend(Employee, Roo.util.Observable);
5747 </code></pre>
5748  * @param {Object} config properties to use (incuding events / listeners)
5749  */
5750
5751 Roo.util.Observable = function(cfg){
5752     
5753     cfg = cfg|| {};
5754     this.addEvents(cfg.events || {});
5755     if (cfg.events) {
5756         delete cfg.events; // make sure
5757     }
5758      
5759     Roo.apply(this, cfg);
5760     
5761     if(this.listeners){
5762         this.on(this.listeners);
5763         delete this.listeners;
5764     }
5765 };
5766 Roo.util.Observable.prototype = {
5767     /** 
5768  * @cfg {Object} listeners  list of events and functions to call for this object, 
5769  * For example :
5770  * <pre><code>
5771     listeners :  { 
5772        'click' : function(e) {
5773            ..... 
5774         } ,
5775         .... 
5776     } 
5777   </code></pre>
5778  */
5779     
5780     
5781     /**
5782      * Fires the specified event with the passed parameters (minus the event name).
5783      * @param {String} eventName
5784      * @param {Object...} args Variable number of parameters are passed to handlers
5785      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5786      */
5787     fireEvent : function(){
5788         var ce = this.events[arguments[0].toLowerCase()];
5789         if(typeof ce == "object"){
5790             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5791         }else{
5792             return true;
5793         }
5794     },
5795
5796     // private
5797     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5798
5799     /**
5800      * Appends an event handler to this component
5801      * @param {String}   eventName The type of event to listen for
5802      * @param {Function} handler The method the event invokes
5803      * @param {Object}   scope (optional) The scope in which to execute the handler
5804      * function. The handler function's "this" context.
5805      * @param {Object}   options (optional) An object containing handler configuration
5806      * properties. This may contain any of the following properties:<ul>
5807      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5808      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5809      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5810      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5811      * by the specified number of milliseconds. If the event fires again within that time, the original
5812      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5813      * </ul><br>
5814      * <p>
5815      * <b>Combining Options</b><br>
5816      * Using the options argument, it is possible to combine different types of listeners:<br>
5817      * <br>
5818      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5819                 <pre><code>
5820                 el.on('click', this.onClick, this, {
5821                         single: true,
5822                 delay: 100,
5823                 forumId: 4
5824                 });
5825                 </code></pre>
5826      * <p>
5827      * <b>Attaching multiple handlers in 1 call</b><br>
5828      * The method also allows for a single argument to be passed which is a config object containing properties
5829      * which specify multiple handlers.
5830      * <pre><code>
5831                 el.on({
5832                         'click': {
5833                         fn: this.onClick,
5834                         scope: this,
5835                         delay: 100
5836                 }, 
5837                 'mouseover': {
5838                         fn: this.onMouseOver,
5839                         scope: this
5840                 },
5841                 'mouseout': {
5842                         fn: this.onMouseOut,
5843                         scope: this
5844                 }
5845                 });
5846                 </code></pre>
5847      * <p>
5848      * Or a shorthand syntax which passes the same scope object to all handlers:
5849         <pre><code>
5850                 el.on({
5851                         'click': this.onClick,
5852                 'mouseover': this.onMouseOver,
5853                 'mouseout': this.onMouseOut,
5854                 scope: this
5855                 });
5856                 </code></pre>
5857      */
5858     addListener : function(eventName, fn, scope, o){
5859         if(typeof eventName == "object"){
5860             o = eventName;
5861             for(var e in o){
5862                 if(this.filterOptRe.test(e)){
5863                     continue;
5864                 }
5865                 if(typeof o[e] == "function"){
5866                     // shared options
5867                     this.addListener(e, o[e], o.scope,  o);
5868                 }else{
5869                     // individual options
5870                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5871                 }
5872             }
5873             return;
5874         }
5875         o = (!o || typeof o == "boolean") ? {} : o;
5876         eventName = eventName.toLowerCase();
5877         var ce = this.events[eventName] || true;
5878         if(typeof ce == "boolean"){
5879             ce = new Roo.util.Event(this, eventName);
5880             this.events[eventName] = ce;
5881         }
5882         ce.addListener(fn, scope, o);
5883     },
5884
5885     /**
5886      * Removes a listener
5887      * @param {String}   eventName     The type of event to listen for
5888      * @param {Function} handler        The handler to remove
5889      * @param {Object}   scope  (optional) The scope (this object) for the handler
5890      */
5891     removeListener : function(eventName, fn, scope){
5892         var ce = this.events[eventName.toLowerCase()];
5893         if(typeof ce == "object"){
5894             ce.removeListener(fn, scope);
5895         }
5896     },
5897
5898     /**
5899      * Removes all listeners for this object
5900      */
5901     purgeListeners : function(){
5902         for(var evt in this.events){
5903             if(typeof this.events[evt] == "object"){
5904                  this.events[evt].clearListeners();
5905             }
5906         }
5907     },
5908
5909     relayEvents : function(o, events){
5910         var createHandler = function(ename){
5911             return function(){
5912                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5913             };
5914         };
5915         for(var i = 0, len = events.length; i < len; i++){
5916             var ename = events[i];
5917             if(!this.events[ename]){ this.events[ename] = true; };
5918             o.on(ename, createHandler(ename), this);
5919         }
5920     },
5921
5922     /**
5923      * Used to define events on this Observable
5924      * @param {Object} object The object with the events defined
5925      */
5926     addEvents : function(o){
5927         if(!this.events){
5928             this.events = {};
5929         }
5930         Roo.applyIf(this.events, o);
5931     },
5932
5933     /**
5934      * Checks to see if this object has any listeners for a specified event
5935      * @param {String} eventName The name of the event to check for
5936      * @return {Boolean} True if the event is being listened for, else false
5937      */
5938     hasListener : function(eventName){
5939         var e = this.events[eventName];
5940         return typeof e == "object" && e.listeners.length > 0;
5941     }
5942 };
5943 /**
5944  * Appends an event handler to this element (shorthand for addListener)
5945  * @param {String}   eventName     The type of event to listen for
5946  * @param {Function} handler        The method the event invokes
5947  * @param {Object}   scope (optional) The scope in which to execute the handler
5948  * function. The handler function's "this" context.
5949  * @param {Object}   options  (optional)
5950  * @method
5951  */
5952 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5953 /**
5954  * Removes a listener (shorthand for removeListener)
5955  * @param {String}   eventName     The type of event to listen for
5956  * @param {Function} handler        The handler to remove
5957  * @param {Object}   scope  (optional) The scope (this object) for the handler
5958  * @method
5959  */
5960 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5961
5962 /**
5963  * Starts capture on the specified Observable. All events will be passed
5964  * to the supplied function with the event name + standard signature of the event
5965  * <b>before</b> the event is fired. If the supplied function returns false,
5966  * the event will not fire.
5967  * @param {Observable} o The Observable to capture
5968  * @param {Function} fn The function to call
5969  * @param {Object} scope (optional) The scope (this object) for the fn
5970  * @static
5971  */
5972 Roo.util.Observable.capture = function(o, fn, scope){
5973     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5974 };
5975
5976 /**
5977  * Removes <b>all</b> added captures from the Observable.
5978  * @param {Observable} o The Observable to release
5979  * @static
5980  */
5981 Roo.util.Observable.releaseCapture = function(o){
5982     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5983 };
5984
5985 (function(){
5986
5987     var createBuffered = function(h, o, scope){
5988         var task = new Roo.util.DelayedTask();
5989         return function(){
5990             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5991         };
5992     };
5993
5994     var createSingle = function(h, e, fn, scope){
5995         return function(){
5996             e.removeListener(fn, scope);
5997             return h.apply(scope, arguments);
5998         };
5999     };
6000
6001     var createDelayed = function(h, o, scope){
6002         return function(){
6003             var args = Array.prototype.slice.call(arguments, 0);
6004             setTimeout(function(){
6005                 h.apply(scope, args);
6006             }, o.delay || 10);
6007         };
6008     };
6009
6010     Roo.util.Event = function(obj, name){
6011         this.name = name;
6012         this.obj = obj;
6013         this.listeners = [];
6014     };
6015
6016     Roo.util.Event.prototype = {
6017         addListener : function(fn, scope, options){
6018             var o = options || {};
6019             scope = scope || this.obj;
6020             if(!this.isListening(fn, scope)){
6021                 var l = {fn: fn, scope: scope, options: o};
6022                 var h = fn;
6023                 if(o.delay){
6024                     h = createDelayed(h, o, scope);
6025                 }
6026                 if(o.single){
6027                     h = createSingle(h, this, fn, scope);
6028                 }
6029                 if(o.buffer){
6030                     h = createBuffered(h, o, scope);
6031                 }
6032                 l.fireFn = h;
6033                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6034                     this.listeners.push(l);
6035                 }else{
6036                     this.listeners = this.listeners.slice(0);
6037                     this.listeners.push(l);
6038                 }
6039             }
6040         },
6041
6042         findListener : function(fn, scope){
6043             scope = scope || this.obj;
6044             var ls = this.listeners;
6045             for(var i = 0, len = ls.length; i < len; i++){
6046                 var l = ls[i];
6047                 if(l.fn == fn && l.scope == scope){
6048                     return i;
6049                 }
6050             }
6051             return -1;
6052         },
6053
6054         isListening : function(fn, scope){
6055             return this.findListener(fn, scope) != -1;
6056         },
6057
6058         removeListener : function(fn, scope){
6059             var index;
6060             if((index = this.findListener(fn, scope)) != -1){
6061                 if(!this.firing){
6062                     this.listeners.splice(index, 1);
6063                 }else{
6064                     this.listeners = this.listeners.slice(0);
6065                     this.listeners.splice(index, 1);
6066                 }
6067                 return true;
6068             }
6069             return false;
6070         },
6071
6072         clearListeners : function(){
6073             this.listeners = [];
6074         },
6075
6076         fire : function(){
6077             var ls = this.listeners, scope, len = ls.length;
6078             if(len > 0){
6079                 this.firing = true;
6080                 var args = Array.prototype.slice.call(arguments, 0);
6081                 for(var i = 0; i < len; i++){
6082                     var l = ls[i];
6083                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6084                         this.firing = false;
6085                         return false;
6086                     }
6087                 }
6088                 this.firing = false;
6089             }
6090             return true;
6091         }
6092     };
6093 })();/*
6094  * RooJS Library 
6095  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6096  *
6097  * Licence LGPL 
6098  *
6099  */
6100  
6101 /**
6102  * @class Roo.Document
6103  * @extends Roo.util.Observable
6104  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6105  * 
6106  * @param {Object} config the methods and properties of the 'base' class for the application.
6107  * 
6108  *  Generic Page handler - implement this to start your app..
6109  * 
6110  * eg.
6111  *  MyProject = new Roo.Document({
6112         events : {
6113             'load' : true // your events..
6114         },
6115         listeners : {
6116             'ready' : function() {
6117                 // fired on Roo.onReady()
6118             }
6119         }
6120  * 
6121  */
6122 Roo.Document = function(cfg) {
6123      
6124     this.addEvents({ 
6125         'ready' : true
6126     });
6127     Roo.util.Observable.call(this,cfg);
6128     
6129     var _this = this;
6130     
6131     Roo.onReady(function() {
6132         _this.fireEvent('ready');
6133     },null,false);
6134     
6135     
6136 }
6137
6138 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6139  * Based on:
6140  * Ext JS Library 1.1.1
6141  * Copyright(c) 2006-2007, Ext JS, LLC.
6142  *
6143  * Originally Released Under LGPL - original licence link has changed is not relivant.
6144  *
6145  * Fork - LGPL
6146  * <script type="text/javascript">
6147  */
6148
6149 /**
6150  * @class Roo.EventManager
6151  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6152  * several useful events directly.
6153  * See {@link Roo.EventObject} for more details on normalized event objects.
6154  * @singleton
6155  */
6156 Roo.EventManager = function(){
6157     var docReadyEvent, docReadyProcId, docReadyState = false;
6158     var resizeEvent, resizeTask, textEvent, textSize;
6159     var E = Roo.lib.Event;
6160     var D = Roo.lib.Dom;
6161
6162     
6163     
6164
6165     var fireDocReady = function(){
6166         if(!docReadyState){
6167             docReadyState = true;
6168             Roo.isReady = true;
6169             if(docReadyProcId){
6170                 clearInterval(docReadyProcId);
6171             }
6172             if(Roo.isGecko || Roo.isOpera) {
6173                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6174             }
6175             if(Roo.isIE){
6176                 var defer = document.getElementById("ie-deferred-loader");
6177                 if(defer){
6178                     defer.onreadystatechange = null;
6179                     defer.parentNode.removeChild(defer);
6180                 }
6181             }
6182             if(docReadyEvent){
6183                 docReadyEvent.fire();
6184                 docReadyEvent.clearListeners();
6185             }
6186         }
6187     };
6188     
6189     var initDocReady = function(){
6190         docReadyEvent = new Roo.util.Event();
6191         if(Roo.isGecko || Roo.isOpera) {
6192             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6193         }else if(Roo.isIE){
6194             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6195             var defer = document.getElementById("ie-deferred-loader");
6196             defer.onreadystatechange = function(){
6197                 if(this.readyState == "complete"){
6198                     fireDocReady();
6199                 }
6200             };
6201         }else if(Roo.isSafari){ 
6202             docReadyProcId = setInterval(function(){
6203                 var rs = document.readyState;
6204                 if(rs == "complete") {
6205                     fireDocReady();     
6206                  }
6207             }, 10);
6208         }
6209         // no matter what, make sure it fires on load
6210         E.on(window, "load", fireDocReady);
6211     };
6212
6213     var createBuffered = function(h, o){
6214         var task = new Roo.util.DelayedTask(h);
6215         return function(e){
6216             // create new event object impl so new events don't wipe out properties
6217             e = new Roo.EventObjectImpl(e);
6218             task.delay(o.buffer, h, null, [e]);
6219         };
6220     };
6221
6222     var createSingle = function(h, el, ename, fn){
6223         return function(e){
6224             Roo.EventManager.removeListener(el, ename, fn);
6225             h(e);
6226         };
6227     };
6228
6229     var createDelayed = function(h, o){
6230         return function(e){
6231             // create new event object impl so new events don't wipe out properties
6232             e = new Roo.EventObjectImpl(e);
6233             setTimeout(function(){
6234                 h(e);
6235             }, o.delay || 10);
6236         };
6237     };
6238     var transitionEndVal = false;
6239     
6240     var transitionEnd = function()
6241     {
6242         if (transitionEndVal) {
6243             return transitionEndVal;
6244         }
6245         var el = document.createElement('div');
6246
6247         var transEndEventNames = {
6248             WebkitTransition : 'webkitTransitionEnd',
6249             MozTransition    : 'transitionend',
6250             OTransition      : 'oTransitionEnd otransitionend',
6251             transition       : 'transitionend'
6252         };
6253     
6254         for (var name in transEndEventNames) {
6255             if (el.style[name] !== undefined) {
6256                 transitionEndVal = transEndEventNames[name];
6257                 return  transitionEndVal ;
6258             }
6259         }
6260     }
6261     
6262
6263     var listen = function(element, ename, opt, fn, scope){
6264         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6265         fn = fn || o.fn; scope = scope || o.scope;
6266         var el = Roo.getDom(element);
6267         
6268         
6269         if(!el){
6270             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6271         }
6272         
6273         if (ename == 'transitionend') {
6274             ename = transitionEnd();
6275         }
6276         var h = function(e){
6277             e = Roo.EventObject.setEvent(e);
6278             var t;
6279             if(o.delegate){
6280                 t = e.getTarget(o.delegate, el);
6281                 if(!t){
6282                     return;
6283                 }
6284             }else{
6285                 t = e.target;
6286             }
6287             if(o.stopEvent === true){
6288                 e.stopEvent();
6289             }
6290             if(o.preventDefault === true){
6291                e.preventDefault();
6292             }
6293             if(o.stopPropagation === true){
6294                 e.stopPropagation();
6295             }
6296
6297             if(o.normalized === false){
6298                 e = e.browserEvent;
6299             }
6300
6301             fn.call(scope || el, e, t, o);
6302         };
6303         if(o.delay){
6304             h = createDelayed(h, o);
6305         }
6306         if(o.single){
6307             h = createSingle(h, el, ename, fn);
6308         }
6309         if(o.buffer){
6310             h = createBuffered(h, o);
6311         }
6312         
6313         fn._handlers = fn._handlers || [];
6314         
6315         
6316         fn._handlers.push([Roo.id(el), ename, h]);
6317         
6318         
6319          
6320         E.on(el, ename, h);
6321         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6322             el.addEventListener("DOMMouseScroll", h, false);
6323             E.on(window, 'unload', function(){
6324                 el.removeEventListener("DOMMouseScroll", h, false);
6325             });
6326         }
6327         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6328             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6329         }
6330         return h;
6331     };
6332
6333     var stopListening = function(el, ename, fn){
6334         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6335         if(hds){
6336             for(var i = 0, len = hds.length; i < len; i++){
6337                 var h = hds[i];
6338                 if(h[0] == id && h[1] == ename){
6339                     hd = h[2];
6340                     hds.splice(i, 1);
6341                     break;
6342                 }
6343             }
6344         }
6345         E.un(el, ename, hd);
6346         el = Roo.getDom(el);
6347         if(ename == "mousewheel" && el.addEventListener){
6348             el.removeEventListener("DOMMouseScroll", hd, false);
6349         }
6350         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6351             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6352         }
6353     };
6354
6355     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6356     
6357     var pub = {
6358         
6359         
6360         /** 
6361          * Fix for doc tools
6362          * @scope Roo.EventManager
6363          */
6364         
6365         
6366         /** 
6367          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6368          * object with a Roo.EventObject
6369          * @param {Function} fn        The method the event invokes
6370          * @param {Object}   scope    An object that becomes the scope of the handler
6371          * @param {boolean}  override If true, the obj passed in becomes
6372          *                             the execution scope of the listener
6373          * @return {Function} The wrapped function
6374          * @deprecated
6375          */
6376         wrap : function(fn, scope, override){
6377             return function(e){
6378                 Roo.EventObject.setEvent(e);
6379                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6380             };
6381         },
6382         
6383         /**
6384      * Appends an event handler to an element (shorthand for addListener)
6385      * @param {String/HTMLElement}   element        The html element or id to assign the
6386      * @param {String}   eventName The type of event to listen for
6387      * @param {Function} handler The method the event invokes
6388      * @param {Object}   scope (optional) The scope in which to execute the handler
6389      * function. The handler function's "this" context.
6390      * @param {Object}   options (optional) An object containing handler configuration
6391      * properties. This may contain any of the following properties:<ul>
6392      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6393      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6394      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6395      * <li>preventDefault {Boolean} True to prevent the default action</li>
6396      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6397      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6398      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6399      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6400      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6401      * by the specified number of milliseconds. If the event fires again within that time, the original
6402      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6403      * </ul><br>
6404      * <p>
6405      * <b>Combining Options</b><br>
6406      * Using the options argument, it is possible to combine different types of listeners:<br>
6407      * <br>
6408      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6409      * Code:<pre><code>
6410 el.on('click', this.onClick, this, {
6411     single: true,
6412     delay: 100,
6413     stopEvent : true,
6414     forumId: 4
6415 });</code></pre>
6416      * <p>
6417      * <b>Attaching multiple handlers in 1 call</b><br>
6418       * The method also allows for a single argument to be passed which is a config object containing properties
6419      * which specify multiple handlers.
6420      * <p>
6421      * Code:<pre><code>
6422 el.on({
6423     'click' : {
6424         fn: this.onClick
6425         scope: this,
6426         delay: 100
6427     },
6428     'mouseover' : {
6429         fn: this.onMouseOver
6430         scope: this
6431     },
6432     'mouseout' : {
6433         fn: this.onMouseOut
6434         scope: this
6435     }
6436 });</code></pre>
6437      * <p>
6438      * Or a shorthand syntax:<br>
6439      * Code:<pre><code>
6440 el.on({
6441     'click' : this.onClick,
6442     'mouseover' : this.onMouseOver,
6443     'mouseout' : this.onMouseOut
6444     scope: this
6445 });</code></pre>
6446      */
6447         addListener : function(element, eventName, fn, scope, options){
6448             if(typeof eventName == "object"){
6449                 var o = eventName;
6450                 for(var e in o){
6451                     if(propRe.test(e)){
6452                         continue;
6453                     }
6454                     if(typeof o[e] == "function"){
6455                         // shared options
6456                         listen(element, e, o, o[e], o.scope);
6457                     }else{
6458                         // individual options
6459                         listen(element, e, o[e]);
6460                     }
6461                 }
6462                 return;
6463             }
6464             return listen(element, eventName, options, fn, scope);
6465         },
6466         
6467         /**
6468          * Removes an event handler
6469          *
6470          * @param {String/HTMLElement}   element        The id or html element to remove the 
6471          *                             event from
6472          * @param {String}   eventName     The type of event
6473          * @param {Function} fn
6474          * @return {Boolean} True if a listener was actually removed
6475          */
6476         removeListener : function(element, eventName, fn){
6477             return stopListening(element, eventName, fn);
6478         },
6479         
6480         /**
6481          * Fires when the document is ready (before onload and before images are loaded). Can be 
6482          * accessed shorthanded Roo.onReady().
6483          * @param {Function} fn        The method the event invokes
6484          * @param {Object}   scope    An  object that becomes the scope of the handler
6485          * @param {boolean}  options
6486          */
6487         onDocumentReady : function(fn, scope, options){
6488             if(docReadyState){ // if it already fired
6489                 docReadyEvent.addListener(fn, scope, options);
6490                 docReadyEvent.fire();
6491                 docReadyEvent.clearListeners();
6492                 return;
6493             }
6494             if(!docReadyEvent){
6495                 initDocReady();
6496             }
6497             docReadyEvent.addListener(fn, scope, options);
6498         },
6499         
6500         /**
6501          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6502          * @param {Function} fn        The method the event invokes
6503          * @param {Object}   scope    An object that becomes the scope of the handler
6504          * @param {boolean}  options
6505          */
6506         onWindowResize : function(fn, scope, options){
6507             if(!resizeEvent){
6508                 resizeEvent = new Roo.util.Event();
6509                 resizeTask = new Roo.util.DelayedTask(function(){
6510                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6511                 });
6512                 E.on(window, "resize", function(){
6513                     if(Roo.isIE){
6514                         resizeTask.delay(50);
6515                     }else{
6516                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6517                     }
6518                 });
6519             }
6520             resizeEvent.addListener(fn, scope, options);
6521         },
6522
6523         /**
6524          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6525          * @param {Function} fn        The method the event invokes
6526          * @param {Object}   scope    An object that becomes the scope of the handler
6527          * @param {boolean}  options
6528          */
6529         onTextResize : function(fn, scope, options){
6530             if(!textEvent){
6531                 textEvent = new Roo.util.Event();
6532                 var textEl = new Roo.Element(document.createElement('div'));
6533                 textEl.dom.className = 'x-text-resize';
6534                 textEl.dom.innerHTML = 'X';
6535                 textEl.appendTo(document.body);
6536                 textSize = textEl.dom.offsetHeight;
6537                 setInterval(function(){
6538                     if(textEl.dom.offsetHeight != textSize){
6539                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6540                     }
6541                 }, this.textResizeInterval);
6542             }
6543             textEvent.addListener(fn, scope, options);
6544         },
6545
6546         /**
6547          * Removes the passed window resize listener.
6548          * @param {Function} fn        The method the event invokes
6549          * @param {Object}   scope    The scope of handler
6550          */
6551         removeResizeListener : function(fn, scope){
6552             if(resizeEvent){
6553                 resizeEvent.removeListener(fn, scope);
6554             }
6555         },
6556
6557         // private
6558         fireResize : function(){
6559             if(resizeEvent){
6560                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6561             }   
6562         },
6563         /**
6564          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6565          */
6566         ieDeferSrc : false,
6567         /**
6568          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6569          */
6570         textResizeInterval : 50
6571     };
6572     
6573     /**
6574      * Fix for doc tools
6575      * @scopeAlias pub=Roo.EventManager
6576      */
6577     
6578      /**
6579      * Appends an event handler to an element (shorthand for addListener)
6580      * @param {String/HTMLElement}   element        The html element or id to assign the
6581      * @param {String}   eventName The type of event to listen for
6582      * @param {Function} handler The method the event invokes
6583      * @param {Object}   scope (optional) The scope in which to execute the handler
6584      * function. The handler function's "this" context.
6585      * @param {Object}   options (optional) An object containing handler configuration
6586      * properties. This may contain any of the following properties:<ul>
6587      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6588      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6589      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6590      * <li>preventDefault {Boolean} True to prevent the default action</li>
6591      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6592      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6593      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6594      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6595      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6596      * by the specified number of milliseconds. If the event fires again within that time, the original
6597      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6598      * </ul><br>
6599      * <p>
6600      * <b>Combining Options</b><br>
6601      * Using the options argument, it is possible to combine different types of listeners:<br>
6602      * <br>
6603      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6604      * Code:<pre><code>
6605 el.on('click', this.onClick, this, {
6606     single: true,
6607     delay: 100,
6608     stopEvent : true,
6609     forumId: 4
6610 });</code></pre>
6611      * <p>
6612      * <b>Attaching multiple handlers in 1 call</b><br>
6613       * The method also allows for a single argument to be passed which is a config object containing properties
6614      * which specify multiple handlers.
6615      * <p>
6616      * Code:<pre><code>
6617 el.on({
6618     'click' : {
6619         fn: this.onClick
6620         scope: this,
6621         delay: 100
6622     },
6623     'mouseover' : {
6624         fn: this.onMouseOver
6625         scope: this
6626     },
6627     'mouseout' : {
6628         fn: this.onMouseOut
6629         scope: this
6630     }
6631 });</code></pre>
6632      * <p>
6633      * Or a shorthand syntax:<br>
6634      * Code:<pre><code>
6635 el.on({
6636     'click' : this.onClick,
6637     'mouseover' : this.onMouseOver,
6638     'mouseout' : this.onMouseOut
6639     scope: this
6640 });</code></pre>
6641      */
6642     pub.on = pub.addListener;
6643     pub.un = pub.removeListener;
6644
6645     pub.stoppedMouseDownEvent = new Roo.util.Event();
6646     return pub;
6647 }();
6648 /**
6649   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6650   * @param {Function} fn        The method the event invokes
6651   * @param {Object}   scope    An  object that becomes the scope of the handler
6652   * @param {boolean}  override If true, the obj passed in becomes
6653   *                             the execution scope of the listener
6654   * @member Roo
6655   * @method onReady
6656  */
6657 Roo.onReady = Roo.EventManager.onDocumentReady;
6658
6659 Roo.onReady(function(){
6660     var bd = Roo.get(document.body);
6661     if(!bd){ return; }
6662
6663     var cls = [
6664             Roo.isIE ? "roo-ie"
6665             : Roo.isIE11 ? "roo-ie11"
6666             : Roo.isEdge ? "roo-edge"
6667             : Roo.isGecko ? "roo-gecko"
6668             : Roo.isOpera ? "roo-opera"
6669             : Roo.isSafari ? "roo-safari" : ""];
6670
6671     if(Roo.isMac){
6672         cls.push("roo-mac");
6673     }
6674     if(Roo.isLinux){
6675         cls.push("roo-linux");
6676     }
6677     if(Roo.isIOS){
6678         cls.push("roo-ios");
6679     }
6680     if(Roo.isTouch){
6681         cls.push("roo-touch");
6682     }
6683     if(Roo.isBorderBox){
6684         cls.push('roo-border-box');
6685     }
6686     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6687         var p = bd.dom.parentNode;
6688         if(p){
6689             p.className += ' roo-strict';
6690         }
6691     }
6692     bd.addClass(cls.join(' '));
6693 });
6694
6695 /**
6696  * @class Roo.EventObject
6697  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6698  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6699  * Example:
6700  * <pre><code>
6701  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6702     e.preventDefault();
6703     var target = e.getTarget();
6704     ...
6705  }
6706  var myDiv = Roo.get("myDiv");
6707  myDiv.on("click", handleClick);
6708  //or
6709  Roo.EventManager.on("myDiv", 'click', handleClick);
6710  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6711  </code></pre>
6712  * @singleton
6713  */
6714 Roo.EventObject = function(){
6715     
6716     var E = Roo.lib.Event;
6717     
6718     // safari keypress events for special keys return bad keycodes
6719     var safariKeys = {
6720         63234 : 37, // left
6721         63235 : 39, // right
6722         63232 : 38, // up
6723         63233 : 40, // down
6724         63276 : 33, // page up
6725         63277 : 34, // page down
6726         63272 : 46, // delete
6727         63273 : 36, // home
6728         63275 : 35  // end
6729     };
6730
6731     // normalize button clicks
6732     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6733                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6734
6735     Roo.EventObjectImpl = function(e){
6736         if(e){
6737             this.setEvent(e.browserEvent || e);
6738         }
6739     };
6740     Roo.EventObjectImpl.prototype = {
6741         /**
6742          * Used to fix doc tools.
6743          * @scope Roo.EventObject.prototype
6744          */
6745             
6746
6747         
6748         
6749         /** The normal browser event */
6750         browserEvent : null,
6751         /** The button pressed in a mouse event */
6752         button : -1,
6753         /** True if the shift key was down during the event */
6754         shiftKey : false,
6755         /** True if the control key was down during the event */
6756         ctrlKey : false,
6757         /** True if the alt key was down during the event */
6758         altKey : false,
6759
6760         /** Key constant 
6761         * @type Number */
6762         BACKSPACE : 8,
6763         /** Key constant 
6764         * @type Number */
6765         TAB : 9,
6766         /** Key constant 
6767         * @type Number */
6768         RETURN : 13,
6769         /** Key constant 
6770         * @type Number */
6771         ENTER : 13,
6772         /** Key constant 
6773         * @type Number */
6774         SHIFT : 16,
6775         /** Key constant 
6776         * @type Number */
6777         CONTROL : 17,
6778         /** Key constant 
6779         * @type Number */
6780         ESC : 27,
6781         /** Key constant 
6782         * @type Number */
6783         SPACE : 32,
6784         /** Key constant 
6785         * @type Number */
6786         PAGEUP : 33,
6787         /** Key constant 
6788         * @type Number */
6789         PAGEDOWN : 34,
6790         /** Key constant 
6791         * @type Number */
6792         END : 35,
6793         /** Key constant 
6794         * @type Number */
6795         HOME : 36,
6796         /** Key constant 
6797         * @type Number */
6798         LEFT : 37,
6799         /** Key constant 
6800         * @type Number */
6801         UP : 38,
6802         /** Key constant 
6803         * @type Number */
6804         RIGHT : 39,
6805         /** Key constant 
6806         * @type Number */
6807         DOWN : 40,
6808         /** Key constant 
6809         * @type Number */
6810         DELETE : 46,
6811         /** Key constant 
6812         * @type Number */
6813         F5 : 116,
6814
6815            /** @private */
6816         setEvent : function(e){
6817             if(e == this || (e && e.browserEvent)){ // already wrapped
6818                 return e;
6819             }
6820             this.browserEvent = e;
6821             if(e){
6822                 // normalize buttons
6823                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6824                 if(e.type == 'click' && this.button == -1){
6825                     this.button = 0;
6826                 }
6827                 this.type = e.type;
6828                 this.shiftKey = e.shiftKey;
6829                 // mac metaKey behaves like ctrlKey
6830                 this.ctrlKey = e.ctrlKey || e.metaKey;
6831                 this.altKey = e.altKey;
6832                 // in getKey these will be normalized for the mac
6833                 this.keyCode = e.keyCode;
6834                 // keyup warnings on firefox.
6835                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6836                 // cache the target for the delayed and or buffered events
6837                 this.target = E.getTarget(e);
6838                 // same for XY
6839                 this.xy = E.getXY(e);
6840             }else{
6841                 this.button = -1;
6842                 this.shiftKey = false;
6843                 this.ctrlKey = false;
6844                 this.altKey = false;
6845                 this.keyCode = 0;
6846                 this.charCode =0;
6847                 this.target = null;
6848                 this.xy = [0, 0];
6849             }
6850             return this;
6851         },
6852
6853         /**
6854          * Stop the event (preventDefault and stopPropagation)
6855          */
6856         stopEvent : function(){
6857             if(this.browserEvent){
6858                 if(this.browserEvent.type == 'mousedown'){
6859                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6860                 }
6861                 E.stopEvent(this.browserEvent);
6862             }
6863         },
6864
6865         /**
6866          * Prevents the browsers default handling of the event.
6867          */
6868         preventDefault : function(){
6869             if(this.browserEvent){
6870                 E.preventDefault(this.browserEvent);
6871             }
6872         },
6873
6874         /** @private */
6875         isNavKeyPress : function(){
6876             var k = this.keyCode;
6877             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6878             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6879         },
6880
6881         isSpecialKey : function(){
6882             var k = this.keyCode;
6883             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6884             (k == 16) || (k == 17) ||
6885             (k >= 18 && k <= 20) ||
6886             (k >= 33 && k <= 35) ||
6887             (k >= 36 && k <= 39) ||
6888             (k >= 44 && k <= 45);
6889         },
6890         /**
6891          * Cancels bubbling of the event.
6892          */
6893         stopPropagation : function(){
6894             if(this.browserEvent){
6895                 if(this.type == 'mousedown'){
6896                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6897                 }
6898                 E.stopPropagation(this.browserEvent);
6899             }
6900         },
6901
6902         /**
6903          * Gets the key code for the event.
6904          * @return {Number}
6905          */
6906         getCharCode : function(){
6907             return this.charCode || this.keyCode;
6908         },
6909
6910         /**
6911          * Returns a normalized keyCode for the event.
6912          * @return {Number} The key code
6913          */
6914         getKey : function(){
6915             var k = this.keyCode || this.charCode;
6916             return Roo.isSafari ? (safariKeys[k] || k) : k;
6917         },
6918
6919         /**
6920          * Gets the x coordinate of the event.
6921          * @return {Number}
6922          */
6923         getPageX : function(){
6924             return this.xy[0];
6925         },
6926
6927         /**
6928          * Gets the y coordinate of the event.
6929          * @return {Number}
6930          */
6931         getPageY : function(){
6932             return this.xy[1];
6933         },
6934
6935         /**
6936          * Gets the time of the event.
6937          * @return {Number}
6938          */
6939         getTime : function(){
6940             if(this.browserEvent){
6941                 return E.getTime(this.browserEvent);
6942             }
6943             return null;
6944         },
6945
6946         /**
6947          * Gets the page coordinates of the event.
6948          * @return {Array} The xy values like [x, y]
6949          */
6950         getXY : function(){
6951             return this.xy;
6952         },
6953
6954         /**
6955          * Gets the target for the event.
6956          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6957          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6958                 search as a number or element (defaults to 10 || document.body)
6959          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6960          * @return {HTMLelement}
6961          */
6962         getTarget : function(selector, maxDepth, returnEl){
6963             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6964         },
6965         /**
6966          * Gets the related target.
6967          * @return {HTMLElement}
6968          */
6969         getRelatedTarget : function(){
6970             if(this.browserEvent){
6971                 return E.getRelatedTarget(this.browserEvent);
6972             }
6973             return null;
6974         },
6975
6976         /**
6977          * Normalizes mouse wheel delta across browsers
6978          * @return {Number} The delta
6979          */
6980         getWheelDelta : function(){
6981             var e = this.browserEvent;
6982             var delta = 0;
6983             if(e.wheelDelta){ /* IE/Opera. */
6984                 delta = e.wheelDelta/120;
6985             }else if(e.detail){ /* Mozilla case. */
6986                 delta = -e.detail/3;
6987             }
6988             return delta;
6989         },
6990
6991         /**
6992          * Returns true if the control, meta, shift or alt key was pressed during this event.
6993          * @return {Boolean}
6994          */
6995         hasModifier : function(){
6996             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6997         },
6998
6999         /**
7000          * Returns true if the target of this event equals el or is a child of el
7001          * @param {String/HTMLElement/Element} el
7002          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7003          * @return {Boolean}
7004          */
7005         within : function(el, related){
7006             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7007             return t && Roo.fly(el).contains(t);
7008         },
7009
7010         getPoint : function(){
7011             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7012         }
7013     };
7014
7015     return new Roo.EventObjectImpl();
7016 }();
7017             
7018     /*
7019  * Based on:
7020  * Ext JS Library 1.1.1
7021  * Copyright(c) 2006-2007, Ext JS, LLC.
7022  *
7023  * Originally Released Under LGPL - original licence link has changed is not relivant.
7024  *
7025  * Fork - LGPL
7026  * <script type="text/javascript">
7027  */
7028
7029  
7030 // was in Composite Element!??!?!
7031  
7032 (function(){
7033     var D = Roo.lib.Dom;
7034     var E = Roo.lib.Event;
7035     var A = Roo.lib.Anim;
7036
7037     // local style camelizing for speed
7038     var propCache = {};
7039     var camelRe = /(-[a-z])/gi;
7040     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7041     var view = document.defaultView;
7042
7043 /**
7044  * @class Roo.Element
7045  * Represents an Element in the DOM.<br><br>
7046  * Usage:<br>
7047 <pre><code>
7048 var el = Roo.get("my-div");
7049
7050 // or with getEl
7051 var el = getEl("my-div");
7052
7053 // or with a DOM element
7054 var el = Roo.get(myDivElement);
7055 </code></pre>
7056  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7057  * each call instead of constructing a new one.<br><br>
7058  * <b>Animations</b><br />
7059  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7060  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7061 <pre>
7062 Option    Default   Description
7063 --------- --------  ---------------------------------------------
7064 duration  .35       The duration of the animation in seconds
7065 easing    easeOut   The YUI easing method
7066 callback  none      A function to execute when the anim completes
7067 scope     this      The scope (this) of the callback function
7068 </pre>
7069 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7070 * manipulate the animation. Here's an example:
7071 <pre><code>
7072 var el = Roo.get("my-div");
7073
7074 // no animation
7075 el.setWidth(100);
7076
7077 // default animation
7078 el.setWidth(100, true);
7079
7080 // animation with some options set
7081 el.setWidth(100, {
7082     duration: 1,
7083     callback: this.foo,
7084     scope: this
7085 });
7086
7087 // using the "anim" property to get the Anim object
7088 var opt = {
7089     duration: 1,
7090     callback: this.foo,
7091     scope: this
7092 };
7093 el.setWidth(100, opt);
7094 ...
7095 if(opt.anim.isAnimated()){
7096     opt.anim.stop();
7097 }
7098 </code></pre>
7099 * <b> Composite (Collections of) Elements</b><br />
7100  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7101  * @constructor Create a new Element directly.
7102  * @param {String/HTMLElement} element
7103  * @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).
7104  */
7105     Roo.Element = function(element, forceNew){
7106         var dom = typeof element == "string" ?
7107                 document.getElementById(element) : element;
7108         if(!dom){ // invalid id/element
7109             return null;
7110         }
7111         var id = dom.id;
7112         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7113             return Roo.Element.cache[id];
7114         }
7115
7116         /**
7117          * The DOM element
7118          * @type HTMLElement
7119          */
7120         this.dom = dom;
7121
7122         /**
7123          * The DOM element ID
7124          * @type String
7125          */
7126         this.id = id || Roo.id(dom);
7127     };
7128
7129     var El = Roo.Element;
7130
7131     El.prototype = {
7132         /**
7133          * The element's default display mode  (defaults to "")
7134          * @type String
7135          */
7136         originalDisplay : "",
7137
7138         visibilityMode : 1,
7139         /**
7140          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7141          * @type String
7142          */
7143         defaultUnit : "px",
7144         
7145         /**
7146          * Sets the element's visibility mode. When setVisible() is called it
7147          * will use this to determine whether to set the visibility or the display property.
7148          * @param visMode Element.VISIBILITY or Element.DISPLAY
7149          * @return {Roo.Element} this
7150          */
7151         setVisibilityMode : function(visMode){
7152             this.visibilityMode = visMode;
7153             return this;
7154         },
7155         /**
7156          * Convenience method for setVisibilityMode(Element.DISPLAY)
7157          * @param {String} display (optional) What to set display to when visible
7158          * @return {Roo.Element} this
7159          */
7160         enableDisplayMode : function(display){
7161             this.setVisibilityMode(El.DISPLAY);
7162             if(typeof display != "undefined") { this.originalDisplay = display; }
7163             return this;
7164         },
7165
7166         /**
7167          * 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)
7168          * @param {String} selector The simple selector to test
7169          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7170                 search as a number or element (defaults to 10 || document.body)
7171          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7172          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7173          */
7174         findParent : function(simpleSelector, maxDepth, returnEl){
7175             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7176             maxDepth = maxDepth || 50;
7177             if(typeof maxDepth != "number"){
7178                 stopEl = Roo.getDom(maxDepth);
7179                 maxDepth = 10;
7180             }
7181             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7182                 if(dq.is(p, simpleSelector)){
7183                     return returnEl ? Roo.get(p) : p;
7184                 }
7185                 depth++;
7186                 p = p.parentNode;
7187             }
7188             return null;
7189         },
7190
7191
7192         /**
7193          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7194          * @param {String} selector The simple selector to test
7195          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7196                 search as a number or element (defaults to 10 || document.body)
7197          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7198          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7199          */
7200         findParentNode : function(simpleSelector, maxDepth, returnEl){
7201             var p = Roo.fly(this.dom.parentNode, '_internal');
7202             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7203         },
7204         
7205         /**
7206          * Looks at  the scrollable parent element
7207          */
7208         findScrollableParent : function()
7209         {
7210             var overflowRegex = /(auto|scroll)/;
7211             
7212             if(this.getStyle('position') === 'fixed'){
7213                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7214             }
7215             
7216             var excludeStaticParent = this.getStyle('position') === "absolute";
7217             
7218             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7219                 
7220                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7221                     continue;
7222                 }
7223                 
7224                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7225                     return parent;
7226                 }
7227                 
7228                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7229                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7230                 }
7231             }
7232             
7233             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7234         },
7235
7236         /**
7237          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7238          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7239          * @param {String} selector The simple selector to test
7240          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7241                 search as a number or element (defaults to 10 || document.body)
7242          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7243          */
7244         up : function(simpleSelector, maxDepth){
7245             return this.findParentNode(simpleSelector, maxDepth, true);
7246         },
7247
7248
7249
7250         /**
7251          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7252          * @param {String} selector The simple selector to test
7253          * @return {Boolean} True if this element matches the selector, else false
7254          */
7255         is : function(simpleSelector){
7256             return Roo.DomQuery.is(this.dom, simpleSelector);
7257         },
7258
7259         /**
7260          * Perform animation on this element.
7261          * @param {Object} args The YUI animation control args
7262          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7263          * @param {Function} onComplete (optional) Function to call when animation completes
7264          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7265          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7266          * @return {Roo.Element} this
7267          */
7268         animate : function(args, duration, onComplete, easing, animType){
7269             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7270             return this;
7271         },
7272
7273         /*
7274          * @private Internal animation call
7275          */
7276         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7277             animType = animType || 'run';
7278             opt = opt || {};
7279             var anim = Roo.lib.Anim[animType](
7280                 this.dom, args,
7281                 (opt.duration || defaultDur) || .35,
7282                 (opt.easing || defaultEase) || 'easeOut',
7283                 function(){
7284                     Roo.callback(cb, this);
7285                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7286                 },
7287                 this
7288             );
7289             opt.anim = anim;
7290             return anim;
7291         },
7292
7293         // private legacy anim prep
7294         preanim : function(a, i){
7295             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7296         },
7297
7298         /**
7299          * Removes worthless text nodes
7300          * @param {Boolean} forceReclean (optional) By default the element
7301          * keeps track if it has been cleaned already so
7302          * you can call this over and over. However, if you update the element and
7303          * need to force a reclean, you can pass true.
7304          */
7305         clean : function(forceReclean){
7306             if(this.isCleaned && forceReclean !== true){
7307                 return this;
7308             }
7309             var ns = /\S/;
7310             var d = this.dom, n = d.firstChild, ni = -1;
7311             while(n){
7312                 var nx = n.nextSibling;
7313                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7314                     d.removeChild(n);
7315                 }else{
7316                     n.nodeIndex = ++ni;
7317                 }
7318                 n = nx;
7319             }
7320             this.isCleaned = true;
7321             return this;
7322         },
7323
7324         // private
7325         calcOffsetsTo : function(el){
7326             el = Roo.get(el);
7327             var d = el.dom;
7328             var restorePos = false;
7329             if(el.getStyle('position') == 'static'){
7330                 el.position('relative');
7331                 restorePos = true;
7332             }
7333             var x = 0, y =0;
7334             var op = this.dom;
7335             while(op && op != d && op.tagName != 'HTML'){
7336                 x+= op.offsetLeft;
7337                 y+= op.offsetTop;
7338                 op = op.offsetParent;
7339             }
7340             if(restorePos){
7341                 el.position('static');
7342             }
7343             return [x, y];
7344         },
7345
7346         /**
7347          * Scrolls this element into view within the passed container.
7348          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7349          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7350          * @return {Roo.Element} this
7351          */
7352         scrollIntoView : function(container, hscroll){
7353             var c = Roo.getDom(container) || document.body;
7354             var el = this.dom;
7355
7356             var o = this.calcOffsetsTo(c),
7357                 l = o[0],
7358                 t = o[1],
7359                 b = t+el.offsetHeight,
7360                 r = l+el.offsetWidth;
7361
7362             var ch = c.clientHeight;
7363             var ct = parseInt(c.scrollTop, 10);
7364             var cl = parseInt(c.scrollLeft, 10);
7365             var cb = ct + ch;
7366             var cr = cl + c.clientWidth;
7367
7368             if(t < ct){
7369                 c.scrollTop = t;
7370             }else if(b > cb){
7371                 c.scrollTop = b-ch;
7372             }
7373
7374             if(hscroll !== false){
7375                 if(l < cl){
7376                     c.scrollLeft = l;
7377                 }else if(r > cr){
7378                     c.scrollLeft = r-c.clientWidth;
7379                 }
7380             }
7381             return this;
7382         },
7383
7384         // private
7385         scrollChildIntoView : function(child, hscroll){
7386             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7387         },
7388
7389         /**
7390          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7391          * the new height may not be available immediately.
7392          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7393          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7394          * @param {Function} onComplete (optional) Function to call when animation completes
7395          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7396          * @return {Roo.Element} this
7397          */
7398         autoHeight : function(animate, duration, onComplete, easing){
7399             var oldHeight = this.getHeight();
7400             this.clip();
7401             this.setHeight(1); // force clipping
7402             setTimeout(function(){
7403                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7404                 if(!animate){
7405                     this.setHeight(height);
7406                     this.unclip();
7407                     if(typeof onComplete == "function"){
7408                         onComplete();
7409                     }
7410                 }else{
7411                     this.setHeight(oldHeight); // restore original height
7412                     this.setHeight(height, animate, duration, function(){
7413                         this.unclip();
7414                         if(typeof onComplete == "function") { onComplete(); }
7415                     }.createDelegate(this), easing);
7416                 }
7417             }.createDelegate(this), 0);
7418             return this;
7419         },
7420
7421         /**
7422          * Returns true if this element is an ancestor of the passed element
7423          * @param {HTMLElement/String} el The element to check
7424          * @return {Boolean} True if this element is an ancestor of el, else false
7425          */
7426         contains : function(el){
7427             if(!el){return false;}
7428             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7429         },
7430
7431         /**
7432          * Checks whether the element is currently visible using both visibility and display properties.
7433          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7434          * @return {Boolean} True if the element is currently visible, else false
7435          */
7436         isVisible : function(deep) {
7437             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7438             if(deep !== true || !vis){
7439                 return vis;
7440             }
7441             var p = this.dom.parentNode;
7442             while(p && p.tagName.toLowerCase() != "body"){
7443                 if(!Roo.fly(p, '_isVisible').isVisible()){
7444                     return false;
7445                 }
7446                 p = p.parentNode;
7447             }
7448             return true;
7449         },
7450
7451         /**
7452          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7453          * @param {String} selector The CSS selector
7454          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7455          * @return {CompositeElement/CompositeElementLite} The composite element
7456          */
7457         select : function(selector, unique){
7458             return El.select(selector, unique, this.dom);
7459         },
7460
7461         /**
7462          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7463          * @param {String} selector The CSS selector
7464          * @return {Array} An array of the matched nodes
7465          */
7466         query : function(selector, unique){
7467             return Roo.DomQuery.select(selector, this.dom);
7468         },
7469
7470         /**
7471          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7472          * @param {String} selector The CSS selector
7473          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7474          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7475          */
7476         child : function(selector, returnDom){
7477             var n = Roo.DomQuery.selectNode(selector, this.dom);
7478             return returnDom ? n : Roo.get(n);
7479         },
7480
7481         /**
7482          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7483          * @param {String} selector The CSS selector
7484          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7485          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7486          */
7487         down : function(selector, returnDom){
7488             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7489             return returnDom ? n : Roo.get(n);
7490         },
7491
7492         /**
7493          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7494          * @param {String} group The group the DD object is member of
7495          * @param {Object} config The DD config object
7496          * @param {Object} overrides An object containing methods to override/implement on the DD object
7497          * @return {Roo.dd.DD} The DD object
7498          */
7499         initDD : function(group, config, overrides){
7500             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7501             return Roo.apply(dd, overrides);
7502         },
7503
7504         /**
7505          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7506          * @param {String} group The group the DDProxy object is member of
7507          * @param {Object} config The DDProxy config object
7508          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7509          * @return {Roo.dd.DDProxy} The DDProxy object
7510          */
7511         initDDProxy : function(group, config, overrides){
7512             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7513             return Roo.apply(dd, overrides);
7514         },
7515
7516         /**
7517          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7518          * @param {String} group The group the DDTarget object is member of
7519          * @param {Object} config The DDTarget config object
7520          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7521          * @return {Roo.dd.DDTarget} The DDTarget object
7522          */
7523         initDDTarget : function(group, config, overrides){
7524             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7525             return Roo.apply(dd, overrides);
7526         },
7527
7528         /**
7529          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7530          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7531          * @param {Boolean} visible Whether the element is visible
7532          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7533          * @return {Roo.Element} this
7534          */
7535          setVisible : function(visible, animate){
7536             if(!animate || !A){
7537                 if(this.visibilityMode == El.DISPLAY){
7538                     this.setDisplayed(visible);
7539                 }else{
7540                     this.fixDisplay();
7541                     this.dom.style.visibility = visible ? "visible" : "hidden";
7542                 }
7543             }else{
7544                 // closure for composites
7545                 var dom = this.dom;
7546                 var visMode = this.visibilityMode;
7547                 if(visible){
7548                     this.setOpacity(.01);
7549                     this.setVisible(true);
7550                 }
7551                 this.anim({opacity: { to: (visible?1:0) }},
7552                       this.preanim(arguments, 1),
7553                       null, .35, 'easeIn', function(){
7554                          if(!visible){
7555                              if(visMode == El.DISPLAY){
7556                                  dom.style.display = "none";
7557                              }else{
7558                                  dom.style.visibility = "hidden";
7559                              }
7560                              Roo.get(dom).setOpacity(1);
7561                          }
7562                      });
7563             }
7564             return this;
7565         },
7566
7567         /**
7568          * Returns true if display is not "none"
7569          * @return {Boolean}
7570          */
7571         isDisplayed : function() {
7572             return this.getStyle("display") != "none";
7573         },
7574
7575         /**
7576          * Toggles the element's visibility or display, depending on visibility mode.
7577          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7578          * @return {Roo.Element} this
7579          */
7580         toggle : function(animate){
7581             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7582             return this;
7583         },
7584
7585         /**
7586          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7587          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7588          * @return {Roo.Element} this
7589          */
7590         setDisplayed : function(value) {
7591             if(typeof value == "boolean"){
7592                value = value ? this.originalDisplay : "none";
7593             }
7594             this.setStyle("display", value);
7595             return this;
7596         },
7597
7598         /**
7599          * Tries to focus the element. Any exceptions are caught and ignored.
7600          * @return {Roo.Element} this
7601          */
7602         focus : function() {
7603             try{
7604                 this.dom.focus();
7605             }catch(e){}
7606             return this;
7607         },
7608
7609         /**
7610          * Tries to blur the element. Any exceptions are caught and ignored.
7611          * @return {Roo.Element} this
7612          */
7613         blur : function() {
7614             try{
7615                 this.dom.blur();
7616             }catch(e){}
7617             return this;
7618         },
7619
7620         /**
7621          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7622          * @param {String/Array} className The CSS class to add, or an array of classes
7623          * @return {Roo.Element} this
7624          */
7625         addClass : function(className){
7626             if(className instanceof Array){
7627                 for(var i = 0, len = className.length; i < len; i++) {
7628                     this.addClass(className[i]);
7629                 }
7630             }else{
7631                 if(className && !this.hasClass(className)){
7632                     this.dom.className = this.dom.className + " " + className;
7633                 }
7634             }
7635             return this;
7636         },
7637
7638         /**
7639          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7640          * @param {String/Array} className The CSS class to add, or an array of classes
7641          * @return {Roo.Element} this
7642          */
7643         radioClass : function(className){
7644             var siblings = this.dom.parentNode.childNodes;
7645             for(var i = 0; i < siblings.length; i++) {
7646                 var s = siblings[i];
7647                 if(s.nodeType == 1){
7648                     Roo.get(s).removeClass(className);
7649                 }
7650             }
7651             this.addClass(className);
7652             return this;
7653         },
7654
7655         /**
7656          * Removes one or more CSS classes from the element.
7657          * @param {String/Array} className The CSS class to remove, or an array of classes
7658          * @return {Roo.Element} this
7659          */
7660         removeClass : function(className){
7661             if(!className || !this.dom.className){
7662                 return this;
7663             }
7664             if(className instanceof Array){
7665                 for(var i = 0, len = className.length; i < len; i++) {
7666                     this.removeClass(className[i]);
7667                 }
7668             }else{
7669                 if(this.hasClass(className)){
7670                     var re = this.classReCache[className];
7671                     if (!re) {
7672                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7673                        this.classReCache[className] = re;
7674                     }
7675                     this.dom.className =
7676                         this.dom.className.replace(re, " ");
7677                 }
7678             }
7679             return this;
7680         },
7681
7682         // private
7683         classReCache: {},
7684
7685         /**
7686          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7687          * @param {String} className The CSS class to toggle
7688          * @return {Roo.Element} this
7689          */
7690         toggleClass : function(className){
7691             if(this.hasClass(className)){
7692                 this.removeClass(className);
7693             }else{
7694                 this.addClass(className);
7695             }
7696             return this;
7697         },
7698
7699         /**
7700          * Checks if the specified CSS class exists on this element's DOM node.
7701          * @param {String} className The CSS class to check for
7702          * @return {Boolean} True if the class exists, else false
7703          */
7704         hasClass : function(className){
7705             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7706         },
7707
7708         /**
7709          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7710          * @param {String} oldClassName The CSS class to replace
7711          * @param {String} newClassName The replacement CSS class
7712          * @return {Roo.Element} this
7713          */
7714         replaceClass : function(oldClassName, newClassName){
7715             this.removeClass(oldClassName);
7716             this.addClass(newClassName);
7717             return this;
7718         },
7719
7720         /**
7721          * Returns an object with properties matching the styles requested.
7722          * For example, el.getStyles('color', 'font-size', 'width') might return
7723          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7724          * @param {String} style1 A style name
7725          * @param {String} style2 A style name
7726          * @param {String} etc.
7727          * @return {Object} The style object
7728          */
7729         getStyles : function(){
7730             var a = arguments, len = a.length, r = {};
7731             for(var i = 0; i < len; i++){
7732                 r[a[i]] = this.getStyle(a[i]);
7733             }
7734             return r;
7735         },
7736
7737         /**
7738          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7739          * @param {String} property The style property whose value is returned.
7740          * @return {String} The current value of the style property for this element.
7741          */
7742         getStyle : function(){
7743             return view && view.getComputedStyle ?
7744                 function(prop){
7745                     var el = this.dom, v, cs, camel;
7746                     if(prop == 'float'){
7747                         prop = "cssFloat";
7748                     }
7749                     if(el.style && (v = el.style[prop])){
7750                         return v;
7751                     }
7752                     if(cs = view.getComputedStyle(el, "")){
7753                         if(!(camel = propCache[prop])){
7754                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7755                         }
7756                         return cs[camel];
7757                     }
7758                     return null;
7759                 } :
7760                 function(prop){
7761                     var el = this.dom, v, cs, camel;
7762                     if(prop == 'opacity'){
7763                         if(typeof el.style.filter == 'string'){
7764                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7765                             if(m){
7766                                 var fv = parseFloat(m[1]);
7767                                 if(!isNaN(fv)){
7768                                     return fv ? fv / 100 : 0;
7769                                 }
7770                             }
7771                         }
7772                         return 1;
7773                     }else if(prop == 'float'){
7774                         prop = "styleFloat";
7775                     }
7776                     if(!(camel = propCache[prop])){
7777                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7778                     }
7779                     if(v = el.style[camel]){
7780                         return v;
7781                     }
7782                     if(cs = el.currentStyle){
7783                         return cs[camel];
7784                     }
7785                     return null;
7786                 };
7787         }(),
7788
7789         /**
7790          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7791          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7792          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7793          * @return {Roo.Element} this
7794          */
7795         setStyle : function(prop, value){
7796             if(typeof prop == "string"){
7797                 
7798                 if (prop == 'float') {
7799                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7800                     return this;
7801                 }
7802                 
7803                 var camel;
7804                 if(!(camel = propCache[prop])){
7805                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7806                 }
7807                 
7808                 if(camel == 'opacity') {
7809                     this.setOpacity(value);
7810                 }else{
7811                     this.dom.style[camel] = value;
7812                 }
7813             }else{
7814                 for(var style in prop){
7815                     if(typeof prop[style] != "function"){
7816                        this.setStyle(style, prop[style]);
7817                     }
7818                 }
7819             }
7820             return this;
7821         },
7822
7823         /**
7824          * More flexible version of {@link #setStyle} for setting style properties.
7825          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7826          * a function which returns such a specification.
7827          * @return {Roo.Element} this
7828          */
7829         applyStyles : function(style){
7830             Roo.DomHelper.applyStyles(this.dom, style);
7831             return this;
7832         },
7833
7834         /**
7835           * 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).
7836           * @return {Number} The X position of the element
7837           */
7838         getX : function(){
7839             return D.getX(this.dom);
7840         },
7841
7842         /**
7843           * 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).
7844           * @return {Number} The Y position of the element
7845           */
7846         getY : function(){
7847             return D.getY(this.dom);
7848         },
7849
7850         /**
7851           * 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).
7852           * @return {Array} The XY position of the element
7853           */
7854         getXY : function(){
7855             return D.getXY(this.dom);
7856         },
7857
7858         /**
7859          * 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).
7860          * @param {Number} The X position of the element
7861          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7862          * @return {Roo.Element} this
7863          */
7864         setX : function(x, animate){
7865             if(!animate || !A){
7866                 D.setX(this.dom, x);
7867             }else{
7868                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7869             }
7870             return this;
7871         },
7872
7873         /**
7874          * 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).
7875          * @param {Number} The Y position of the element
7876          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7877          * @return {Roo.Element} this
7878          */
7879         setY : function(y, animate){
7880             if(!animate || !A){
7881                 D.setY(this.dom, y);
7882             }else{
7883                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7884             }
7885             return this;
7886         },
7887
7888         /**
7889          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7890          * @param {String} left The left CSS property value
7891          * @return {Roo.Element} this
7892          */
7893         setLeft : function(left){
7894             this.setStyle("left", this.addUnits(left));
7895             return this;
7896         },
7897
7898         /**
7899          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7900          * @param {String} top The top CSS property value
7901          * @return {Roo.Element} this
7902          */
7903         setTop : function(top){
7904             this.setStyle("top", this.addUnits(top));
7905             return this;
7906         },
7907
7908         /**
7909          * Sets the element's CSS right style.
7910          * @param {String} right The right CSS property value
7911          * @return {Roo.Element} this
7912          */
7913         setRight : function(right){
7914             this.setStyle("right", this.addUnits(right));
7915             return this;
7916         },
7917
7918         /**
7919          * Sets the element's CSS bottom style.
7920          * @param {String} bottom The bottom CSS property value
7921          * @return {Roo.Element} this
7922          */
7923         setBottom : function(bottom){
7924             this.setStyle("bottom", this.addUnits(bottom));
7925             return this;
7926         },
7927
7928         /**
7929          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7930          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7931          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7932          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7933          * @return {Roo.Element} this
7934          */
7935         setXY : function(pos, animate){
7936             if(!animate || !A){
7937                 D.setXY(this.dom, pos);
7938             }else{
7939                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7940             }
7941             return this;
7942         },
7943
7944         /**
7945          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7946          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7947          * @param {Number} x X value for new position (coordinates are page-based)
7948          * @param {Number} y Y value for new position (coordinates are page-based)
7949          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7950          * @return {Roo.Element} this
7951          */
7952         setLocation : function(x, y, animate){
7953             this.setXY([x, y], this.preanim(arguments, 2));
7954             return this;
7955         },
7956
7957         /**
7958          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7959          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7960          * @param {Number} x X value for new position (coordinates are page-based)
7961          * @param {Number} y Y value for new position (coordinates are page-based)
7962          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7963          * @return {Roo.Element} this
7964          */
7965         moveTo : function(x, y, animate){
7966             this.setXY([x, y], this.preanim(arguments, 2));
7967             return this;
7968         },
7969
7970         /**
7971          * Returns the region of the given element.
7972          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7973          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7974          */
7975         getRegion : function(){
7976             return D.getRegion(this.dom);
7977         },
7978
7979         /**
7980          * Returns the offset height of the element
7981          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7982          * @return {Number} The element's height
7983          */
7984         getHeight : function(contentHeight){
7985             var h = this.dom.offsetHeight || 0;
7986             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7987         },
7988
7989         /**
7990          * Returns the offset width of the element
7991          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7992          * @return {Number} The element's width
7993          */
7994         getWidth : function(contentWidth){
7995             var w = this.dom.offsetWidth || 0;
7996             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7997         },
7998
7999         /**
8000          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8001          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8002          * if a height has not been set using CSS.
8003          * @return {Number}
8004          */
8005         getComputedHeight : function(){
8006             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8007             if(!h){
8008                 h = parseInt(this.getStyle('height'), 10) || 0;
8009                 if(!this.isBorderBox()){
8010                     h += this.getFrameWidth('tb');
8011                 }
8012             }
8013             return h;
8014         },
8015
8016         /**
8017          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8018          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8019          * if a width has not been set using CSS.
8020          * @return {Number}
8021          */
8022         getComputedWidth : function(){
8023             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8024             if(!w){
8025                 w = parseInt(this.getStyle('width'), 10) || 0;
8026                 if(!this.isBorderBox()){
8027                     w += this.getFrameWidth('lr');
8028                 }
8029             }
8030             return w;
8031         },
8032
8033         /**
8034          * Returns the size of the element.
8035          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8036          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8037          */
8038         getSize : function(contentSize){
8039             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8040         },
8041
8042         /**
8043          * Returns the width and height of the viewport.
8044          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8045          */
8046         getViewSize : function(){
8047             var d = this.dom, doc = document, aw = 0, ah = 0;
8048             if(d == doc || d == doc.body){
8049                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8050             }else{
8051                 return {
8052                     width : d.clientWidth,
8053                     height: d.clientHeight
8054                 };
8055             }
8056         },
8057
8058         /**
8059          * Returns the value of the "value" attribute
8060          * @param {Boolean} asNumber true to parse the value as a number
8061          * @return {String/Number}
8062          */
8063         getValue : function(asNumber){
8064             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8065         },
8066
8067         // private
8068         adjustWidth : function(width){
8069             if(typeof width == "number"){
8070                 if(this.autoBoxAdjust && !this.isBorderBox()){
8071                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8072                 }
8073                 if(width < 0){
8074                     width = 0;
8075                 }
8076             }
8077             return width;
8078         },
8079
8080         // private
8081         adjustHeight : function(height){
8082             if(typeof height == "number"){
8083                if(this.autoBoxAdjust && !this.isBorderBox()){
8084                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8085                }
8086                if(height < 0){
8087                    height = 0;
8088                }
8089             }
8090             return height;
8091         },
8092
8093         /**
8094          * Set the width of the element
8095          * @param {Number} width The new width
8096          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8097          * @return {Roo.Element} this
8098          */
8099         setWidth : function(width, animate){
8100             width = this.adjustWidth(width);
8101             if(!animate || !A){
8102                 this.dom.style.width = this.addUnits(width);
8103             }else{
8104                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8105             }
8106             return this;
8107         },
8108
8109         /**
8110          * Set the height of the element
8111          * @param {Number} height The new height
8112          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8113          * @return {Roo.Element} this
8114          */
8115          setHeight : function(height, animate){
8116             height = this.adjustHeight(height);
8117             if(!animate || !A){
8118                 this.dom.style.height = this.addUnits(height);
8119             }else{
8120                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8121             }
8122             return this;
8123         },
8124
8125         /**
8126          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8127          * @param {Number} width The new width
8128          * @param {Number} height The new height
8129          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8130          * @return {Roo.Element} this
8131          */
8132          setSize : function(width, height, animate){
8133             if(typeof width == "object"){ // in case of object from getSize()
8134                 height = width.height; width = width.width;
8135             }
8136             width = this.adjustWidth(width); height = this.adjustHeight(height);
8137             if(!animate || !A){
8138                 this.dom.style.width = this.addUnits(width);
8139                 this.dom.style.height = this.addUnits(height);
8140             }else{
8141                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8142             }
8143             return this;
8144         },
8145
8146         /**
8147          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8148          * @param {Number} x X value for new position (coordinates are page-based)
8149          * @param {Number} y Y value for new position (coordinates are page-based)
8150          * @param {Number} width The new width
8151          * @param {Number} height The new height
8152          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8153          * @return {Roo.Element} this
8154          */
8155         setBounds : function(x, y, width, height, animate){
8156             if(!animate || !A){
8157                 this.setSize(width, height);
8158                 this.setLocation(x, y);
8159             }else{
8160                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8161                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8162                               this.preanim(arguments, 4), 'motion');
8163             }
8164             return this;
8165         },
8166
8167         /**
8168          * 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.
8169          * @param {Roo.lib.Region} region The region to fill
8170          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8171          * @return {Roo.Element} this
8172          */
8173         setRegion : function(region, animate){
8174             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8175             return this;
8176         },
8177
8178         /**
8179          * Appends an event handler
8180          *
8181          * @param {String}   eventName     The type of event to append
8182          * @param {Function} fn        The method the event invokes
8183          * @param {Object} scope       (optional) The scope (this object) of the fn
8184          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8185          */
8186         addListener : function(eventName, fn, scope, options){
8187             if (this.dom) {
8188                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8189             }
8190         },
8191
8192         /**
8193          * Removes an event handler from this element
8194          * @param {String} eventName the type of event to remove
8195          * @param {Function} fn the method the event invokes
8196          * @return {Roo.Element} this
8197          */
8198         removeListener : function(eventName, fn){
8199             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8200             return this;
8201         },
8202
8203         /**
8204          * Removes all previous added listeners from this element
8205          * @return {Roo.Element} this
8206          */
8207         removeAllListeners : function(){
8208             E.purgeElement(this.dom);
8209             return this;
8210         },
8211
8212         relayEvent : function(eventName, observable){
8213             this.on(eventName, function(e){
8214                 observable.fireEvent(eventName, e);
8215             });
8216         },
8217
8218         /**
8219          * Set the opacity of the element
8220          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8221          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8222          * @return {Roo.Element} this
8223          */
8224          setOpacity : function(opacity, animate){
8225             if(!animate || !A){
8226                 var s = this.dom.style;
8227                 if(Roo.isIE){
8228                     s.zoom = 1;
8229                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8230                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8231                 }else{
8232                     s.opacity = opacity;
8233                 }
8234             }else{
8235                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8236             }
8237             return this;
8238         },
8239
8240         /**
8241          * Gets the left X coordinate
8242          * @param {Boolean} local True to get the local css position instead of page coordinate
8243          * @return {Number}
8244          */
8245         getLeft : function(local){
8246             if(!local){
8247                 return this.getX();
8248             }else{
8249                 return parseInt(this.getStyle("left"), 10) || 0;
8250             }
8251         },
8252
8253         /**
8254          * Gets the right X coordinate of the element (element X position + element width)
8255          * @param {Boolean} local True to get the local css position instead of page coordinate
8256          * @return {Number}
8257          */
8258         getRight : function(local){
8259             if(!local){
8260                 return this.getX() + this.getWidth();
8261             }else{
8262                 return (this.getLeft(true) + this.getWidth()) || 0;
8263             }
8264         },
8265
8266         /**
8267          * Gets the top Y coordinate
8268          * @param {Boolean} local True to get the local css position instead of page coordinate
8269          * @return {Number}
8270          */
8271         getTop : function(local) {
8272             if(!local){
8273                 return this.getY();
8274             }else{
8275                 return parseInt(this.getStyle("top"), 10) || 0;
8276             }
8277         },
8278
8279         /**
8280          * Gets the bottom Y coordinate of the element (element Y position + element height)
8281          * @param {Boolean} local True to get the local css position instead of page coordinate
8282          * @return {Number}
8283          */
8284         getBottom : function(local){
8285             if(!local){
8286                 return this.getY() + this.getHeight();
8287             }else{
8288                 return (this.getTop(true) + this.getHeight()) || 0;
8289             }
8290         },
8291
8292         /**
8293         * Initializes positioning on this element. If a desired position is not passed, it will make the
8294         * the element positioned relative IF it is not already positioned.
8295         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8296         * @param {Number} zIndex (optional) The zIndex to apply
8297         * @param {Number} x (optional) Set the page X position
8298         * @param {Number} y (optional) Set the page Y position
8299         */
8300         position : function(pos, zIndex, x, y){
8301             if(!pos){
8302                if(this.getStyle('position') == 'static'){
8303                    this.setStyle('position', 'relative');
8304                }
8305             }else{
8306                 this.setStyle("position", pos);
8307             }
8308             if(zIndex){
8309                 this.setStyle("z-index", zIndex);
8310             }
8311             if(x !== undefined && y !== undefined){
8312                 this.setXY([x, y]);
8313             }else if(x !== undefined){
8314                 this.setX(x);
8315             }else if(y !== undefined){
8316                 this.setY(y);
8317             }
8318         },
8319
8320         /**
8321         * Clear positioning back to the default when the document was loaded
8322         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8323         * @return {Roo.Element} this
8324          */
8325         clearPositioning : function(value){
8326             value = value ||'';
8327             this.setStyle({
8328                 "left": value,
8329                 "right": value,
8330                 "top": value,
8331                 "bottom": value,
8332                 "z-index": "",
8333                 "position" : "static"
8334             });
8335             return this;
8336         },
8337
8338         /**
8339         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8340         * snapshot before performing an update and then restoring the element.
8341         * @return {Object}
8342         */
8343         getPositioning : function(){
8344             var l = this.getStyle("left");
8345             var t = this.getStyle("top");
8346             return {
8347                 "position" : this.getStyle("position"),
8348                 "left" : l,
8349                 "right" : l ? "" : this.getStyle("right"),
8350                 "top" : t,
8351                 "bottom" : t ? "" : this.getStyle("bottom"),
8352                 "z-index" : this.getStyle("z-index")
8353             };
8354         },
8355
8356         /**
8357          * Gets the width of the border(s) for the specified side(s)
8358          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8359          * passing lr would get the border (l)eft width + the border (r)ight width.
8360          * @return {Number} The width of the sides passed added together
8361          */
8362         getBorderWidth : function(side){
8363             return this.addStyles(side, El.borders);
8364         },
8365
8366         /**
8367          * Gets the width of the padding(s) for the specified side(s)
8368          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8369          * passing lr would get the padding (l)eft + the padding (r)ight.
8370          * @return {Number} The padding of the sides passed added together
8371          */
8372         getPadding : function(side){
8373             return this.addStyles(side, El.paddings);
8374         },
8375
8376         /**
8377         * Set positioning with an object returned by getPositioning().
8378         * @param {Object} posCfg
8379         * @return {Roo.Element} this
8380          */
8381         setPositioning : function(pc){
8382             this.applyStyles(pc);
8383             if(pc.right == "auto"){
8384                 this.dom.style.right = "";
8385             }
8386             if(pc.bottom == "auto"){
8387                 this.dom.style.bottom = "";
8388             }
8389             return this;
8390         },
8391
8392         // private
8393         fixDisplay : function(){
8394             if(this.getStyle("display") == "none"){
8395                 this.setStyle("visibility", "hidden");
8396                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8397                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8398                     this.setStyle("display", "block");
8399                 }
8400             }
8401         },
8402
8403         /**
8404          * Quick set left and top adding default units
8405          * @param {String} left The left CSS property value
8406          * @param {String} top The top CSS property value
8407          * @return {Roo.Element} this
8408          */
8409          setLeftTop : function(left, top){
8410             this.dom.style.left = this.addUnits(left);
8411             this.dom.style.top = this.addUnits(top);
8412             return this;
8413         },
8414
8415         /**
8416          * Move this element relative to its current position.
8417          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8418          * @param {Number} distance How far to move the element in pixels
8419          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8420          * @return {Roo.Element} this
8421          */
8422          move : function(direction, distance, animate){
8423             var xy = this.getXY();
8424             direction = direction.toLowerCase();
8425             switch(direction){
8426                 case "l":
8427                 case "left":
8428                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8429                     break;
8430                case "r":
8431                case "right":
8432                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8433                     break;
8434                case "t":
8435                case "top":
8436                case "up":
8437                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8438                     break;
8439                case "b":
8440                case "bottom":
8441                case "down":
8442                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8443                     break;
8444             }
8445             return this;
8446         },
8447
8448         /**
8449          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8450          * @return {Roo.Element} this
8451          */
8452         clip : function(){
8453             if(!this.isClipped){
8454                this.isClipped = true;
8455                this.originalClip = {
8456                    "o": this.getStyle("overflow"),
8457                    "x": this.getStyle("overflow-x"),
8458                    "y": this.getStyle("overflow-y")
8459                };
8460                this.setStyle("overflow", "hidden");
8461                this.setStyle("overflow-x", "hidden");
8462                this.setStyle("overflow-y", "hidden");
8463             }
8464             return this;
8465         },
8466
8467         /**
8468          *  Return clipping (overflow) to original clipping before clip() was called
8469          * @return {Roo.Element} this
8470          */
8471         unclip : function(){
8472             if(this.isClipped){
8473                 this.isClipped = false;
8474                 var o = this.originalClip;
8475                 if(o.o){this.setStyle("overflow", o.o);}
8476                 if(o.x){this.setStyle("overflow-x", o.x);}
8477                 if(o.y){this.setStyle("overflow-y", o.y);}
8478             }
8479             return this;
8480         },
8481
8482
8483         /**
8484          * Gets the x,y coordinates specified by the anchor position on the element.
8485          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8486          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8487          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8488          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8489          * @return {Array} [x, y] An array containing the element's x and y coordinates
8490          */
8491         getAnchorXY : function(anchor, local, s){
8492             //Passing a different size is useful for pre-calculating anchors,
8493             //especially for anchored animations that change the el size.
8494
8495             var w, h, vp = false;
8496             if(!s){
8497                 var d = this.dom;
8498                 if(d == document.body || d == document){
8499                     vp = true;
8500                     w = D.getViewWidth(); h = D.getViewHeight();
8501                 }else{
8502                     w = this.getWidth(); h = this.getHeight();
8503                 }
8504             }else{
8505                 w = s.width;  h = s.height;
8506             }
8507             var x = 0, y = 0, r = Math.round;
8508             switch((anchor || "tl").toLowerCase()){
8509                 case "c":
8510                     x = r(w*.5);
8511                     y = r(h*.5);
8512                 break;
8513                 case "t":
8514                     x = r(w*.5);
8515                     y = 0;
8516                 break;
8517                 case "l":
8518                     x = 0;
8519                     y = r(h*.5);
8520                 break;
8521                 case "r":
8522                     x = w;
8523                     y = r(h*.5);
8524                 break;
8525                 case "b":
8526                     x = r(w*.5);
8527                     y = h;
8528                 break;
8529                 case "tl":
8530                     x = 0;
8531                     y = 0;
8532                 break;
8533                 case "bl":
8534                     x = 0;
8535                     y = h;
8536                 break;
8537                 case "br":
8538                     x = w;
8539                     y = h;
8540                 break;
8541                 case "tr":
8542                     x = w;
8543                     y = 0;
8544                 break;
8545             }
8546             if(local === true){
8547                 return [x, y];
8548             }
8549             if(vp){
8550                 var sc = this.getScroll();
8551                 return [x + sc.left, y + sc.top];
8552             }
8553             //Add the element's offset xy
8554             var o = this.getXY();
8555             return [x+o[0], y+o[1]];
8556         },
8557
8558         /**
8559          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8560          * supported position values.
8561          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8562          * @param {String} position The position to align to.
8563          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8564          * @return {Array} [x, y]
8565          */
8566         getAlignToXY : function(el, p, o){
8567             el = Roo.get(el);
8568             var d = this.dom;
8569             if(!el.dom){
8570                 throw "Element.alignTo with an element that doesn't exist";
8571             }
8572             var c = false; //constrain to viewport
8573             var p1 = "", p2 = "";
8574             o = o || [0,0];
8575
8576             if(!p){
8577                 p = "tl-bl";
8578             }else if(p == "?"){
8579                 p = "tl-bl?";
8580             }else if(p.indexOf("-") == -1){
8581                 p = "tl-" + p;
8582             }
8583             p = p.toLowerCase();
8584             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8585             if(!m){
8586                throw "Element.alignTo with an invalid alignment " + p;
8587             }
8588             p1 = m[1]; p2 = m[2]; c = !!m[3];
8589
8590             //Subtract the aligned el's internal xy from the target's offset xy
8591             //plus custom offset to get the aligned el's new offset xy
8592             var a1 = this.getAnchorXY(p1, true);
8593             var a2 = el.getAnchorXY(p2, false);
8594             var x = a2[0] - a1[0] + o[0];
8595             var y = a2[1] - a1[1] + o[1];
8596             if(c){
8597                 //constrain the aligned el to viewport if necessary
8598                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8599                 // 5px of margin for ie
8600                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8601
8602                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8603                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8604                 //otherwise swap the aligned el to the opposite border of the target.
8605                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8606                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8607                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8608                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8609
8610                var doc = document;
8611                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8612                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8613
8614                if((x+w) > dw + scrollX){
8615                     x = swapX ? r.left-w : dw+scrollX-w;
8616                 }
8617                if(x < scrollX){
8618                    x = swapX ? r.right : scrollX;
8619                }
8620                if((y+h) > dh + scrollY){
8621                     y = swapY ? r.top-h : dh+scrollY-h;
8622                 }
8623                if (y < scrollY){
8624                    y = swapY ? r.bottom : scrollY;
8625                }
8626             }
8627             return [x,y];
8628         },
8629
8630         // private
8631         getConstrainToXY : function(){
8632             var os = {top:0, left:0, bottom:0, right: 0};
8633
8634             return function(el, local, offsets, proposedXY){
8635                 el = Roo.get(el);
8636                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8637
8638                 var vw, vh, vx = 0, vy = 0;
8639                 if(el.dom == document.body || el.dom == document){
8640                     vw = Roo.lib.Dom.getViewWidth();
8641                     vh = Roo.lib.Dom.getViewHeight();
8642                 }else{
8643                     vw = el.dom.clientWidth;
8644                     vh = el.dom.clientHeight;
8645                     if(!local){
8646                         var vxy = el.getXY();
8647                         vx = vxy[0];
8648                         vy = vxy[1];
8649                     }
8650                 }
8651
8652                 var s = el.getScroll();
8653
8654                 vx += offsets.left + s.left;
8655                 vy += offsets.top + s.top;
8656
8657                 vw -= offsets.right;
8658                 vh -= offsets.bottom;
8659
8660                 var vr = vx+vw;
8661                 var vb = vy+vh;
8662
8663                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8664                 var x = xy[0], y = xy[1];
8665                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8666
8667                 // only move it if it needs it
8668                 var moved = false;
8669
8670                 // first validate right/bottom
8671                 if((x + w) > vr){
8672                     x = vr - w;
8673                     moved = true;
8674                 }
8675                 if((y + h) > vb){
8676                     y = vb - h;
8677                     moved = true;
8678                 }
8679                 // then make sure top/left isn't negative
8680                 if(x < vx){
8681                     x = vx;
8682                     moved = true;
8683                 }
8684                 if(y < vy){
8685                     y = vy;
8686                     moved = true;
8687                 }
8688                 return moved ? [x, y] : false;
8689             };
8690         }(),
8691
8692         // private
8693         adjustForConstraints : function(xy, parent, offsets){
8694             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8695         },
8696
8697         /**
8698          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8699          * document it aligns it to the viewport.
8700          * The position parameter is optional, and can be specified in any one of the following formats:
8701          * <ul>
8702          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8703          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8704          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8705          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8706          *   <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
8707          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8708          * </ul>
8709          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8710          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8711          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8712          * that specified in order to enforce the viewport constraints.
8713          * Following are all of the supported anchor positions:
8714     <pre>
8715     Value  Description
8716     -----  -----------------------------
8717     tl     The top left corner (default)
8718     t      The center of the top edge
8719     tr     The top right corner
8720     l      The center of the left edge
8721     c      In the center of the element
8722     r      The center of the right edge
8723     bl     The bottom left corner
8724     b      The center of the bottom edge
8725     br     The bottom right corner
8726     </pre>
8727     Example Usage:
8728     <pre><code>
8729     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8730     el.alignTo("other-el");
8731
8732     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8733     el.alignTo("other-el", "tr?");
8734
8735     // align the bottom right corner of el with the center left edge of other-el
8736     el.alignTo("other-el", "br-l?");
8737
8738     // align the center of el with the bottom left corner of other-el and
8739     // adjust the x position by -6 pixels (and the y position by 0)
8740     el.alignTo("other-el", "c-bl", [-6, 0]);
8741     </code></pre>
8742          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8743          * @param {String} position The position to align to.
8744          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8745          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8746          * @return {Roo.Element} this
8747          */
8748         alignTo : function(element, position, offsets, animate){
8749             var xy = this.getAlignToXY(element, position, offsets);
8750             this.setXY(xy, this.preanim(arguments, 3));
8751             return this;
8752         },
8753
8754         /**
8755          * Anchors an element to another element and realigns it when the window is resized.
8756          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8757          * @param {String} position The position to align to.
8758          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8759          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8760          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8761          * is a number, it is used as the buffer delay (defaults to 50ms).
8762          * @param {Function} callback The function to call after the animation finishes
8763          * @return {Roo.Element} this
8764          */
8765         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8766             var action = function(){
8767                 this.alignTo(el, alignment, offsets, animate);
8768                 Roo.callback(callback, this);
8769             };
8770             Roo.EventManager.onWindowResize(action, this);
8771             var tm = typeof monitorScroll;
8772             if(tm != 'undefined'){
8773                 Roo.EventManager.on(window, 'scroll', action, this,
8774                     {buffer: tm == 'number' ? monitorScroll : 50});
8775             }
8776             action.call(this); // align immediately
8777             return this;
8778         },
8779         /**
8780          * Clears any opacity settings from this element. Required in some cases for IE.
8781          * @return {Roo.Element} this
8782          */
8783         clearOpacity : function(){
8784             if (window.ActiveXObject) {
8785                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8786                     this.dom.style.filter = "";
8787                 }
8788             } else {
8789                 this.dom.style.opacity = "";
8790                 this.dom.style["-moz-opacity"] = "";
8791                 this.dom.style["-khtml-opacity"] = "";
8792             }
8793             return this;
8794         },
8795
8796         /**
8797          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8798          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8799          * @return {Roo.Element} this
8800          */
8801         hide : function(animate){
8802             this.setVisible(false, this.preanim(arguments, 0));
8803             return this;
8804         },
8805
8806         /**
8807         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8808         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8809          * @return {Roo.Element} this
8810          */
8811         show : function(animate){
8812             this.setVisible(true, this.preanim(arguments, 0));
8813             return this;
8814         },
8815
8816         /**
8817          * @private Test if size has a unit, otherwise appends the default
8818          */
8819         addUnits : function(size){
8820             return Roo.Element.addUnits(size, this.defaultUnit);
8821         },
8822
8823         /**
8824          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8825          * @return {Roo.Element} this
8826          */
8827         beginMeasure : function(){
8828             var el = this.dom;
8829             if(el.offsetWidth || el.offsetHeight){
8830                 return this; // offsets work already
8831             }
8832             var changed = [];
8833             var p = this.dom, b = document.body; // start with this element
8834             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8835                 var pe = Roo.get(p);
8836                 if(pe.getStyle('display') == 'none'){
8837                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8838                     p.style.visibility = "hidden";
8839                     p.style.display = "block";
8840                 }
8841                 p = p.parentNode;
8842             }
8843             this._measureChanged = changed;
8844             return this;
8845
8846         },
8847
8848         /**
8849          * Restores displays to before beginMeasure was called
8850          * @return {Roo.Element} this
8851          */
8852         endMeasure : function(){
8853             var changed = this._measureChanged;
8854             if(changed){
8855                 for(var i = 0, len = changed.length; i < len; i++) {
8856                     var r = changed[i];
8857                     r.el.style.visibility = r.visibility;
8858                     r.el.style.display = "none";
8859                 }
8860                 this._measureChanged = null;
8861             }
8862             return this;
8863         },
8864
8865         /**
8866         * Update the innerHTML of this element, optionally searching for and processing scripts
8867         * @param {String} html The new HTML
8868         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8869         * @param {Function} callback For async script loading you can be noticed when the update completes
8870         * @return {Roo.Element} this
8871          */
8872         update : function(html, loadScripts, callback){
8873             if(typeof html == "undefined"){
8874                 html = "";
8875             }
8876             if(loadScripts !== true){
8877                 this.dom.innerHTML = html;
8878                 if(typeof callback == "function"){
8879                     callback();
8880                 }
8881                 return this;
8882             }
8883             var id = Roo.id();
8884             var dom = this.dom;
8885
8886             html += '<span id="' + id + '"></span>';
8887
8888             E.onAvailable(id, function(){
8889                 var hd = document.getElementsByTagName("head")[0];
8890                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8891                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8892                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8893
8894                 var match;
8895                 while(match = re.exec(html)){
8896                     var attrs = match[1];
8897                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8898                     if(srcMatch && srcMatch[2]){
8899                        var s = document.createElement("script");
8900                        s.src = srcMatch[2];
8901                        var typeMatch = attrs.match(typeRe);
8902                        if(typeMatch && typeMatch[2]){
8903                            s.type = typeMatch[2];
8904                        }
8905                        hd.appendChild(s);
8906                     }else if(match[2] && match[2].length > 0){
8907                         if(window.execScript) {
8908                            window.execScript(match[2]);
8909                         } else {
8910                             /**
8911                              * eval:var:id
8912                              * eval:var:dom
8913                              * eval:var:html
8914                              * 
8915                              */
8916                            window.eval(match[2]);
8917                         }
8918                     }
8919                 }
8920                 var el = document.getElementById(id);
8921                 if(el){el.parentNode.removeChild(el);}
8922                 if(typeof callback == "function"){
8923                     callback();
8924                 }
8925             });
8926             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8927             return this;
8928         },
8929
8930         /**
8931          * Direct access to the UpdateManager update() method (takes the same parameters).
8932          * @param {String/Function} url The url for this request or a function to call to get the url
8933          * @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}
8934          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8935          * @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.
8936          * @return {Roo.Element} this
8937          */
8938         load : function(){
8939             var um = this.getUpdateManager();
8940             um.update.apply(um, arguments);
8941             return this;
8942         },
8943
8944         /**
8945         * Gets this element's UpdateManager
8946         * @return {Roo.UpdateManager} The UpdateManager
8947         */
8948         getUpdateManager : function(){
8949             if(!this.updateManager){
8950                 this.updateManager = new Roo.UpdateManager(this);
8951             }
8952             return this.updateManager;
8953         },
8954
8955         /**
8956          * Disables text selection for this element (normalized across browsers)
8957          * @return {Roo.Element} this
8958          */
8959         unselectable : function(){
8960             this.dom.unselectable = "on";
8961             this.swallowEvent("selectstart", true);
8962             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8963             this.addClass("x-unselectable");
8964             return this;
8965         },
8966
8967         /**
8968         * Calculates the x, y to center this element on the screen
8969         * @return {Array} The x, y values [x, y]
8970         */
8971         getCenterXY : function(){
8972             return this.getAlignToXY(document, 'c-c');
8973         },
8974
8975         /**
8976         * Centers the Element in either the viewport, or another Element.
8977         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8978         */
8979         center : function(centerIn){
8980             this.alignTo(centerIn || document, 'c-c');
8981             return this;
8982         },
8983
8984         /**
8985          * Tests various css rules/browsers to determine if this element uses a border box
8986          * @return {Boolean}
8987          */
8988         isBorderBox : function(){
8989             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8990         },
8991
8992         /**
8993          * Return a box {x, y, width, height} that can be used to set another elements
8994          * size/location to match this element.
8995          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8996          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8997          * @return {Object} box An object in the format {x, y, width, height}
8998          */
8999         getBox : function(contentBox, local){
9000             var xy;
9001             if(!local){
9002                 xy = this.getXY();
9003             }else{
9004                 var left = parseInt(this.getStyle("left"), 10) || 0;
9005                 var top = parseInt(this.getStyle("top"), 10) || 0;
9006                 xy = [left, top];
9007             }
9008             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9009             if(!contentBox){
9010                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9011             }else{
9012                 var l = this.getBorderWidth("l")+this.getPadding("l");
9013                 var r = this.getBorderWidth("r")+this.getPadding("r");
9014                 var t = this.getBorderWidth("t")+this.getPadding("t");
9015                 var b = this.getBorderWidth("b")+this.getPadding("b");
9016                 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)};
9017             }
9018             bx.right = bx.x + bx.width;
9019             bx.bottom = bx.y + bx.height;
9020             return bx;
9021         },
9022
9023         /**
9024          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9025          for more information about the sides.
9026          * @param {String} sides
9027          * @return {Number}
9028          */
9029         getFrameWidth : function(sides, onlyContentBox){
9030             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9031         },
9032
9033         /**
9034          * 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.
9035          * @param {Object} box The box to fill {x, y, width, height}
9036          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9037          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9038          * @return {Roo.Element} this
9039          */
9040         setBox : function(box, adjust, animate){
9041             var w = box.width, h = box.height;
9042             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9043                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9044                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9045             }
9046             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9047             return this;
9048         },
9049
9050         /**
9051          * Forces the browser to repaint this element
9052          * @return {Roo.Element} this
9053          */
9054          repaint : function(){
9055             var dom = this.dom;
9056             this.addClass("x-repaint");
9057             setTimeout(function(){
9058                 Roo.get(dom).removeClass("x-repaint");
9059             }, 1);
9060             return this;
9061         },
9062
9063         /**
9064          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9065          * then it returns the calculated width of the sides (see getPadding)
9066          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9067          * @return {Object/Number}
9068          */
9069         getMargins : function(side){
9070             if(!side){
9071                 return {
9072                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9073                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9074                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9075                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9076                 };
9077             }else{
9078                 return this.addStyles(side, El.margins);
9079              }
9080         },
9081
9082         // private
9083         addStyles : function(sides, styles){
9084             var val = 0, v, w;
9085             for(var i = 0, len = sides.length; i < len; i++){
9086                 v = this.getStyle(styles[sides.charAt(i)]);
9087                 if(v){
9088                      w = parseInt(v, 10);
9089                      if(w){ val += w; }
9090                 }
9091             }
9092             return val;
9093         },
9094
9095         /**
9096          * Creates a proxy element of this element
9097          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9098          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9099          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9100          * @return {Roo.Element} The new proxy element
9101          */
9102         createProxy : function(config, renderTo, matchBox){
9103             if(renderTo){
9104                 renderTo = Roo.getDom(renderTo);
9105             }else{
9106                 renderTo = document.body;
9107             }
9108             config = typeof config == "object" ?
9109                 config : {tag : "div", cls: config};
9110             var proxy = Roo.DomHelper.append(renderTo, config, true);
9111             if(matchBox){
9112                proxy.setBox(this.getBox());
9113             }
9114             return proxy;
9115         },
9116
9117         /**
9118          * Puts a mask over this element to disable user interaction. Requires core.css.
9119          * This method can only be applied to elements which accept child nodes.
9120          * @param {String} msg (optional) A message to display in the mask
9121          * @param {String} msgCls (optional) A css class to apply to the msg element
9122          * @return {Element} The mask  element
9123          */
9124         mask : function(msg, msgCls)
9125         {
9126             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9127                 this.setStyle("position", "relative");
9128             }
9129             if(!this._mask){
9130                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9131             }
9132             
9133             this._mask.dom.className = msgCls ? "roo-el-mask " + msgCls : "roo-el-mask";
9134             
9135             this.addClass("x-masked");
9136             this._mask.setDisplayed(true);
9137             
9138             // we wander
9139             var z = 0;
9140             var dom = this.dom;
9141             while (dom && dom.style) {
9142                 if (!isNaN(parseInt(dom.style.zIndex))) {
9143                     z = Math.max(z, parseInt(dom.style.zIndex));
9144                 }
9145                 dom = dom.parentNode;
9146             }
9147             // if we are masking the body - then it hides everything..
9148             if (this.dom == document.body) {
9149                 z = 1000000;
9150                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9151                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9152             }
9153            
9154             if(typeof msg == 'string'){
9155                 if(!this._maskMsg){
9156                     this._maskMsg = Roo.DomHelper.append(this.dom, {
9157                         cls: "roo-el-mask-msg", 
9158                         cn: [
9159                             {
9160                                 tag: 'i',
9161                                 cls: 'fa fa-spinner fa-spin'
9162                             },
9163                             {
9164                                 tag: 'div'
9165                             }   
9166                         ]
9167                     }, true);
9168                 }
9169                 var mm = this._maskMsg;
9170                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9171                 if (mm.dom.lastChild) { // weird IE issue?
9172                     mm.dom.lastChild.innerHTML = msg;
9173                 }
9174                 mm.setDisplayed(true);
9175                 mm.center(this);
9176                 mm.setStyle('z-index', z + 102);
9177             }
9178             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9179                 this._mask.setHeight(this.getHeight());
9180             }
9181             this._mask.setStyle('z-index', z + 100);
9182             
9183             return this._mask;
9184         },
9185
9186         /**
9187          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9188          * it is cached for reuse.
9189          */
9190         unmask : function(removeEl){
9191             if(this._mask){
9192                 if(removeEl === true){
9193                     this._mask.remove();
9194                     delete this._mask;
9195                     if(this._maskMsg){
9196                         this._maskMsg.remove();
9197                         delete this._maskMsg;
9198                     }
9199                 }else{
9200                     this._mask.setDisplayed(false);
9201                     if(this._maskMsg){
9202                         this._maskMsg.setDisplayed(false);
9203                     }
9204                 }
9205             }
9206             this.removeClass("x-masked");
9207         },
9208
9209         /**
9210          * Returns true if this element is masked
9211          * @return {Boolean}
9212          */
9213         isMasked : function(){
9214             return this._mask && this._mask.isVisible();
9215         },
9216
9217         /**
9218          * Creates an iframe shim for this element to keep selects and other windowed objects from
9219          * showing through.
9220          * @return {Roo.Element} The new shim element
9221          */
9222         createShim : function(){
9223             var el = document.createElement('iframe');
9224             el.frameBorder = 'no';
9225             el.className = 'roo-shim';
9226             if(Roo.isIE && Roo.isSecure){
9227                 el.src = Roo.SSL_SECURE_URL;
9228             }
9229             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9230             shim.autoBoxAdjust = false;
9231             return shim;
9232         },
9233
9234         /**
9235          * Removes this element from the DOM and deletes it from the cache
9236          */
9237         remove : function(){
9238             if(this.dom.parentNode){
9239                 this.dom.parentNode.removeChild(this.dom);
9240             }
9241             delete El.cache[this.dom.id];
9242         },
9243
9244         /**
9245          * Sets up event handlers to add and remove a css class when the mouse is over this element
9246          * @param {String} className
9247          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9248          * mouseout events for children elements
9249          * @return {Roo.Element} this
9250          */
9251         addClassOnOver : function(className, preventFlicker){
9252             this.on("mouseover", function(){
9253                 Roo.fly(this, '_internal').addClass(className);
9254             }, this.dom);
9255             var removeFn = function(e){
9256                 if(preventFlicker !== true || !e.within(this, true)){
9257                     Roo.fly(this, '_internal').removeClass(className);
9258                 }
9259             };
9260             this.on("mouseout", removeFn, this.dom);
9261             return this;
9262         },
9263
9264         /**
9265          * Sets up event handlers to add and remove a css class when this element has the focus
9266          * @param {String} className
9267          * @return {Roo.Element} this
9268          */
9269         addClassOnFocus : function(className){
9270             this.on("focus", function(){
9271                 Roo.fly(this, '_internal').addClass(className);
9272             }, this.dom);
9273             this.on("blur", function(){
9274                 Roo.fly(this, '_internal').removeClass(className);
9275             }, this.dom);
9276             return this;
9277         },
9278         /**
9279          * 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)
9280          * @param {String} className
9281          * @return {Roo.Element} this
9282          */
9283         addClassOnClick : function(className){
9284             var dom = this.dom;
9285             this.on("mousedown", function(){
9286                 Roo.fly(dom, '_internal').addClass(className);
9287                 var d = Roo.get(document);
9288                 var fn = function(){
9289                     Roo.fly(dom, '_internal').removeClass(className);
9290                     d.removeListener("mouseup", fn);
9291                 };
9292                 d.on("mouseup", fn);
9293             });
9294             return this;
9295         },
9296
9297         /**
9298          * Stops the specified event from bubbling and optionally prevents the default action
9299          * @param {String} eventName
9300          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9301          * @return {Roo.Element} this
9302          */
9303         swallowEvent : function(eventName, preventDefault){
9304             var fn = function(e){
9305                 e.stopPropagation();
9306                 if(preventDefault){
9307                     e.preventDefault();
9308                 }
9309             };
9310             if(eventName instanceof Array){
9311                 for(var i = 0, len = eventName.length; i < len; i++){
9312                      this.on(eventName[i], fn);
9313                 }
9314                 return this;
9315             }
9316             this.on(eventName, fn);
9317             return this;
9318         },
9319
9320         /**
9321          * @private
9322          */
9323       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9324
9325         /**
9326          * Sizes this element to its parent element's dimensions performing
9327          * neccessary box adjustments.
9328          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9329          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9330          * @return {Roo.Element} this
9331          */
9332         fitToParent : function(monitorResize, targetParent) {
9333           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9334           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9335           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9336             return;
9337           }
9338           var p = Roo.get(targetParent || this.dom.parentNode);
9339           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9340           if (monitorResize === true) {
9341             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9342             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9343           }
9344           return this;
9345         },
9346
9347         /**
9348          * Gets the next sibling, skipping text nodes
9349          * @return {HTMLElement} The next sibling or null
9350          */
9351         getNextSibling : function(){
9352             var n = this.dom.nextSibling;
9353             while(n && n.nodeType != 1){
9354                 n = n.nextSibling;
9355             }
9356             return n;
9357         },
9358
9359         /**
9360          * Gets the previous sibling, skipping text nodes
9361          * @return {HTMLElement} The previous sibling or null
9362          */
9363         getPrevSibling : function(){
9364             var n = this.dom.previousSibling;
9365             while(n && n.nodeType != 1){
9366                 n = n.previousSibling;
9367             }
9368             return n;
9369         },
9370
9371
9372         /**
9373          * Appends the passed element(s) to this element
9374          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9375          * @return {Roo.Element} this
9376          */
9377         appendChild: function(el){
9378             el = Roo.get(el);
9379             el.appendTo(this);
9380             return this;
9381         },
9382
9383         /**
9384          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9385          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9386          * automatically generated with the specified attributes.
9387          * @param {HTMLElement} insertBefore (optional) a child element of this element
9388          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9389          * @return {Roo.Element} The new child element
9390          */
9391         createChild: function(config, insertBefore, returnDom){
9392             config = config || {tag:'div'};
9393             if(insertBefore){
9394                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9395             }
9396             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9397         },
9398
9399         /**
9400          * Appends this element to the passed element
9401          * @param {String/HTMLElement/Element} el The new parent element
9402          * @return {Roo.Element} this
9403          */
9404         appendTo: function(el){
9405             el = Roo.getDom(el);
9406             el.appendChild(this.dom);
9407             return this;
9408         },
9409
9410         /**
9411          * Inserts this element before the passed element in the DOM
9412          * @param {String/HTMLElement/Element} el The element to insert before
9413          * @return {Roo.Element} this
9414          */
9415         insertBefore: function(el){
9416             el = Roo.getDom(el);
9417             el.parentNode.insertBefore(this.dom, el);
9418             return this;
9419         },
9420
9421         /**
9422          * Inserts this element after the passed element in the DOM
9423          * @param {String/HTMLElement/Element} el The element to insert after
9424          * @return {Roo.Element} this
9425          */
9426         insertAfter: function(el){
9427             el = Roo.getDom(el);
9428             el.parentNode.insertBefore(this.dom, el.nextSibling);
9429             return this;
9430         },
9431
9432         /**
9433          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9434          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9435          * @return {Roo.Element} The new child
9436          */
9437         insertFirst: function(el, returnDom){
9438             el = el || {};
9439             if(typeof el == 'object' && !el.nodeType){ // dh config
9440                 return this.createChild(el, this.dom.firstChild, returnDom);
9441             }else{
9442                 el = Roo.getDom(el);
9443                 this.dom.insertBefore(el, this.dom.firstChild);
9444                 return !returnDom ? Roo.get(el) : el;
9445             }
9446         },
9447
9448         /**
9449          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9450          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9451          * @param {String} where (optional) 'before' or 'after' defaults to before
9452          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9453          * @return {Roo.Element} the inserted Element
9454          */
9455         insertSibling: function(el, where, returnDom){
9456             where = where ? where.toLowerCase() : 'before';
9457             el = el || {};
9458             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9459
9460             if(typeof el == 'object' && !el.nodeType){ // dh config
9461                 if(where == 'after' && !this.dom.nextSibling){
9462                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9463                 }else{
9464                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9465                 }
9466
9467             }else{
9468                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9469                             where == 'before' ? this.dom : this.dom.nextSibling);
9470                 if(!returnDom){
9471                     rt = Roo.get(rt);
9472                 }
9473             }
9474             return rt;
9475         },
9476
9477         /**
9478          * Creates and wraps this element with another element
9479          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9480          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9481          * @return {HTMLElement/Element} The newly created wrapper element
9482          */
9483         wrap: function(config, returnDom){
9484             if(!config){
9485                 config = {tag: "div"};
9486             }
9487             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9488             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9489             return newEl;
9490         },
9491
9492         /**
9493          * Replaces the passed element with this element
9494          * @param {String/HTMLElement/Element} el The element to replace
9495          * @return {Roo.Element} this
9496          */
9497         replace: function(el){
9498             el = Roo.get(el);
9499             this.insertBefore(el);
9500             el.remove();
9501             return this;
9502         },
9503
9504         /**
9505          * Inserts an html fragment into this element
9506          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9507          * @param {String} html The HTML fragment
9508          * @param {Boolean} returnEl True to return an Roo.Element
9509          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9510          */
9511         insertHtml : function(where, html, returnEl){
9512             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9513             return returnEl ? Roo.get(el) : el;
9514         },
9515
9516         /**
9517          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9518          * @param {Object} o The object with the attributes
9519          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9520          * @return {Roo.Element} this
9521          */
9522         set : function(o, useSet){
9523             var el = this.dom;
9524             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9525             for(var attr in o){
9526                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9527                 if(attr=="cls"){
9528                     el.className = o["cls"];
9529                 }else{
9530                     if(useSet) {
9531                         el.setAttribute(attr, o[attr]);
9532                     } else {
9533                         el[attr] = o[attr];
9534                     }
9535                 }
9536             }
9537             if(o.style){
9538                 Roo.DomHelper.applyStyles(el, o.style);
9539             }
9540             return this;
9541         },
9542
9543         /**
9544          * Convenience method for constructing a KeyMap
9545          * @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:
9546          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9547          * @param {Function} fn The function to call
9548          * @param {Object} scope (optional) The scope of the function
9549          * @return {Roo.KeyMap} The KeyMap created
9550          */
9551         addKeyListener : function(key, fn, scope){
9552             var config;
9553             if(typeof key != "object" || key instanceof Array){
9554                 config = {
9555                     key: key,
9556                     fn: fn,
9557                     scope: scope
9558                 };
9559             }else{
9560                 config = {
9561                     key : key.key,
9562                     shift : key.shift,
9563                     ctrl : key.ctrl,
9564                     alt : key.alt,
9565                     fn: fn,
9566                     scope: scope
9567                 };
9568             }
9569             return new Roo.KeyMap(this, config);
9570         },
9571
9572         /**
9573          * Creates a KeyMap for this element
9574          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9575          * @return {Roo.KeyMap} The KeyMap created
9576          */
9577         addKeyMap : function(config){
9578             return new Roo.KeyMap(this, config);
9579         },
9580
9581         /**
9582          * Returns true if this element is scrollable.
9583          * @return {Boolean}
9584          */
9585          isScrollable : function(){
9586             var dom = this.dom;
9587             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9588         },
9589
9590         /**
9591          * 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().
9592          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9593          * @param {Number} value The new scroll value
9594          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9595          * @return {Element} this
9596          */
9597
9598         scrollTo : function(side, value, animate){
9599             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9600             if(!animate || !A){
9601                 this.dom[prop] = value;
9602             }else{
9603                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9604                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9605             }
9606             return this;
9607         },
9608
9609         /**
9610          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9611          * within this element's scrollable range.
9612          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9613          * @param {Number} distance How far to scroll the element in pixels
9614          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9615          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9616          * was scrolled as far as it could go.
9617          */
9618          scroll : function(direction, distance, animate){
9619              if(!this.isScrollable()){
9620                  return;
9621              }
9622              var el = this.dom;
9623              var l = el.scrollLeft, t = el.scrollTop;
9624              var w = el.scrollWidth, h = el.scrollHeight;
9625              var cw = el.clientWidth, ch = el.clientHeight;
9626              direction = direction.toLowerCase();
9627              var scrolled = false;
9628              var a = this.preanim(arguments, 2);
9629              switch(direction){
9630                  case "l":
9631                  case "left":
9632                      if(w - l > cw){
9633                          var v = Math.min(l + distance, w-cw);
9634                          this.scrollTo("left", v, a);
9635                          scrolled = true;
9636                      }
9637                      break;
9638                 case "r":
9639                 case "right":
9640                      if(l > 0){
9641                          var v = Math.max(l - distance, 0);
9642                          this.scrollTo("left", v, a);
9643                          scrolled = true;
9644                      }
9645                      break;
9646                 case "t":
9647                 case "top":
9648                 case "up":
9649                      if(t > 0){
9650                          var v = Math.max(t - distance, 0);
9651                          this.scrollTo("top", v, a);
9652                          scrolled = true;
9653                      }
9654                      break;
9655                 case "b":
9656                 case "bottom":
9657                 case "down":
9658                      if(h - t > ch){
9659                          var v = Math.min(t + distance, h-ch);
9660                          this.scrollTo("top", v, a);
9661                          scrolled = true;
9662                      }
9663                      break;
9664              }
9665              return scrolled;
9666         },
9667
9668         /**
9669          * Translates the passed page coordinates into left/top css values for this element
9670          * @param {Number/Array} x The page x or an array containing [x, y]
9671          * @param {Number} y The page y
9672          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9673          */
9674         translatePoints : function(x, y){
9675             if(typeof x == 'object' || x instanceof Array){
9676                 y = x[1]; x = x[0];
9677             }
9678             var p = this.getStyle('position');
9679             var o = this.getXY();
9680
9681             var l = parseInt(this.getStyle('left'), 10);
9682             var t = parseInt(this.getStyle('top'), 10);
9683
9684             if(isNaN(l)){
9685                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9686             }
9687             if(isNaN(t)){
9688                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9689             }
9690
9691             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9692         },
9693
9694         /**
9695          * Returns the current scroll position of the element.
9696          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9697          */
9698         getScroll : function(){
9699             var d = this.dom, doc = document;
9700             if(d == doc || d == doc.body){
9701                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9702                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9703                 return {left: l, top: t};
9704             }else{
9705                 return {left: d.scrollLeft, top: d.scrollTop};
9706             }
9707         },
9708
9709         /**
9710          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9711          * are convert to standard 6 digit hex color.
9712          * @param {String} attr The css attribute
9713          * @param {String} defaultValue The default value to use when a valid color isn't found
9714          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9715          * YUI color anims.
9716          */
9717         getColor : function(attr, defaultValue, prefix){
9718             var v = this.getStyle(attr);
9719             if(!v || v == "transparent" || v == "inherit") {
9720                 return defaultValue;
9721             }
9722             var color = typeof prefix == "undefined" ? "#" : prefix;
9723             if(v.substr(0, 4) == "rgb("){
9724                 var rvs = v.slice(4, v.length -1).split(",");
9725                 for(var i = 0; i < 3; i++){
9726                     var h = parseInt(rvs[i]).toString(16);
9727                     if(h < 16){
9728                         h = "0" + h;
9729                     }
9730                     color += h;
9731                 }
9732             } else {
9733                 if(v.substr(0, 1) == "#"){
9734                     if(v.length == 4) {
9735                         for(var i = 1; i < 4; i++){
9736                             var c = v.charAt(i);
9737                             color +=  c + c;
9738                         }
9739                     }else if(v.length == 7){
9740                         color += v.substr(1);
9741                     }
9742                 }
9743             }
9744             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9745         },
9746
9747         /**
9748          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9749          * gradient background, rounded corners and a 4-way shadow.
9750          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9751          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9752          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9753          * @return {Roo.Element} this
9754          */
9755         boxWrap : function(cls){
9756             cls = cls || 'x-box';
9757             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9758             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9759             return el;
9760         },
9761
9762         /**
9763          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9764          * @param {String} namespace The namespace in which to look for the attribute
9765          * @param {String} name The attribute name
9766          * @return {String} The attribute value
9767          */
9768         getAttributeNS : Roo.isIE ? function(ns, name){
9769             var d = this.dom;
9770             var type = typeof d[ns+":"+name];
9771             if(type != 'undefined' && type != 'unknown'){
9772                 return d[ns+":"+name];
9773             }
9774             return d[name];
9775         } : function(ns, name){
9776             var d = this.dom;
9777             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9778         },
9779         
9780         
9781         /**
9782          * Sets or Returns the value the dom attribute value
9783          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9784          * @param {String} value (optional) The value to set the attribute to
9785          * @return {String} The attribute value
9786          */
9787         attr : function(name){
9788             if (arguments.length > 1) {
9789                 this.dom.setAttribute(name, arguments[1]);
9790                 return arguments[1];
9791             }
9792             if (typeof(name) == 'object') {
9793                 for(var i in name) {
9794                     this.attr(i, name[i]);
9795                 }
9796                 return name;
9797             }
9798             
9799             
9800             if (!this.dom.hasAttribute(name)) {
9801                 return undefined;
9802             }
9803             return this.dom.getAttribute(name);
9804         }
9805         
9806         
9807         
9808     };
9809
9810     var ep = El.prototype;
9811
9812     /**
9813      * Appends an event handler (Shorthand for addListener)
9814      * @param {String}   eventName     The type of event to append
9815      * @param {Function} fn        The method the event invokes
9816      * @param {Object} scope       (optional) The scope (this object) of the fn
9817      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9818      * @method
9819      */
9820     ep.on = ep.addListener;
9821         // backwards compat
9822     ep.mon = ep.addListener;
9823
9824     /**
9825      * Removes an event handler from this element (shorthand for removeListener)
9826      * @param {String} eventName the type of event to remove
9827      * @param {Function} fn the method the event invokes
9828      * @return {Roo.Element} this
9829      * @method
9830      */
9831     ep.un = ep.removeListener;
9832
9833     /**
9834      * true to automatically adjust width and height settings for box-model issues (default to true)
9835      */
9836     ep.autoBoxAdjust = true;
9837
9838     // private
9839     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9840
9841     // private
9842     El.addUnits = function(v, defaultUnit){
9843         if(v === "" || v == "auto"){
9844             return v;
9845         }
9846         if(v === undefined){
9847             return '';
9848         }
9849         if(typeof v == "number" || !El.unitPattern.test(v)){
9850             return v + (defaultUnit || 'px');
9851         }
9852         return v;
9853     };
9854
9855     // special markup used throughout Roo when box wrapping elements
9856     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>';
9857     /**
9858      * Visibility mode constant - Use visibility to hide element
9859      * @static
9860      * @type Number
9861      */
9862     El.VISIBILITY = 1;
9863     /**
9864      * Visibility mode constant - Use display to hide element
9865      * @static
9866      * @type Number
9867      */
9868     El.DISPLAY = 2;
9869
9870     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9871     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9872     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9873
9874
9875
9876     /**
9877      * @private
9878      */
9879     El.cache = {};
9880
9881     var docEl;
9882
9883     /**
9884      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9885      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9886      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9887      * @return {Element} The Element object
9888      * @static
9889      */
9890     El.get = function(el){
9891         var ex, elm, id;
9892         if(!el){ return null; }
9893         if(typeof el == "string"){ // element id
9894             if(!(elm = document.getElementById(el))){
9895                 return null;
9896             }
9897             if(ex = El.cache[el]){
9898                 ex.dom = elm;
9899             }else{
9900                 ex = El.cache[el] = new El(elm);
9901             }
9902             return ex;
9903         }else if(el.tagName){ // dom element
9904             if(!(id = el.id)){
9905                 id = Roo.id(el);
9906             }
9907             if(ex = El.cache[id]){
9908                 ex.dom = el;
9909             }else{
9910                 ex = El.cache[id] = new El(el);
9911             }
9912             return ex;
9913         }else if(el instanceof El){
9914             if(el != docEl){
9915                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9916                                                               // catch case where it hasn't been appended
9917                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9918             }
9919             return el;
9920         }else if(el.isComposite){
9921             return el;
9922         }else if(el instanceof Array){
9923             return El.select(el);
9924         }else if(el == document){
9925             // create a bogus element object representing the document object
9926             if(!docEl){
9927                 var f = function(){};
9928                 f.prototype = El.prototype;
9929                 docEl = new f();
9930                 docEl.dom = document;
9931             }
9932             return docEl;
9933         }
9934         return null;
9935     };
9936
9937     // private
9938     El.uncache = function(el){
9939         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9940             if(a[i]){
9941                 delete El.cache[a[i].id || a[i]];
9942             }
9943         }
9944     };
9945
9946     // private
9947     // Garbage collection - uncache elements/purge listeners on orphaned elements
9948     // so we don't hold a reference and cause the browser to retain them
9949     El.garbageCollect = function(){
9950         if(!Roo.enableGarbageCollector){
9951             clearInterval(El.collectorThread);
9952             return;
9953         }
9954         for(var eid in El.cache){
9955             var el = El.cache[eid], d = el.dom;
9956             // -------------------------------------------------------
9957             // Determining what is garbage:
9958             // -------------------------------------------------------
9959             // !d
9960             // dom node is null, definitely garbage
9961             // -------------------------------------------------------
9962             // !d.parentNode
9963             // no parentNode == direct orphan, definitely garbage
9964             // -------------------------------------------------------
9965             // !d.offsetParent && !document.getElementById(eid)
9966             // display none elements have no offsetParent so we will
9967             // also try to look it up by it's id. However, check
9968             // offsetParent first so we don't do unneeded lookups.
9969             // This enables collection of elements that are not orphans
9970             // directly, but somewhere up the line they have an orphan
9971             // parent.
9972             // -------------------------------------------------------
9973             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9974                 delete El.cache[eid];
9975                 if(d && Roo.enableListenerCollection){
9976                     E.purgeElement(d);
9977                 }
9978             }
9979         }
9980     }
9981     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9982
9983
9984     // dom is optional
9985     El.Flyweight = function(dom){
9986         this.dom = dom;
9987     };
9988     El.Flyweight.prototype = El.prototype;
9989
9990     El._flyweights = {};
9991     /**
9992      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9993      * the dom node can be overwritten by other code.
9994      * @param {String/HTMLElement} el The dom node or id
9995      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9996      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9997      * @static
9998      * @return {Element} The shared Element object
9999      */
10000     El.fly = function(el, named){
10001         named = named || '_global';
10002         el = Roo.getDom(el);
10003         if(!el){
10004             return null;
10005         }
10006         if(!El._flyweights[named]){
10007             El._flyweights[named] = new El.Flyweight();
10008         }
10009         El._flyweights[named].dom = el;
10010         return El._flyweights[named];
10011     };
10012
10013     /**
10014      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10015      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10016      * Shorthand of {@link Roo.Element#get}
10017      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10018      * @return {Element} The Element object
10019      * @member Roo
10020      * @method get
10021      */
10022     Roo.get = El.get;
10023     /**
10024      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10025      * the dom node can be overwritten by other code.
10026      * Shorthand of {@link Roo.Element#fly}
10027      * @param {String/HTMLElement} el The dom node or id
10028      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10029      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10030      * @static
10031      * @return {Element} The shared Element object
10032      * @member Roo
10033      * @method fly
10034      */
10035     Roo.fly = El.fly;
10036
10037     // speedy lookup for elements never to box adjust
10038     var noBoxAdjust = Roo.isStrict ? {
10039         select:1
10040     } : {
10041         input:1, select:1, textarea:1
10042     };
10043     if(Roo.isIE || Roo.isGecko){
10044         noBoxAdjust['button'] = 1;
10045     }
10046
10047
10048     Roo.EventManager.on(window, 'unload', function(){
10049         delete El.cache;
10050         delete El._flyweights;
10051     });
10052 })();
10053
10054
10055
10056
10057 if(Roo.DomQuery){
10058     Roo.Element.selectorFunction = Roo.DomQuery.select;
10059 }
10060
10061 Roo.Element.select = function(selector, unique, root){
10062     var els;
10063     if(typeof selector == "string"){
10064         els = Roo.Element.selectorFunction(selector, root);
10065     }else if(selector.length !== undefined){
10066         els = selector;
10067     }else{
10068         throw "Invalid selector";
10069     }
10070     if(unique === true){
10071         return new Roo.CompositeElement(els);
10072     }else{
10073         return new Roo.CompositeElementLite(els);
10074     }
10075 };
10076 /**
10077  * Selects elements based on the passed CSS selector to enable working on them as 1.
10078  * @param {String/Array} selector The CSS selector or an array of elements
10079  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10080  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10081  * @return {CompositeElementLite/CompositeElement}
10082  * @member Roo
10083  * @method select
10084  */
10085 Roo.select = Roo.Element.select;
10086
10087
10088
10089
10090
10091
10092
10093
10094
10095
10096
10097
10098
10099
10100 /*
10101  * Based on:
10102  * Ext JS Library 1.1.1
10103  * Copyright(c) 2006-2007, Ext JS, LLC.
10104  *
10105  * Originally Released Under LGPL - original licence link has changed is not relivant.
10106  *
10107  * Fork - LGPL
10108  * <script type="text/javascript">
10109  */
10110
10111
10112
10113 //Notifies Element that fx methods are available
10114 Roo.enableFx = true;
10115
10116 /**
10117  * @class Roo.Fx
10118  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10119  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10120  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10121  * Element effects to work.</p><br/>
10122  *
10123  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10124  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10125  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10126  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10127  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10128  * expected results and should be done with care.</p><br/>
10129  *
10130  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10131  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10132 <pre>
10133 Value  Description
10134 -----  -----------------------------
10135 tl     The top left corner
10136 t      The center of the top edge
10137 tr     The top right corner
10138 l      The center of the left edge
10139 r      The center of the right edge
10140 bl     The bottom left corner
10141 b      The center of the bottom edge
10142 br     The bottom right corner
10143 </pre>
10144  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10145  * below are common options that can be passed to any Fx method.</b>
10146  * @cfg {Function} callback A function called when the effect is finished
10147  * @cfg {Object} scope The scope of the effect function
10148  * @cfg {String} easing A valid Easing value for the effect
10149  * @cfg {String} afterCls A css class to apply after the effect
10150  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10151  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10152  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10153  * effects that end with the element being visually hidden, ignored otherwise)
10154  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10155  * a function which returns such a specification that will be applied to the Element after the effect finishes
10156  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10157  * @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
10158  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10159  */
10160 Roo.Fx = {
10161         /**
10162          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10163          * origin for the slide effect.  This function automatically handles wrapping the element with
10164          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10165          * Usage:
10166          *<pre><code>
10167 // default: slide the element in from the top
10168 el.slideIn();
10169
10170 // custom: slide the element in from the right with a 2-second duration
10171 el.slideIn('r', { duration: 2 });
10172
10173 // common config options shown with default values
10174 el.slideIn('t', {
10175     easing: 'easeOut',
10176     duration: .5
10177 });
10178 </code></pre>
10179          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10180          * @param {Object} options (optional) Object literal with any of the Fx config options
10181          * @return {Roo.Element} The Element
10182          */
10183     slideIn : function(anchor, o){
10184         var el = this.getFxEl();
10185         o = o || {};
10186
10187         el.queueFx(o, function(){
10188
10189             anchor = anchor || "t";
10190
10191             // fix display to visibility
10192             this.fixDisplay();
10193
10194             // restore values after effect
10195             var r = this.getFxRestore();
10196             var b = this.getBox();
10197             // fixed size for slide
10198             this.setSize(b);
10199
10200             // wrap if needed
10201             var wrap = this.fxWrap(r.pos, o, "hidden");
10202
10203             var st = this.dom.style;
10204             st.visibility = "visible";
10205             st.position = "absolute";
10206
10207             // clear out temp styles after slide and unwrap
10208             var after = function(){
10209                 el.fxUnwrap(wrap, r.pos, o);
10210                 st.width = r.width;
10211                 st.height = r.height;
10212                 el.afterFx(o);
10213             };
10214             // time to calc the positions
10215             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10216
10217             switch(anchor.toLowerCase()){
10218                 case "t":
10219                     wrap.setSize(b.width, 0);
10220                     st.left = st.bottom = "0";
10221                     a = {height: bh};
10222                 break;
10223                 case "l":
10224                     wrap.setSize(0, b.height);
10225                     st.right = st.top = "0";
10226                     a = {width: bw};
10227                 break;
10228                 case "r":
10229                     wrap.setSize(0, b.height);
10230                     wrap.setX(b.right);
10231                     st.left = st.top = "0";
10232                     a = {width: bw, points: pt};
10233                 break;
10234                 case "b":
10235                     wrap.setSize(b.width, 0);
10236                     wrap.setY(b.bottom);
10237                     st.left = st.top = "0";
10238                     a = {height: bh, points: pt};
10239                 break;
10240                 case "tl":
10241                     wrap.setSize(0, 0);
10242                     st.right = st.bottom = "0";
10243                     a = {width: bw, height: bh};
10244                 break;
10245                 case "bl":
10246                     wrap.setSize(0, 0);
10247                     wrap.setY(b.y+b.height);
10248                     st.right = st.top = "0";
10249                     a = {width: bw, height: bh, points: pt};
10250                 break;
10251                 case "br":
10252                     wrap.setSize(0, 0);
10253                     wrap.setXY([b.right, b.bottom]);
10254                     st.left = st.top = "0";
10255                     a = {width: bw, height: bh, points: pt};
10256                 break;
10257                 case "tr":
10258                     wrap.setSize(0, 0);
10259                     wrap.setX(b.x+b.width);
10260                     st.left = st.bottom = "0";
10261                     a = {width: bw, height: bh, points: pt};
10262                 break;
10263             }
10264             this.dom.style.visibility = "visible";
10265             wrap.show();
10266
10267             arguments.callee.anim = wrap.fxanim(a,
10268                 o,
10269                 'motion',
10270                 .5,
10271                 'easeOut', after);
10272         });
10273         return this;
10274     },
10275     
10276         /**
10277          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10278          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10279          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10280          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10281          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10282          * Usage:
10283          *<pre><code>
10284 // default: slide the element out to the top
10285 el.slideOut();
10286
10287 // custom: slide the element out to the right with a 2-second duration
10288 el.slideOut('r', { duration: 2 });
10289
10290 // common config options shown with default values
10291 el.slideOut('t', {
10292     easing: 'easeOut',
10293     duration: .5,
10294     remove: false,
10295     useDisplay: false
10296 });
10297 </code></pre>
10298          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10299          * @param {Object} options (optional) Object literal with any of the Fx config options
10300          * @return {Roo.Element} The Element
10301          */
10302     slideOut : function(anchor, o){
10303         var el = this.getFxEl();
10304         o = o || {};
10305
10306         el.queueFx(o, function(){
10307
10308             anchor = anchor || "t";
10309
10310             // restore values after effect
10311             var r = this.getFxRestore();
10312             
10313             var b = this.getBox();
10314             // fixed size for slide
10315             this.setSize(b);
10316
10317             // wrap if needed
10318             var wrap = this.fxWrap(r.pos, o, "visible");
10319
10320             var st = this.dom.style;
10321             st.visibility = "visible";
10322             st.position = "absolute";
10323
10324             wrap.setSize(b);
10325
10326             var after = function(){
10327                 if(o.useDisplay){
10328                     el.setDisplayed(false);
10329                 }else{
10330                     el.hide();
10331                 }
10332
10333                 el.fxUnwrap(wrap, r.pos, o);
10334
10335                 st.width = r.width;
10336                 st.height = r.height;
10337
10338                 el.afterFx(o);
10339             };
10340
10341             var a, zero = {to: 0};
10342             switch(anchor.toLowerCase()){
10343                 case "t":
10344                     st.left = st.bottom = "0";
10345                     a = {height: zero};
10346                 break;
10347                 case "l":
10348                     st.right = st.top = "0";
10349                     a = {width: zero};
10350                 break;
10351                 case "r":
10352                     st.left = st.top = "0";
10353                     a = {width: zero, points: {to:[b.right, b.y]}};
10354                 break;
10355                 case "b":
10356                     st.left = st.top = "0";
10357                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10358                 break;
10359                 case "tl":
10360                     st.right = st.bottom = "0";
10361                     a = {width: zero, height: zero};
10362                 break;
10363                 case "bl":
10364                     st.right = st.top = "0";
10365                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10366                 break;
10367                 case "br":
10368                     st.left = st.top = "0";
10369                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10370                 break;
10371                 case "tr":
10372                     st.left = st.bottom = "0";
10373                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10374                 break;
10375             }
10376
10377             arguments.callee.anim = wrap.fxanim(a,
10378                 o,
10379                 'motion',
10380                 .5,
10381                 "easeOut", after);
10382         });
10383         return this;
10384     },
10385
10386         /**
10387          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10388          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10389          * The element must be removed from the DOM using the 'remove' config option if desired.
10390          * Usage:
10391          *<pre><code>
10392 // default
10393 el.puff();
10394
10395 // common config options shown with default values
10396 el.puff({
10397     easing: 'easeOut',
10398     duration: .5,
10399     remove: false,
10400     useDisplay: false
10401 });
10402 </code></pre>
10403          * @param {Object} options (optional) Object literal with any of the Fx config options
10404          * @return {Roo.Element} The Element
10405          */
10406     puff : function(o){
10407         var el = this.getFxEl();
10408         o = o || {};
10409
10410         el.queueFx(o, function(){
10411             this.clearOpacity();
10412             this.show();
10413
10414             // restore values after effect
10415             var r = this.getFxRestore();
10416             var st = this.dom.style;
10417
10418             var after = function(){
10419                 if(o.useDisplay){
10420                     el.setDisplayed(false);
10421                 }else{
10422                     el.hide();
10423                 }
10424
10425                 el.clearOpacity();
10426
10427                 el.setPositioning(r.pos);
10428                 st.width = r.width;
10429                 st.height = r.height;
10430                 st.fontSize = '';
10431                 el.afterFx(o);
10432             };
10433
10434             var width = this.getWidth();
10435             var height = this.getHeight();
10436
10437             arguments.callee.anim = this.fxanim({
10438                     width : {to: this.adjustWidth(width * 2)},
10439                     height : {to: this.adjustHeight(height * 2)},
10440                     points : {by: [-(width * .5), -(height * .5)]},
10441                     opacity : {to: 0},
10442                     fontSize: {to:200, unit: "%"}
10443                 },
10444                 o,
10445                 'motion',
10446                 .5,
10447                 "easeOut", after);
10448         });
10449         return this;
10450     },
10451
10452         /**
10453          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10454          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10455          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10456          * Usage:
10457          *<pre><code>
10458 // default
10459 el.switchOff();
10460
10461 // all config options shown with default values
10462 el.switchOff({
10463     easing: 'easeIn',
10464     duration: .3,
10465     remove: false,
10466     useDisplay: false
10467 });
10468 </code></pre>
10469          * @param {Object} options (optional) Object literal with any of the Fx config options
10470          * @return {Roo.Element} The Element
10471          */
10472     switchOff : function(o){
10473         var el = this.getFxEl();
10474         o = o || {};
10475
10476         el.queueFx(o, function(){
10477             this.clearOpacity();
10478             this.clip();
10479
10480             // restore values after effect
10481             var r = this.getFxRestore();
10482             var st = this.dom.style;
10483
10484             var after = function(){
10485                 if(o.useDisplay){
10486                     el.setDisplayed(false);
10487                 }else{
10488                     el.hide();
10489                 }
10490
10491                 el.clearOpacity();
10492                 el.setPositioning(r.pos);
10493                 st.width = r.width;
10494                 st.height = r.height;
10495
10496                 el.afterFx(o);
10497             };
10498
10499             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10500                 this.clearOpacity();
10501                 (function(){
10502                     this.fxanim({
10503                         height:{to:1},
10504                         points:{by:[0, this.getHeight() * .5]}
10505                     }, o, 'motion', 0.3, 'easeIn', after);
10506                 }).defer(100, this);
10507             });
10508         });
10509         return this;
10510     },
10511
10512     /**
10513      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10514      * changed using the "attr" config option) and then fading back to the original color. If no original
10515      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10516      * Usage:
10517 <pre><code>
10518 // default: highlight background to yellow
10519 el.highlight();
10520
10521 // custom: highlight foreground text to blue for 2 seconds
10522 el.highlight("0000ff", { attr: 'color', duration: 2 });
10523
10524 // common config options shown with default values
10525 el.highlight("ffff9c", {
10526     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10527     endColor: (current color) or "ffffff",
10528     easing: 'easeIn',
10529     duration: 1
10530 });
10531 </code></pre>
10532      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10533      * @param {Object} options (optional) Object literal with any of the Fx config options
10534      * @return {Roo.Element} The Element
10535      */ 
10536     highlight : function(color, o){
10537         var el = this.getFxEl();
10538         o = o || {};
10539
10540         el.queueFx(o, function(){
10541             color = color || "ffff9c";
10542             attr = o.attr || "backgroundColor";
10543
10544             this.clearOpacity();
10545             this.show();
10546
10547             var origColor = this.getColor(attr);
10548             var restoreColor = this.dom.style[attr];
10549             endColor = (o.endColor || origColor) || "ffffff";
10550
10551             var after = function(){
10552                 el.dom.style[attr] = restoreColor;
10553                 el.afterFx(o);
10554             };
10555
10556             var a = {};
10557             a[attr] = {from: color, to: endColor};
10558             arguments.callee.anim = this.fxanim(a,
10559                 o,
10560                 'color',
10561                 1,
10562                 'easeIn', after);
10563         });
10564         return this;
10565     },
10566
10567    /**
10568     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10569     * Usage:
10570 <pre><code>
10571 // default: a single light blue ripple
10572 el.frame();
10573
10574 // custom: 3 red ripples lasting 3 seconds total
10575 el.frame("ff0000", 3, { duration: 3 });
10576
10577 // common config options shown with default values
10578 el.frame("C3DAF9", 1, {
10579     duration: 1 //duration of entire animation (not each individual ripple)
10580     // Note: Easing is not configurable and will be ignored if included
10581 });
10582 </code></pre>
10583     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10584     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10585     * @param {Object} options (optional) Object literal with any of the Fx config options
10586     * @return {Roo.Element} The Element
10587     */
10588     frame : function(color, count, o){
10589         var el = this.getFxEl();
10590         o = o || {};
10591
10592         el.queueFx(o, function(){
10593             color = color || "#C3DAF9";
10594             if(color.length == 6){
10595                 color = "#" + color;
10596             }
10597             count = count || 1;
10598             duration = o.duration || 1;
10599             this.show();
10600
10601             var b = this.getBox();
10602             var animFn = function(){
10603                 var proxy = this.createProxy({
10604
10605                      style:{
10606                         visbility:"hidden",
10607                         position:"absolute",
10608                         "z-index":"35000", // yee haw
10609                         border:"0px solid " + color
10610                      }
10611                   });
10612                 var scale = Roo.isBorderBox ? 2 : 1;
10613                 proxy.animate({
10614                     top:{from:b.y, to:b.y - 20},
10615                     left:{from:b.x, to:b.x - 20},
10616                     borderWidth:{from:0, to:10},
10617                     opacity:{from:1, to:0},
10618                     height:{from:b.height, to:(b.height + (20*scale))},
10619                     width:{from:b.width, to:(b.width + (20*scale))}
10620                 }, duration, function(){
10621                     proxy.remove();
10622                 });
10623                 if(--count > 0){
10624                      animFn.defer((duration/2)*1000, this);
10625                 }else{
10626                     el.afterFx(o);
10627                 }
10628             };
10629             animFn.call(this);
10630         });
10631         return this;
10632     },
10633
10634    /**
10635     * Creates a pause before any subsequent queued effects begin.  If there are
10636     * no effects queued after the pause it will have no effect.
10637     * Usage:
10638 <pre><code>
10639 el.pause(1);
10640 </code></pre>
10641     * @param {Number} seconds The length of time to pause (in seconds)
10642     * @return {Roo.Element} The Element
10643     */
10644     pause : function(seconds){
10645         var el = this.getFxEl();
10646         var o = {};
10647
10648         el.queueFx(o, function(){
10649             setTimeout(function(){
10650                 el.afterFx(o);
10651             }, seconds * 1000);
10652         });
10653         return this;
10654     },
10655
10656    /**
10657     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10658     * using the "endOpacity" config option.
10659     * Usage:
10660 <pre><code>
10661 // default: fade in from opacity 0 to 100%
10662 el.fadeIn();
10663
10664 // custom: fade in from opacity 0 to 75% over 2 seconds
10665 el.fadeIn({ endOpacity: .75, duration: 2});
10666
10667 // common config options shown with default values
10668 el.fadeIn({
10669     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10670     easing: 'easeOut',
10671     duration: .5
10672 });
10673 </code></pre>
10674     * @param {Object} options (optional) Object literal with any of the Fx config options
10675     * @return {Roo.Element} The Element
10676     */
10677     fadeIn : function(o){
10678         var el = this.getFxEl();
10679         o = o || {};
10680         el.queueFx(o, function(){
10681             this.setOpacity(0);
10682             this.fixDisplay();
10683             this.dom.style.visibility = 'visible';
10684             var to = o.endOpacity || 1;
10685             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10686                 o, null, .5, "easeOut", function(){
10687                 if(to == 1){
10688                     this.clearOpacity();
10689                 }
10690                 el.afterFx(o);
10691             });
10692         });
10693         return this;
10694     },
10695
10696    /**
10697     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10698     * using the "endOpacity" config option.
10699     * Usage:
10700 <pre><code>
10701 // default: fade out from the element's current opacity to 0
10702 el.fadeOut();
10703
10704 // custom: fade out from the element's current opacity to 25% over 2 seconds
10705 el.fadeOut({ endOpacity: .25, duration: 2});
10706
10707 // common config options shown with default values
10708 el.fadeOut({
10709     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10710     easing: 'easeOut',
10711     duration: .5
10712     remove: false,
10713     useDisplay: false
10714 });
10715 </code></pre>
10716     * @param {Object} options (optional) Object literal with any of the Fx config options
10717     * @return {Roo.Element} The Element
10718     */
10719     fadeOut : function(o){
10720         var el = this.getFxEl();
10721         o = o || {};
10722         el.queueFx(o, function(){
10723             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10724                 o, null, .5, "easeOut", function(){
10725                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10726                      this.dom.style.display = "none";
10727                 }else{
10728                      this.dom.style.visibility = "hidden";
10729                 }
10730                 this.clearOpacity();
10731                 el.afterFx(o);
10732             });
10733         });
10734         return this;
10735     },
10736
10737    /**
10738     * Animates the transition of an element's dimensions from a starting height/width
10739     * to an ending height/width.
10740     * Usage:
10741 <pre><code>
10742 // change height and width to 100x100 pixels
10743 el.scale(100, 100);
10744
10745 // common config options shown with default values.  The height and width will default to
10746 // the element's existing values if passed as null.
10747 el.scale(
10748     [element's width],
10749     [element's height], {
10750     easing: 'easeOut',
10751     duration: .35
10752 });
10753 </code></pre>
10754     * @param {Number} width  The new width (pass undefined to keep the original width)
10755     * @param {Number} height  The new height (pass undefined to keep the original height)
10756     * @param {Object} options (optional) Object literal with any of the Fx config options
10757     * @return {Roo.Element} The Element
10758     */
10759     scale : function(w, h, o){
10760         this.shift(Roo.apply({}, o, {
10761             width: w,
10762             height: h
10763         }));
10764         return this;
10765     },
10766
10767    /**
10768     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10769     * Any of these properties not specified in the config object will not be changed.  This effect 
10770     * requires that at least one new dimension, position or opacity setting must be passed in on
10771     * the config object in order for the function to have any effect.
10772     * Usage:
10773 <pre><code>
10774 // slide the element horizontally to x position 200 while changing the height and opacity
10775 el.shift({ x: 200, height: 50, opacity: .8 });
10776
10777 // common config options shown with default values.
10778 el.shift({
10779     width: [element's width],
10780     height: [element's height],
10781     x: [element's x position],
10782     y: [element's y position],
10783     opacity: [element's opacity],
10784     easing: 'easeOut',
10785     duration: .35
10786 });
10787 </code></pre>
10788     * @param {Object} options  Object literal with any of the Fx config options
10789     * @return {Roo.Element} The Element
10790     */
10791     shift : function(o){
10792         var el = this.getFxEl();
10793         o = o || {};
10794         el.queueFx(o, function(){
10795             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10796             if(w !== undefined){
10797                 a.width = {to: this.adjustWidth(w)};
10798             }
10799             if(h !== undefined){
10800                 a.height = {to: this.adjustHeight(h)};
10801             }
10802             if(x !== undefined || y !== undefined){
10803                 a.points = {to: [
10804                     x !== undefined ? x : this.getX(),
10805                     y !== undefined ? y : this.getY()
10806                 ]};
10807             }
10808             if(op !== undefined){
10809                 a.opacity = {to: op};
10810             }
10811             if(o.xy !== undefined){
10812                 a.points = {to: o.xy};
10813             }
10814             arguments.callee.anim = this.fxanim(a,
10815                 o, 'motion', .35, "easeOut", function(){
10816                 el.afterFx(o);
10817             });
10818         });
10819         return this;
10820     },
10821
10822         /**
10823          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10824          * ending point of the effect.
10825          * Usage:
10826          *<pre><code>
10827 // default: slide the element downward while fading out
10828 el.ghost();
10829
10830 // custom: slide the element out to the right with a 2-second duration
10831 el.ghost('r', { duration: 2 });
10832
10833 // common config options shown with default values
10834 el.ghost('b', {
10835     easing: 'easeOut',
10836     duration: .5
10837     remove: false,
10838     useDisplay: false
10839 });
10840 </code></pre>
10841          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10842          * @param {Object} options (optional) Object literal with any of the Fx config options
10843          * @return {Roo.Element} The Element
10844          */
10845     ghost : function(anchor, o){
10846         var el = this.getFxEl();
10847         o = o || {};
10848
10849         el.queueFx(o, function(){
10850             anchor = anchor || "b";
10851
10852             // restore values after effect
10853             var r = this.getFxRestore();
10854             var w = this.getWidth(),
10855                 h = this.getHeight();
10856
10857             var st = this.dom.style;
10858
10859             var after = function(){
10860                 if(o.useDisplay){
10861                     el.setDisplayed(false);
10862                 }else{
10863                     el.hide();
10864                 }
10865
10866                 el.clearOpacity();
10867                 el.setPositioning(r.pos);
10868                 st.width = r.width;
10869                 st.height = r.height;
10870
10871                 el.afterFx(o);
10872             };
10873
10874             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10875             switch(anchor.toLowerCase()){
10876                 case "t":
10877                     pt.by = [0, -h];
10878                 break;
10879                 case "l":
10880                     pt.by = [-w, 0];
10881                 break;
10882                 case "r":
10883                     pt.by = [w, 0];
10884                 break;
10885                 case "b":
10886                     pt.by = [0, h];
10887                 break;
10888                 case "tl":
10889                     pt.by = [-w, -h];
10890                 break;
10891                 case "bl":
10892                     pt.by = [-w, h];
10893                 break;
10894                 case "br":
10895                     pt.by = [w, h];
10896                 break;
10897                 case "tr":
10898                     pt.by = [w, -h];
10899                 break;
10900             }
10901
10902             arguments.callee.anim = this.fxanim(a,
10903                 o,
10904                 'motion',
10905                 .5,
10906                 "easeOut", after);
10907         });
10908         return this;
10909     },
10910
10911         /**
10912          * Ensures that all effects queued after syncFx is called on the element are
10913          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10914          * @return {Roo.Element} The Element
10915          */
10916     syncFx : function(){
10917         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10918             block : false,
10919             concurrent : true,
10920             stopFx : false
10921         });
10922         return this;
10923     },
10924
10925         /**
10926          * Ensures that all effects queued after sequenceFx is called on the element are
10927          * run in sequence.  This is the opposite of {@link #syncFx}.
10928          * @return {Roo.Element} The Element
10929          */
10930     sequenceFx : function(){
10931         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10932             block : false,
10933             concurrent : false,
10934             stopFx : false
10935         });
10936         return this;
10937     },
10938
10939         /* @private */
10940     nextFx : function(){
10941         var ef = this.fxQueue[0];
10942         if(ef){
10943             ef.call(this);
10944         }
10945     },
10946
10947         /**
10948          * Returns true if the element has any effects actively running or queued, else returns false.
10949          * @return {Boolean} True if element has active effects, else false
10950          */
10951     hasActiveFx : function(){
10952         return this.fxQueue && this.fxQueue[0];
10953     },
10954
10955         /**
10956          * Stops any running effects and clears the element's internal effects queue if it contains
10957          * any additional effects that haven't started yet.
10958          * @return {Roo.Element} The Element
10959          */
10960     stopFx : function(){
10961         if(this.hasActiveFx()){
10962             var cur = this.fxQueue[0];
10963             if(cur && cur.anim && cur.anim.isAnimated()){
10964                 this.fxQueue = [cur]; // clear out others
10965                 cur.anim.stop(true);
10966             }
10967         }
10968         return this;
10969     },
10970
10971         /* @private */
10972     beforeFx : function(o){
10973         if(this.hasActiveFx() && !o.concurrent){
10974            if(o.stopFx){
10975                this.stopFx();
10976                return true;
10977            }
10978            return false;
10979         }
10980         return true;
10981     },
10982
10983         /**
10984          * Returns true if the element is currently blocking so that no other effect can be queued
10985          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10986          * used to ensure that an effect initiated by a user action runs to completion prior to the
10987          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10988          * @return {Boolean} True if blocking, else false
10989          */
10990     hasFxBlock : function(){
10991         var q = this.fxQueue;
10992         return q && q[0] && q[0].block;
10993     },
10994
10995         /* @private */
10996     queueFx : function(o, fn){
10997         if(!this.fxQueue){
10998             this.fxQueue = [];
10999         }
11000         if(!this.hasFxBlock()){
11001             Roo.applyIf(o, this.fxDefaults);
11002             if(!o.concurrent){
11003                 var run = this.beforeFx(o);
11004                 fn.block = o.block;
11005                 this.fxQueue.push(fn);
11006                 if(run){
11007                     this.nextFx();
11008                 }
11009             }else{
11010                 fn.call(this);
11011             }
11012         }
11013         return this;
11014     },
11015
11016         /* @private */
11017     fxWrap : function(pos, o, vis){
11018         var wrap;
11019         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11020             var wrapXY;
11021             if(o.fixPosition){
11022                 wrapXY = this.getXY();
11023             }
11024             var div = document.createElement("div");
11025             div.style.visibility = vis;
11026             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11027             wrap.setPositioning(pos);
11028             if(wrap.getStyle("position") == "static"){
11029                 wrap.position("relative");
11030             }
11031             this.clearPositioning('auto');
11032             wrap.clip();
11033             wrap.dom.appendChild(this.dom);
11034             if(wrapXY){
11035                 wrap.setXY(wrapXY);
11036             }
11037         }
11038         return wrap;
11039     },
11040
11041         /* @private */
11042     fxUnwrap : function(wrap, pos, o){
11043         this.clearPositioning();
11044         this.setPositioning(pos);
11045         if(!o.wrap){
11046             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11047             wrap.remove();
11048         }
11049     },
11050
11051         /* @private */
11052     getFxRestore : function(){
11053         var st = this.dom.style;
11054         return {pos: this.getPositioning(), width: st.width, height : st.height};
11055     },
11056
11057         /* @private */
11058     afterFx : function(o){
11059         if(o.afterStyle){
11060             this.applyStyles(o.afterStyle);
11061         }
11062         if(o.afterCls){
11063             this.addClass(o.afterCls);
11064         }
11065         if(o.remove === true){
11066             this.remove();
11067         }
11068         Roo.callback(o.callback, o.scope, [this]);
11069         if(!o.concurrent){
11070             this.fxQueue.shift();
11071             this.nextFx();
11072         }
11073     },
11074
11075         /* @private */
11076     getFxEl : function(){ // support for composite element fx
11077         return Roo.get(this.dom);
11078     },
11079
11080         /* @private */
11081     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11082         animType = animType || 'run';
11083         opt = opt || {};
11084         var anim = Roo.lib.Anim[animType](
11085             this.dom, args,
11086             (opt.duration || defaultDur) || .35,
11087             (opt.easing || defaultEase) || 'easeOut',
11088             function(){
11089                 Roo.callback(cb, this);
11090             },
11091             this
11092         );
11093         opt.anim = anim;
11094         return anim;
11095     }
11096 };
11097
11098 // backwords compat
11099 Roo.Fx.resize = Roo.Fx.scale;
11100
11101 //When included, Roo.Fx is automatically applied to Element so that all basic
11102 //effects are available directly via the Element API
11103 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11104  * Based on:
11105  * Ext JS Library 1.1.1
11106  * Copyright(c) 2006-2007, Ext JS, LLC.
11107  *
11108  * Originally Released Under LGPL - original licence link has changed is not relivant.
11109  *
11110  * Fork - LGPL
11111  * <script type="text/javascript">
11112  */
11113
11114
11115 /**
11116  * @class Roo.CompositeElement
11117  * Standard composite class. Creates a Roo.Element for every element in the collection.
11118  * <br><br>
11119  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11120  * actions will be performed on all the elements in this collection.</b>
11121  * <br><br>
11122  * All methods return <i>this</i> and can be chained.
11123  <pre><code>
11124  var els = Roo.select("#some-el div.some-class", true);
11125  // or select directly from an existing element
11126  var el = Roo.get('some-el');
11127  el.select('div.some-class', true);
11128
11129  els.setWidth(100); // all elements become 100 width
11130  els.hide(true); // all elements fade out and hide
11131  // or
11132  els.setWidth(100).hide(true);
11133  </code></pre>
11134  */
11135 Roo.CompositeElement = function(els){
11136     this.elements = [];
11137     this.addElements(els);
11138 };
11139 Roo.CompositeElement.prototype = {
11140     isComposite: true,
11141     addElements : function(els){
11142         if(!els) {
11143             return this;
11144         }
11145         if(typeof els == "string"){
11146             els = Roo.Element.selectorFunction(els);
11147         }
11148         var yels = this.elements;
11149         var index = yels.length-1;
11150         for(var i = 0, len = els.length; i < len; i++) {
11151                 yels[++index] = Roo.get(els[i]);
11152         }
11153         return this;
11154     },
11155
11156     /**
11157     * Clears this composite and adds the elements returned by the passed selector.
11158     * @param {String/Array} els A string CSS selector, an array of elements or an element
11159     * @return {CompositeElement} this
11160     */
11161     fill : function(els){
11162         this.elements = [];
11163         this.add(els);
11164         return this;
11165     },
11166
11167     /**
11168     * Filters this composite to only elements that match the passed selector.
11169     * @param {String} selector A string CSS selector
11170     * @param {Boolean} inverse return inverse filter (not matches)
11171     * @return {CompositeElement} this
11172     */
11173     filter : function(selector, inverse){
11174         var els = [];
11175         inverse = inverse || false;
11176         this.each(function(el){
11177             var match = inverse ? !el.is(selector) : el.is(selector);
11178             if(match){
11179                 els[els.length] = el.dom;
11180             }
11181         });
11182         this.fill(els);
11183         return this;
11184     },
11185
11186     invoke : function(fn, args){
11187         var els = this.elements;
11188         for(var i = 0, len = els.length; i < len; i++) {
11189                 Roo.Element.prototype[fn].apply(els[i], args);
11190         }
11191         return this;
11192     },
11193     /**
11194     * Adds elements to this composite.
11195     * @param {String/Array} els A string CSS selector, an array of elements or an element
11196     * @return {CompositeElement} this
11197     */
11198     add : function(els){
11199         if(typeof els == "string"){
11200             this.addElements(Roo.Element.selectorFunction(els));
11201         }else if(els.length !== undefined){
11202             this.addElements(els);
11203         }else{
11204             this.addElements([els]);
11205         }
11206         return this;
11207     },
11208     /**
11209     * Calls the passed function passing (el, this, index) for each element in this composite.
11210     * @param {Function} fn The function to call
11211     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11212     * @return {CompositeElement} this
11213     */
11214     each : function(fn, scope){
11215         var els = this.elements;
11216         for(var i = 0, len = els.length; i < len; i++){
11217             if(fn.call(scope || els[i], els[i], this, i) === false) {
11218                 break;
11219             }
11220         }
11221         return this;
11222     },
11223
11224     /**
11225      * Returns the Element object at the specified index
11226      * @param {Number} index
11227      * @return {Roo.Element}
11228      */
11229     item : function(index){
11230         return this.elements[index] || null;
11231     },
11232
11233     /**
11234      * Returns the first Element
11235      * @return {Roo.Element}
11236      */
11237     first : function(){
11238         return this.item(0);
11239     },
11240
11241     /**
11242      * Returns the last Element
11243      * @return {Roo.Element}
11244      */
11245     last : function(){
11246         return this.item(this.elements.length-1);
11247     },
11248
11249     /**
11250      * Returns the number of elements in this composite
11251      * @return Number
11252      */
11253     getCount : function(){
11254         return this.elements.length;
11255     },
11256
11257     /**
11258      * Returns true if this composite contains the passed element
11259      * @return Boolean
11260      */
11261     contains : function(el){
11262         return this.indexOf(el) !== -1;
11263     },
11264
11265     /**
11266      * Returns true if this composite contains the passed element
11267      * @return Boolean
11268      */
11269     indexOf : function(el){
11270         return this.elements.indexOf(Roo.get(el));
11271     },
11272
11273
11274     /**
11275     * Removes the specified element(s).
11276     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11277     * or an array of any of those.
11278     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11279     * @return {CompositeElement} this
11280     */
11281     removeElement : function(el, removeDom){
11282         if(el instanceof Array){
11283             for(var i = 0, len = el.length; i < len; i++){
11284                 this.removeElement(el[i]);
11285             }
11286             return this;
11287         }
11288         var index = typeof el == 'number' ? el : this.indexOf(el);
11289         if(index !== -1){
11290             if(removeDom){
11291                 var d = this.elements[index];
11292                 if(d.dom){
11293                     d.remove();
11294                 }else{
11295                     d.parentNode.removeChild(d);
11296                 }
11297             }
11298             this.elements.splice(index, 1);
11299         }
11300         return this;
11301     },
11302
11303     /**
11304     * Replaces the specified element with the passed element.
11305     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11306     * to replace.
11307     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11308     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11309     * @return {CompositeElement} this
11310     */
11311     replaceElement : function(el, replacement, domReplace){
11312         var index = typeof el == 'number' ? el : this.indexOf(el);
11313         if(index !== -1){
11314             if(domReplace){
11315                 this.elements[index].replaceWith(replacement);
11316             }else{
11317                 this.elements.splice(index, 1, Roo.get(replacement))
11318             }
11319         }
11320         return this;
11321     },
11322
11323     /**
11324      * Removes all elements.
11325      */
11326     clear : function(){
11327         this.elements = [];
11328     }
11329 };
11330 (function(){
11331     Roo.CompositeElement.createCall = function(proto, fnName){
11332         if(!proto[fnName]){
11333             proto[fnName] = function(){
11334                 return this.invoke(fnName, arguments);
11335             };
11336         }
11337     };
11338     for(var fnName in Roo.Element.prototype){
11339         if(typeof Roo.Element.prototype[fnName] == "function"){
11340             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11341         }
11342     };
11343 })();
11344 /*
11345  * Based on:
11346  * Ext JS Library 1.1.1
11347  * Copyright(c) 2006-2007, Ext JS, LLC.
11348  *
11349  * Originally Released Under LGPL - original licence link has changed is not relivant.
11350  *
11351  * Fork - LGPL
11352  * <script type="text/javascript">
11353  */
11354
11355 /**
11356  * @class Roo.CompositeElementLite
11357  * @extends Roo.CompositeElement
11358  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11359  <pre><code>
11360  var els = Roo.select("#some-el div.some-class");
11361  // or select directly from an existing element
11362  var el = Roo.get('some-el');
11363  el.select('div.some-class');
11364
11365  els.setWidth(100); // all elements become 100 width
11366  els.hide(true); // all elements fade out and hide
11367  // or
11368  els.setWidth(100).hide(true);
11369  </code></pre><br><br>
11370  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11371  * actions will be performed on all the elements in this collection.</b>
11372  */
11373 Roo.CompositeElementLite = function(els){
11374     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11375     this.el = new Roo.Element.Flyweight();
11376 };
11377 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11378     addElements : function(els){
11379         if(els){
11380             if(els instanceof Array){
11381                 this.elements = this.elements.concat(els);
11382             }else{
11383                 var yels = this.elements;
11384                 var index = yels.length-1;
11385                 for(var i = 0, len = els.length; i < len; i++) {
11386                     yels[++index] = els[i];
11387                 }
11388             }
11389         }
11390         return this;
11391     },
11392     invoke : function(fn, args){
11393         var els = this.elements;
11394         var el = this.el;
11395         for(var i = 0, len = els.length; i < len; i++) {
11396             el.dom = els[i];
11397                 Roo.Element.prototype[fn].apply(el, args);
11398         }
11399         return this;
11400     },
11401     /**
11402      * Returns a flyweight Element of the dom element object at the specified index
11403      * @param {Number} index
11404      * @return {Roo.Element}
11405      */
11406     item : function(index){
11407         if(!this.elements[index]){
11408             return null;
11409         }
11410         this.el.dom = this.elements[index];
11411         return this.el;
11412     },
11413
11414     // fixes scope with flyweight
11415     addListener : function(eventName, handler, scope, opt){
11416         var els = this.elements;
11417         for(var i = 0, len = els.length; i < len; i++) {
11418             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11419         }
11420         return this;
11421     },
11422
11423     /**
11424     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11425     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11426     * a reference to the dom node, use el.dom.</b>
11427     * @param {Function} fn The function to call
11428     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11429     * @return {CompositeElement} this
11430     */
11431     each : function(fn, scope){
11432         var els = this.elements;
11433         var el = this.el;
11434         for(var i = 0, len = els.length; i < len; i++){
11435             el.dom = els[i];
11436                 if(fn.call(scope || el, el, this, i) === false){
11437                 break;
11438             }
11439         }
11440         return this;
11441     },
11442
11443     indexOf : function(el){
11444         return this.elements.indexOf(Roo.getDom(el));
11445     },
11446
11447     replaceElement : function(el, replacement, domReplace){
11448         var index = typeof el == 'number' ? el : this.indexOf(el);
11449         if(index !== -1){
11450             replacement = Roo.getDom(replacement);
11451             if(domReplace){
11452                 var d = this.elements[index];
11453                 d.parentNode.insertBefore(replacement, d);
11454                 d.parentNode.removeChild(d);
11455             }
11456             this.elements.splice(index, 1, replacement);
11457         }
11458         return this;
11459     }
11460 });
11461 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11462
11463 /*
11464  * Based on:
11465  * Ext JS Library 1.1.1
11466  * Copyright(c) 2006-2007, Ext JS, LLC.
11467  *
11468  * Originally Released Under LGPL - original licence link has changed is not relivant.
11469  *
11470  * Fork - LGPL
11471  * <script type="text/javascript">
11472  */
11473
11474  
11475
11476 /**
11477  * @class Roo.data.Connection
11478  * @extends Roo.util.Observable
11479  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11480  * either to a configured URL, or to a URL specified at request time.<br><br>
11481  * <p>
11482  * Requests made by this class are asynchronous, and will return immediately. No data from
11483  * the server will be available to the statement immediately following the {@link #request} call.
11484  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11485  * <p>
11486  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11487  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11488  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11489  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11490  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11491  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11492  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11493  * standard DOM methods.
11494  * @constructor
11495  * @param {Object} config a configuration object.
11496  */
11497 Roo.data.Connection = function(config){
11498     Roo.apply(this, config);
11499     this.addEvents({
11500         /**
11501          * @event beforerequest
11502          * Fires before a network request is made to retrieve a data object.
11503          * @param {Connection} conn This Connection object.
11504          * @param {Object} options The options config object passed to the {@link #request} method.
11505          */
11506         "beforerequest" : true,
11507         /**
11508          * @event requestcomplete
11509          * Fires if the request was successfully completed.
11510          * @param {Connection} conn This Connection object.
11511          * @param {Object} response The XHR object containing the response data.
11512          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11513          * @param {Object} options The options config object passed to the {@link #request} method.
11514          */
11515         "requestcomplete" : true,
11516         /**
11517          * @event requestexception
11518          * Fires if an error HTTP status was returned from the server.
11519          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11520          * @param {Connection} conn This Connection object.
11521          * @param {Object} response The XHR object containing the response data.
11522          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11523          * @param {Object} options The options config object passed to the {@link #request} method.
11524          */
11525         "requestexception" : true
11526     });
11527     Roo.data.Connection.superclass.constructor.call(this);
11528 };
11529
11530 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11531     /**
11532      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11533      */
11534     /**
11535      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11536      * extra parameters to each request made by this object. (defaults to undefined)
11537      */
11538     /**
11539      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11540      *  to each request made by this object. (defaults to undefined)
11541      */
11542     /**
11543      * @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)
11544      */
11545     /**
11546      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11547      */
11548     timeout : 30000,
11549     /**
11550      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11551      * @type Boolean
11552      */
11553     autoAbort:false,
11554
11555     /**
11556      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11557      * @type Boolean
11558      */
11559     disableCaching: true,
11560
11561     /**
11562      * Sends an HTTP request to a remote server.
11563      * @param {Object} options An object which may contain the following properties:<ul>
11564      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11565      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11566      * request, a url encoded string or a function to call to get either.</li>
11567      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11568      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11569      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11570      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11571      * <li>options {Object} The parameter to the request call.</li>
11572      * <li>success {Boolean} True if the request succeeded.</li>
11573      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11574      * </ul></li>
11575      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11576      * The callback is passed the following parameters:<ul>
11577      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11578      * <li>options {Object} The parameter to the request call.</li>
11579      * </ul></li>
11580      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11581      * The callback is passed the following parameters:<ul>
11582      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11583      * <li>options {Object} The parameter to the request call.</li>
11584      * </ul></li>
11585      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11586      * for the callback function. Defaults to the browser window.</li>
11587      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11588      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11589      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11590      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11591      * params for the post data. Any params will be appended to the URL.</li>
11592      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11593      * </ul>
11594      * @return {Number} transactionId
11595      */
11596     request : function(o){
11597         if(this.fireEvent("beforerequest", this, o) !== false){
11598             var p = o.params;
11599
11600             if(typeof p == "function"){
11601                 p = p.call(o.scope||window, o);
11602             }
11603             if(typeof p == "object"){
11604                 p = Roo.urlEncode(o.params);
11605             }
11606             if(this.extraParams){
11607                 var extras = Roo.urlEncode(this.extraParams);
11608                 p = p ? (p + '&' + extras) : extras;
11609             }
11610
11611             var url = o.url || this.url;
11612             if(typeof url == 'function'){
11613                 url = url.call(o.scope||window, o);
11614             }
11615
11616             if(o.form){
11617                 var form = Roo.getDom(o.form);
11618                 url = url || form.action;
11619
11620                 var enctype = form.getAttribute("enctype");
11621                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11622                     return this.doFormUpload(o, p, url);
11623                 }
11624                 var f = Roo.lib.Ajax.serializeForm(form);
11625                 p = p ? (p + '&' + f) : f;
11626             }
11627
11628             var hs = o.headers;
11629             if(this.defaultHeaders){
11630                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11631                 if(!o.headers){
11632                     o.headers = hs;
11633                 }
11634             }
11635
11636             var cb = {
11637                 success: this.handleResponse,
11638                 failure: this.handleFailure,
11639                 scope: this,
11640                 argument: {options: o},
11641                 timeout : o.timeout || this.timeout
11642             };
11643
11644             var method = o.method||this.method||(p ? "POST" : "GET");
11645
11646             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11647                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11648             }
11649
11650             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11651                 if(o.autoAbort){
11652                     this.abort();
11653                 }
11654             }else if(this.autoAbort !== false){
11655                 this.abort();
11656             }
11657
11658             if((method == 'GET' && p) || o.xmlData){
11659                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11660                 p = '';
11661             }
11662             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11663             return this.transId;
11664         }else{
11665             Roo.callback(o.callback, o.scope, [o, null, null]);
11666             return null;
11667         }
11668     },
11669
11670     /**
11671      * Determine whether this object has a request outstanding.
11672      * @param {Number} transactionId (Optional) defaults to the last transaction
11673      * @return {Boolean} True if there is an outstanding request.
11674      */
11675     isLoading : function(transId){
11676         if(transId){
11677             return Roo.lib.Ajax.isCallInProgress(transId);
11678         }else{
11679             return this.transId ? true : false;
11680         }
11681     },
11682
11683     /**
11684      * Aborts any outstanding request.
11685      * @param {Number} transactionId (Optional) defaults to the last transaction
11686      */
11687     abort : function(transId){
11688         if(transId || this.isLoading()){
11689             Roo.lib.Ajax.abort(transId || this.transId);
11690         }
11691     },
11692
11693     // private
11694     handleResponse : function(response){
11695         this.transId = false;
11696         var options = response.argument.options;
11697         response.argument = options ? options.argument : null;
11698         this.fireEvent("requestcomplete", this, response, options);
11699         Roo.callback(options.success, options.scope, [response, options]);
11700         Roo.callback(options.callback, options.scope, [options, true, response]);
11701     },
11702
11703     // private
11704     handleFailure : function(response, e){
11705         this.transId = false;
11706         var options = response.argument.options;
11707         response.argument = options ? options.argument : null;
11708         this.fireEvent("requestexception", this, response, options, e);
11709         Roo.callback(options.failure, options.scope, [response, options]);
11710         Roo.callback(options.callback, options.scope, [options, false, response]);
11711     },
11712
11713     // private
11714     doFormUpload : function(o, ps, url){
11715         var id = Roo.id();
11716         var frame = document.createElement('iframe');
11717         frame.id = id;
11718         frame.name = id;
11719         frame.className = 'x-hidden';
11720         if(Roo.isIE){
11721             frame.src = Roo.SSL_SECURE_URL;
11722         }
11723         document.body.appendChild(frame);
11724
11725         if(Roo.isIE){
11726            document.frames[id].name = id;
11727         }
11728
11729         var form = Roo.getDom(o.form);
11730         form.target = id;
11731         form.method = 'POST';
11732         form.enctype = form.encoding = 'multipart/form-data';
11733         if(url){
11734             form.action = url;
11735         }
11736
11737         var hiddens, hd;
11738         if(ps){ // add dynamic params
11739             hiddens = [];
11740             ps = Roo.urlDecode(ps, false);
11741             for(var k in ps){
11742                 if(ps.hasOwnProperty(k)){
11743                     hd = document.createElement('input');
11744                     hd.type = 'hidden';
11745                     hd.name = k;
11746                     hd.value = ps[k];
11747                     form.appendChild(hd);
11748                     hiddens.push(hd);
11749                 }
11750             }
11751         }
11752
11753         function cb(){
11754             var r = {  // bogus response object
11755                 responseText : '',
11756                 responseXML : null
11757             };
11758
11759             r.argument = o ? o.argument : null;
11760
11761             try { //
11762                 var doc;
11763                 if(Roo.isIE){
11764                     doc = frame.contentWindow.document;
11765                 }else {
11766                     doc = (frame.contentDocument || window.frames[id].document);
11767                 }
11768                 if(doc && doc.body){
11769                     r.responseText = doc.body.innerHTML;
11770                 }
11771                 if(doc && doc.XMLDocument){
11772                     r.responseXML = doc.XMLDocument;
11773                 }else {
11774                     r.responseXML = doc;
11775                 }
11776             }
11777             catch(e) {
11778                 // ignore
11779             }
11780
11781             Roo.EventManager.removeListener(frame, 'load', cb, this);
11782
11783             this.fireEvent("requestcomplete", this, r, o);
11784             Roo.callback(o.success, o.scope, [r, o]);
11785             Roo.callback(o.callback, o.scope, [o, true, r]);
11786
11787             setTimeout(function(){document.body.removeChild(frame);}, 100);
11788         }
11789
11790         Roo.EventManager.on(frame, 'load', cb, this);
11791         form.submit();
11792
11793         if(hiddens){ // remove dynamic params
11794             for(var i = 0, len = hiddens.length; i < len; i++){
11795                 form.removeChild(hiddens[i]);
11796             }
11797         }
11798     }
11799 });
11800 /*
11801  * Based on:
11802  * Ext JS Library 1.1.1
11803  * Copyright(c) 2006-2007, Ext JS, LLC.
11804  *
11805  * Originally Released Under LGPL - original licence link has changed is not relivant.
11806  *
11807  * Fork - LGPL
11808  * <script type="text/javascript">
11809  */
11810  
11811 /**
11812  * Global Ajax request class.
11813  * 
11814  * @class Roo.Ajax
11815  * @extends Roo.data.Connection
11816  * @static
11817  * 
11818  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11819  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11820  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11821  * @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)
11822  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11823  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11824  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11825  */
11826 Roo.Ajax = new Roo.data.Connection({
11827     // fix up the docs
11828     /**
11829      * @scope Roo.Ajax
11830      * @type {Boolear} 
11831      */
11832     autoAbort : false,
11833
11834     /**
11835      * Serialize the passed form into a url encoded string
11836      * @scope Roo.Ajax
11837      * @param {String/HTMLElement} form
11838      * @return {String}
11839      */
11840     serializeForm : function(form){
11841         return Roo.lib.Ajax.serializeForm(form);
11842     }
11843 });/*
11844  * Based on:
11845  * Ext JS Library 1.1.1
11846  * Copyright(c) 2006-2007, Ext JS, LLC.
11847  *
11848  * Originally Released Under LGPL - original licence link has changed is not relivant.
11849  *
11850  * Fork - LGPL
11851  * <script type="text/javascript">
11852  */
11853
11854  
11855 /**
11856  * @class Roo.UpdateManager
11857  * @extends Roo.util.Observable
11858  * Provides AJAX-style update for Element object.<br><br>
11859  * Usage:<br>
11860  * <pre><code>
11861  * // Get it from a Roo.Element object
11862  * var el = Roo.get("foo");
11863  * var mgr = el.getUpdateManager();
11864  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11865  * ...
11866  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11867  * <br>
11868  * // or directly (returns the same UpdateManager instance)
11869  * var mgr = new Roo.UpdateManager("myElementId");
11870  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11871  * mgr.on("update", myFcnNeedsToKnow);
11872  * <br>
11873    // short handed call directly from the element object
11874    Roo.get("foo").load({
11875         url: "bar.php",
11876         scripts:true,
11877         params: "for=bar",
11878         text: "Loading Foo..."
11879    });
11880  * </code></pre>
11881  * @constructor
11882  * Create new UpdateManager directly.
11883  * @param {String/HTMLElement/Roo.Element} el The element to update
11884  * @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).
11885  */
11886 Roo.UpdateManager = function(el, forceNew){
11887     el = Roo.get(el);
11888     if(!forceNew && el.updateManager){
11889         return el.updateManager;
11890     }
11891     /**
11892      * The Element object
11893      * @type Roo.Element
11894      */
11895     this.el = el;
11896     /**
11897      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11898      * @type String
11899      */
11900     this.defaultUrl = null;
11901
11902     this.addEvents({
11903         /**
11904          * @event beforeupdate
11905          * Fired before an update is made, return false from your handler and the update is cancelled.
11906          * @param {Roo.Element} el
11907          * @param {String/Object/Function} url
11908          * @param {String/Object} params
11909          */
11910         "beforeupdate": true,
11911         /**
11912          * @event update
11913          * Fired after successful update is made.
11914          * @param {Roo.Element} el
11915          * @param {Object} oResponseObject The response Object
11916          */
11917         "update": true,
11918         /**
11919          * @event failure
11920          * Fired on update failure.
11921          * @param {Roo.Element} el
11922          * @param {Object} oResponseObject The response Object
11923          */
11924         "failure": true
11925     });
11926     var d = Roo.UpdateManager.defaults;
11927     /**
11928      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11929      * @type String
11930      */
11931     this.sslBlankUrl = d.sslBlankUrl;
11932     /**
11933      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11934      * @type Boolean
11935      */
11936     this.disableCaching = d.disableCaching;
11937     /**
11938      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11939      * @type String
11940      */
11941     this.indicatorText = d.indicatorText;
11942     /**
11943      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11944      * @type String
11945      */
11946     this.showLoadIndicator = d.showLoadIndicator;
11947     /**
11948      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11949      * @type Number
11950      */
11951     this.timeout = d.timeout;
11952
11953     /**
11954      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11955      * @type Boolean
11956      */
11957     this.loadScripts = d.loadScripts;
11958
11959     /**
11960      * Transaction object of current executing transaction
11961      */
11962     this.transaction = null;
11963
11964     /**
11965      * @private
11966      */
11967     this.autoRefreshProcId = null;
11968     /**
11969      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11970      * @type Function
11971      */
11972     this.refreshDelegate = this.refresh.createDelegate(this);
11973     /**
11974      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11975      * @type Function
11976      */
11977     this.updateDelegate = this.update.createDelegate(this);
11978     /**
11979      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11980      * @type Function
11981      */
11982     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11983     /**
11984      * @private
11985      */
11986     this.successDelegate = this.processSuccess.createDelegate(this);
11987     /**
11988      * @private
11989      */
11990     this.failureDelegate = this.processFailure.createDelegate(this);
11991
11992     if(!this.renderer){
11993      /**
11994       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11995       */
11996     this.renderer = new Roo.UpdateManager.BasicRenderer();
11997     }
11998     
11999     Roo.UpdateManager.superclass.constructor.call(this);
12000 };
12001
12002 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12003     /**
12004      * Get the Element this UpdateManager is bound to
12005      * @return {Roo.Element} The element
12006      */
12007     getEl : function(){
12008         return this.el;
12009     },
12010     /**
12011      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12012      * @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:
12013 <pre><code>
12014 um.update({<br/>
12015     url: "your-url.php",<br/>
12016     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12017     callback: yourFunction,<br/>
12018     scope: yourObject, //(optional scope)  <br/>
12019     discardUrl: false, <br/>
12020     nocache: false,<br/>
12021     text: "Loading...",<br/>
12022     timeout: 30,<br/>
12023     scripts: false<br/>
12024 });
12025 </code></pre>
12026      * The only required property is url. The optional properties nocache, text and scripts
12027      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12028      * @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}
12029      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12030      * @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.
12031      */
12032     update : function(url, params, callback, discardUrl){
12033         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12034             var method = this.method,
12035                 cfg;
12036             if(typeof url == "object"){ // must be config object
12037                 cfg = url;
12038                 url = cfg.url;
12039                 params = params || cfg.params;
12040                 callback = callback || cfg.callback;
12041                 discardUrl = discardUrl || cfg.discardUrl;
12042                 if(callback && cfg.scope){
12043                     callback = callback.createDelegate(cfg.scope);
12044                 }
12045                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12046                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12047                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12048                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12049                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12050             }
12051             this.showLoading();
12052             if(!discardUrl){
12053                 this.defaultUrl = url;
12054             }
12055             if(typeof url == "function"){
12056                 url = url.call(this);
12057             }
12058
12059             method = method || (params ? "POST" : "GET");
12060             if(method == "GET"){
12061                 url = this.prepareUrl(url);
12062             }
12063
12064             var o = Roo.apply(cfg ||{}, {
12065                 url : url,
12066                 params: params,
12067                 success: this.successDelegate,
12068                 failure: this.failureDelegate,
12069                 callback: undefined,
12070                 timeout: (this.timeout*1000),
12071                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12072             });
12073             Roo.log("updated manager called with timeout of " + o.timeout);
12074             this.transaction = Roo.Ajax.request(o);
12075         }
12076     },
12077
12078     /**
12079      * 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.
12080      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12081      * @param {String/HTMLElement} form The form Id or form element
12082      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12083      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12084      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12085      */
12086     formUpdate : function(form, url, reset, callback){
12087         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12088             if(typeof url == "function"){
12089                 url = url.call(this);
12090             }
12091             form = Roo.getDom(form);
12092             this.transaction = Roo.Ajax.request({
12093                 form: form,
12094                 url:url,
12095                 success: this.successDelegate,
12096                 failure: this.failureDelegate,
12097                 timeout: (this.timeout*1000),
12098                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12099             });
12100             this.showLoading.defer(1, this);
12101         }
12102     },
12103
12104     /**
12105      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12106      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12107      */
12108     refresh : function(callback){
12109         if(this.defaultUrl == null){
12110             return;
12111         }
12112         this.update(this.defaultUrl, null, callback, true);
12113     },
12114
12115     /**
12116      * Set this element to auto refresh.
12117      * @param {Number} interval How often to update (in seconds).
12118      * @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)
12119      * @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}
12120      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12121      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12122      */
12123     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12124         if(refreshNow){
12125             this.update(url || this.defaultUrl, params, callback, true);
12126         }
12127         if(this.autoRefreshProcId){
12128             clearInterval(this.autoRefreshProcId);
12129         }
12130         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12131     },
12132
12133     /**
12134      * Stop auto refresh on this element.
12135      */
12136      stopAutoRefresh : function(){
12137         if(this.autoRefreshProcId){
12138             clearInterval(this.autoRefreshProcId);
12139             delete this.autoRefreshProcId;
12140         }
12141     },
12142
12143     isAutoRefreshing : function(){
12144        return this.autoRefreshProcId ? true : false;
12145     },
12146     /**
12147      * Called to update the element to "Loading" state. Override to perform custom action.
12148      */
12149     showLoading : function(){
12150         if(this.showLoadIndicator){
12151             this.el.update(this.indicatorText);
12152         }
12153     },
12154
12155     /**
12156      * Adds unique parameter to query string if disableCaching = true
12157      * @private
12158      */
12159     prepareUrl : function(url){
12160         if(this.disableCaching){
12161             var append = "_dc=" + (new Date().getTime());
12162             if(url.indexOf("?") !== -1){
12163                 url += "&" + append;
12164             }else{
12165                 url += "?" + append;
12166             }
12167         }
12168         return url;
12169     },
12170
12171     /**
12172      * @private
12173      */
12174     processSuccess : function(response){
12175         this.transaction = null;
12176         if(response.argument.form && response.argument.reset){
12177             try{ // put in try/catch since some older FF releases had problems with this
12178                 response.argument.form.reset();
12179             }catch(e){}
12180         }
12181         if(this.loadScripts){
12182             this.renderer.render(this.el, response, this,
12183                 this.updateComplete.createDelegate(this, [response]));
12184         }else{
12185             this.renderer.render(this.el, response, this);
12186             this.updateComplete(response);
12187         }
12188     },
12189
12190     updateComplete : function(response){
12191         this.fireEvent("update", this.el, response);
12192         if(typeof response.argument.callback == "function"){
12193             response.argument.callback(this.el, true, response);
12194         }
12195     },
12196
12197     /**
12198      * @private
12199      */
12200     processFailure : function(response){
12201         this.transaction = null;
12202         this.fireEvent("failure", this.el, response);
12203         if(typeof response.argument.callback == "function"){
12204             response.argument.callback(this.el, false, response);
12205         }
12206     },
12207
12208     /**
12209      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12210      * @param {Object} renderer The object implementing the render() method
12211      */
12212     setRenderer : function(renderer){
12213         this.renderer = renderer;
12214     },
12215
12216     getRenderer : function(){
12217        return this.renderer;
12218     },
12219
12220     /**
12221      * Set the defaultUrl used for updates
12222      * @param {String/Function} defaultUrl The url or a function to call to get the url
12223      */
12224     setDefaultUrl : function(defaultUrl){
12225         this.defaultUrl = defaultUrl;
12226     },
12227
12228     /**
12229      * Aborts the executing transaction
12230      */
12231     abort : function(){
12232         if(this.transaction){
12233             Roo.Ajax.abort(this.transaction);
12234         }
12235     },
12236
12237     /**
12238      * Returns true if an update is in progress
12239      * @return {Boolean}
12240      */
12241     isUpdating : function(){
12242         if(this.transaction){
12243             return Roo.Ajax.isLoading(this.transaction);
12244         }
12245         return false;
12246     }
12247 });
12248
12249 /**
12250  * @class Roo.UpdateManager.defaults
12251  * @static (not really - but it helps the doc tool)
12252  * The defaults collection enables customizing the default properties of UpdateManager
12253  */
12254    Roo.UpdateManager.defaults = {
12255        /**
12256          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12257          * @type Number
12258          */
12259          timeout : 30,
12260
12261          /**
12262          * True to process scripts by default (Defaults to false).
12263          * @type Boolean
12264          */
12265         loadScripts : false,
12266
12267         /**
12268         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12269         * @type String
12270         */
12271         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12272         /**
12273          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12274          * @type Boolean
12275          */
12276         disableCaching : false,
12277         /**
12278          * Whether to show indicatorText when loading (Defaults to true).
12279          * @type Boolean
12280          */
12281         showLoadIndicator : true,
12282         /**
12283          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12284          * @type String
12285          */
12286         indicatorText : '<div class="loading-indicator">Loading...</div>'
12287    };
12288
12289 /**
12290  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12291  *Usage:
12292  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12293  * @param {String/HTMLElement/Roo.Element} el The element to update
12294  * @param {String} url The url
12295  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12296  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12297  * @static
12298  * @deprecated
12299  * @member Roo.UpdateManager
12300  */
12301 Roo.UpdateManager.updateElement = function(el, url, params, options){
12302     var um = Roo.get(el, true).getUpdateManager();
12303     Roo.apply(um, options);
12304     um.update(url, params, options ? options.callback : null);
12305 };
12306 // alias for backwards compat
12307 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12308 /**
12309  * @class Roo.UpdateManager.BasicRenderer
12310  * Default Content renderer. Updates the elements innerHTML with the responseText.
12311  */
12312 Roo.UpdateManager.BasicRenderer = function(){};
12313
12314 Roo.UpdateManager.BasicRenderer.prototype = {
12315     /**
12316      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12317      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12318      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12319      * @param {Roo.Element} el The element being rendered
12320      * @param {Object} response The YUI Connect response object
12321      * @param {UpdateManager} updateManager The calling update manager
12322      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12323      */
12324      render : function(el, response, updateManager, callback){
12325         el.update(response.responseText, updateManager.loadScripts, callback);
12326     }
12327 };
12328 /*
12329  * Based on:
12330  * Roo JS
12331  * (c)) Alan Knowles
12332  * Licence : LGPL
12333  */
12334
12335
12336 /**
12337  * @class Roo.DomTemplate
12338  * @extends Roo.Template
12339  * An effort at a dom based template engine..
12340  *
12341  * Similar to XTemplate, except it uses dom parsing to create the template..
12342  *
12343  * Supported features:
12344  *
12345  *  Tags:
12346
12347 <pre><code>
12348       {a_variable} - output encoded.
12349       {a_variable.format:("Y-m-d")} - call a method on the variable
12350       {a_variable:raw} - unencoded output
12351       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12352       {a_variable:this.method_on_template(...)} - call a method on the template object.
12353  
12354 </code></pre>
12355  *  The tpl tag:
12356 <pre><code>
12357         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12358         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12359         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12360         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12361   
12362 </code></pre>
12363  *      
12364  */
12365 Roo.DomTemplate = function()
12366 {
12367      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12368      if (this.html) {
12369         this.compile();
12370      }
12371 };
12372
12373
12374 Roo.extend(Roo.DomTemplate, Roo.Template, {
12375     /**
12376      * id counter for sub templates.
12377      */
12378     id : 0,
12379     /**
12380      * flag to indicate if dom parser is inside a pre,
12381      * it will strip whitespace if not.
12382      */
12383     inPre : false,
12384     
12385     /**
12386      * The various sub templates
12387      */
12388     tpls : false,
12389     
12390     
12391     
12392     /**
12393      *
12394      * basic tag replacing syntax
12395      * WORD:WORD()
12396      *
12397      * // you can fake an object call by doing this
12398      *  x.t:(test,tesT) 
12399      * 
12400      */
12401     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12402     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12403     
12404     iterChild : function (node, method) {
12405         
12406         var oldPre = this.inPre;
12407         if (node.tagName == 'PRE') {
12408             this.inPre = true;
12409         }
12410         for( var i = 0; i < node.childNodes.length; i++) {
12411             method.call(this, node.childNodes[i]);
12412         }
12413         this.inPre = oldPre;
12414     },
12415     
12416     
12417     
12418     /**
12419      * compile the template
12420      *
12421      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12422      *
12423      */
12424     compile: function()
12425     {
12426         var s = this.html;
12427         
12428         // covert the html into DOM...
12429         var doc = false;
12430         var div =false;
12431         try {
12432             doc = document.implementation.createHTMLDocument("");
12433             doc.documentElement.innerHTML =   this.html  ;
12434             div = doc.documentElement;
12435         } catch (e) {
12436             // old IE... - nasty -- it causes all sorts of issues.. with
12437             // images getting pulled from server..
12438             div = document.createElement('div');
12439             div.innerHTML = this.html;
12440         }
12441         //doc.documentElement.innerHTML = htmlBody
12442          
12443         
12444         
12445         this.tpls = [];
12446         var _t = this;
12447         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12448         
12449         var tpls = this.tpls;
12450         
12451         // create a top level template from the snippet..
12452         
12453         //Roo.log(div.innerHTML);
12454         
12455         var tpl = {
12456             uid : 'master',
12457             id : this.id++,
12458             attr : false,
12459             value : false,
12460             body : div.innerHTML,
12461             
12462             forCall : false,
12463             execCall : false,
12464             dom : div,
12465             isTop : true
12466             
12467         };
12468         tpls.unshift(tpl);
12469         
12470         
12471         // compile them...
12472         this.tpls = [];
12473         Roo.each(tpls, function(tp){
12474             this.compileTpl(tp);
12475             this.tpls[tp.id] = tp;
12476         }, this);
12477         
12478         this.master = tpls[0];
12479         return this;
12480         
12481         
12482     },
12483     
12484     compileNode : function(node, istop) {
12485         // test for
12486         //Roo.log(node);
12487         
12488         
12489         // skip anything not a tag..
12490         if (node.nodeType != 1) {
12491             if (node.nodeType == 3 && !this.inPre) {
12492                 // reduce white space..
12493                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12494                 
12495             }
12496             return;
12497         }
12498         
12499         var tpl = {
12500             uid : false,
12501             id : false,
12502             attr : false,
12503             value : false,
12504             body : '',
12505             
12506             forCall : false,
12507             execCall : false,
12508             dom : false,
12509             isTop : istop
12510             
12511             
12512         };
12513         
12514         
12515         switch(true) {
12516             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12517             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12518             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12519             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12520             // no default..
12521         }
12522         
12523         
12524         if (!tpl.attr) {
12525             // just itterate children..
12526             this.iterChild(node,this.compileNode);
12527             return;
12528         }
12529         tpl.uid = this.id++;
12530         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12531         node.removeAttribute('roo-'+ tpl.attr);
12532         if (tpl.attr != 'name') {
12533             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12534             node.parentNode.replaceChild(placeholder,  node);
12535         } else {
12536             
12537             var placeholder =  document.createElement('span');
12538             placeholder.className = 'roo-tpl-' + tpl.value;
12539             node.parentNode.replaceChild(placeholder,  node);
12540         }
12541         
12542         // parent now sees '{domtplXXXX}
12543         this.iterChild(node,this.compileNode);
12544         
12545         // we should now have node body...
12546         var div = document.createElement('div');
12547         div.appendChild(node);
12548         tpl.dom = node;
12549         // this has the unfortunate side effect of converting tagged attributes
12550         // eg. href="{...}" into %7C...%7D
12551         // this has been fixed by searching for those combo's although it's a bit hacky..
12552         
12553         
12554         tpl.body = div.innerHTML;
12555         
12556         
12557          
12558         tpl.id = tpl.uid;
12559         switch(tpl.attr) {
12560             case 'for' :
12561                 switch (tpl.value) {
12562                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12563                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12564                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12565                 }
12566                 break;
12567             
12568             case 'exec':
12569                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12570                 break;
12571             
12572             case 'if':     
12573                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12574                 break;
12575             
12576             case 'name':
12577                 tpl.id  = tpl.value; // replace non characters???
12578                 break;
12579             
12580         }
12581         
12582         
12583         this.tpls.push(tpl);
12584         
12585         
12586         
12587     },
12588     
12589     
12590     
12591     
12592     /**
12593      * Compile a segment of the template into a 'sub-template'
12594      *
12595      * 
12596      * 
12597      *
12598      */
12599     compileTpl : function(tpl)
12600     {
12601         var fm = Roo.util.Format;
12602         var useF = this.disableFormats !== true;
12603         
12604         var sep = Roo.isGecko ? "+\n" : ",\n";
12605         
12606         var undef = function(str) {
12607             Roo.debug && Roo.log("Property not found :"  + str);
12608             return '';
12609         };
12610           
12611         //Roo.log(tpl.body);
12612         
12613         
12614         
12615         var fn = function(m, lbrace, name, format, args)
12616         {
12617             //Roo.log("ARGS");
12618             //Roo.log(arguments);
12619             args = args ? args.replace(/\\'/g,"'") : args;
12620             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12621             if (typeof(format) == 'undefined') {
12622                 format =  'htmlEncode'; 
12623             }
12624             if (format == 'raw' ) {
12625                 format = false;
12626             }
12627             
12628             if(name.substr(0, 6) == 'domtpl'){
12629                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12630             }
12631             
12632             // build an array of options to determine if value is undefined..
12633             
12634             // basically get 'xxxx.yyyy' then do
12635             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12636             //    (function () { Roo.log("Property not found"); return ''; })() :
12637             //    ......
12638             
12639             var udef_ar = [];
12640             var lookfor = '';
12641             Roo.each(name.split('.'), function(st) {
12642                 lookfor += (lookfor.length ? '.': '') + st;
12643                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12644             });
12645             
12646             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12647             
12648             
12649             if(format && useF){
12650                 
12651                 args = args ? ',' + args : "";
12652                  
12653                 if(format.substr(0, 5) != "this."){
12654                     format = "fm." + format + '(';
12655                 }else{
12656                     format = 'this.call("'+ format.substr(5) + '", ';
12657                     args = ", values";
12658                 }
12659                 
12660                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12661             }
12662              
12663             if (args && args.length) {
12664                 // called with xxyx.yuu:(test,test)
12665                 // change to ()
12666                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12667             }
12668             // raw.. - :raw modifier..
12669             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12670             
12671         };
12672         var body;
12673         // branched to use + in gecko and [].join() in others
12674         if(Roo.isGecko){
12675             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12676                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12677                     "';};};";
12678         }else{
12679             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12680             body.push(tpl.body.replace(/(\r\n|\n)/g,
12681                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12682             body.push("'].join('');};};");
12683             body = body.join('');
12684         }
12685         
12686         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12687        
12688         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12689         eval(body);
12690         
12691         return this;
12692     },
12693      
12694     /**
12695      * same as applyTemplate, except it's done to one of the subTemplates
12696      * when using named templates, you can do:
12697      *
12698      * var str = pl.applySubTemplate('your-name', values);
12699      *
12700      * 
12701      * @param {Number} id of the template
12702      * @param {Object} values to apply to template
12703      * @param {Object} parent (normaly the instance of this object)
12704      */
12705     applySubTemplate : function(id, values, parent)
12706     {
12707         
12708         
12709         var t = this.tpls[id];
12710         
12711         
12712         try { 
12713             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12714                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12715                 return '';
12716             }
12717         } catch(e) {
12718             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12719             Roo.log(values);
12720           
12721             return '';
12722         }
12723         try { 
12724             
12725             if(t.execCall && t.execCall.call(this, values, parent)){
12726                 return '';
12727             }
12728         } catch(e) {
12729             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12730             Roo.log(values);
12731             return '';
12732         }
12733         
12734         try {
12735             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12736             parent = t.target ? values : parent;
12737             if(t.forCall && vs instanceof Array){
12738                 var buf = [];
12739                 for(var i = 0, len = vs.length; i < len; i++){
12740                     try {
12741                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12742                     } catch (e) {
12743                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12744                         Roo.log(e.body);
12745                         //Roo.log(t.compiled);
12746                         Roo.log(vs[i]);
12747                     }   
12748                 }
12749                 return buf.join('');
12750             }
12751         } catch (e) {
12752             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12753             Roo.log(values);
12754             return '';
12755         }
12756         try {
12757             return t.compiled.call(this, vs, parent);
12758         } catch (e) {
12759             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12760             Roo.log(e.body);
12761             //Roo.log(t.compiled);
12762             Roo.log(values);
12763             return '';
12764         }
12765     },
12766
12767    
12768
12769     applyTemplate : function(values){
12770         return this.master.compiled.call(this, values, {});
12771         //var s = this.subs;
12772     },
12773
12774     apply : function(){
12775         return this.applyTemplate.apply(this, arguments);
12776     }
12777
12778  });
12779
12780 Roo.DomTemplate.from = function(el){
12781     el = Roo.getDom(el);
12782     return new Roo.Domtemplate(el.value || el.innerHTML);
12783 };/*
12784  * Based on:
12785  * Ext JS Library 1.1.1
12786  * Copyright(c) 2006-2007, Ext JS, LLC.
12787  *
12788  * Originally Released Under LGPL - original licence link has changed is not relivant.
12789  *
12790  * Fork - LGPL
12791  * <script type="text/javascript">
12792  */
12793
12794 /**
12795  * @class Roo.util.DelayedTask
12796  * Provides a convenient method of performing setTimeout where a new
12797  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12798  * You can use this class to buffer
12799  * the keypress events for a certain number of milliseconds, and perform only if they stop
12800  * for that amount of time.
12801  * @constructor The parameters to this constructor serve as defaults and are not required.
12802  * @param {Function} fn (optional) The default function to timeout
12803  * @param {Object} scope (optional) The default scope of that timeout
12804  * @param {Array} args (optional) The default Array of arguments
12805  */
12806 Roo.util.DelayedTask = function(fn, scope, args){
12807     var id = null, d, t;
12808
12809     var call = function(){
12810         var now = new Date().getTime();
12811         if(now - t >= d){
12812             clearInterval(id);
12813             id = null;
12814             fn.apply(scope, args || []);
12815         }
12816     };
12817     /**
12818      * Cancels any pending timeout and queues a new one
12819      * @param {Number} delay The milliseconds to delay
12820      * @param {Function} newFn (optional) Overrides function passed to constructor
12821      * @param {Object} newScope (optional) Overrides scope passed to constructor
12822      * @param {Array} newArgs (optional) Overrides args passed to constructor
12823      */
12824     this.delay = function(delay, newFn, newScope, newArgs){
12825         if(id && delay != d){
12826             this.cancel();
12827         }
12828         d = delay;
12829         t = new Date().getTime();
12830         fn = newFn || fn;
12831         scope = newScope || scope;
12832         args = newArgs || args;
12833         if(!id){
12834             id = setInterval(call, d);
12835         }
12836     };
12837
12838     /**
12839      * Cancel the last queued timeout
12840      */
12841     this.cancel = function(){
12842         if(id){
12843             clearInterval(id);
12844             id = null;
12845         }
12846     };
12847 };/*
12848  * Based on:
12849  * Ext JS Library 1.1.1
12850  * Copyright(c) 2006-2007, Ext JS, LLC.
12851  *
12852  * Originally Released Under LGPL - original licence link has changed is not relivant.
12853  *
12854  * Fork - LGPL
12855  * <script type="text/javascript">
12856  */
12857  
12858  
12859 Roo.util.TaskRunner = function(interval){
12860     interval = interval || 10;
12861     var tasks = [], removeQueue = [];
12862     var id = 0;
12863     var running = false;
12864
12865     var stopThread = function(){
12866         running = false;
12867         clearInterval(id);
12868         id = 0;
12869     };
12870
12871     var startThread = function(){
12872         if(!running){
12873             running = true;
12874             id = setInterval(runTasks, interval);
12875         }
12876     };
12877
12878     var removeTask = function(task){
12879         removeQueue.push(task);
12880         if(task.onStop){
12881             task.onStop();
12882         }
12883     };
12884
12885     var runTasks = function(){
12886         if(removeQueue.length > 0){
12887             for(var i = 0, len = removeQueue.length; i < len; i++){
12888                 tasks.remove(removeQueue[i]);
12889             }
12890             removeQueue = [];
12891             if(tasks.length < 1){
12892                 stopThread();
12893                 return;
12894             }
12895         }
12896         var now = new Date().getTime();
12897         for(var i = 0, len = tasks.length; i < len; ++i){
12898             var t = tasks[i];
12899             var itime = now - t.taskRunTime;
12900             if(t.interval <= itime){
12901                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12902                 t.taskRunTime = now;
12903                 if(rt === false || t.taskRunCount === t.repeat){
12904                     removeTask(t);
12905                     return;
12906                 }
12907             }
12908             if(t.duration && t.duration <= (now - t.taskStartTime)){
12909                 removeTask(t);
12910             }
12911         }
12912     };
12913
12914     /**
12915      * Queues a new task.
12916      * @param {Object} task
12917      */
12918     this.start = function(task){
12919         tasks.push(task);
12920         task.taskStartTime = new Date().getTime();
12921         task.taskRunTime = 0;
12922         task.taskRunCount = 0;
12923         startThread();
12924         return task;
12925     };
12926
12927     this.stop = function(task){
12928         removeTask(task);
12929         return task;
12930     };
12931
12932     this.stopAll = function(){
12933         stopThread();
12934         for(var i = 0, len = tasks.length; i < len; i++){
12935             if(tasks[i].onStop){
12936                 tasks[i].onStop();
12937             }
12938         }
12939         tasks = [];
12940         removeQueue = [];
12941     };
12942 };
12943
12944 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12945  * Based on:
12946  * Ext JS Library 1.1.1
12947  * Copyright(c) 2006-2007, Ext JS, LLC.
12948  *
12949  * Originally Released Under LGPL - original licence link has changed is not relivant.
12950  *
12951  * Fork - LGPL
12952  * <script type="text/javascript">
12953  */
12954
12955  
12956 /**
12957  * @class Roo.util.MixedCollection
12958  * @extends Roo.util.Observable
12959  * A Collection class that maintains both numeric indexes and keys and exposes events.
12960  * @constructor
12961  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12962  * collection (defaults to false)
12963  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12964  * and return the key value for that item.  This is used when available to look up the key on items that
12965  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12966  * equivalent to providing an implementation for the {@link #getKey} method.
12967  */
12968 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12969     this.items = [];
12970     this.map = {};
12971     this.keys = [];
12972     this.length = 0;
12973     this.addEvents({
12974         /**
12975          * @event clear
12976          * Fires when the collection is cleared.
12977          */
12978         "clear" : true,
12979         /**
12980          * @event add
12981          * Fires when an item is added to the collection.
12982          * @param {Number} index The index at which the item was added.
12983          * @param {Object} o The item added.
12984          * @param {String} key The key associated with the added item.
12985          */
12986         "add" : true,
12987         /**
12988          * @event replace
12989          * Fires when an item is replaced in the collection.
12990          * @param {String} key he key associated with the new added.
12991          * @param {Object} old The item being replaced.
12992          * @param {Object} new The new item.
12993          */
12994         "replace" : true,
12995         /**
12996          * @event remove
12997          * Fires when an item is removed from the collection.
12998          * @param {Object} o The item being removed.
12999          * @param {String} key (optional) The key associated with the removed item.
13000          */
13001         "remove" : true,
13002         "sort" : true
13003     });
13004     this.allowFunctions = allowFunctions === true;
13005     if(keyFn){
13006         this.getKey = keyFn;
13007     }
13008     Roo.util.MixedCollection.superclass.constructor.call(this);
13009 };
13010
13011 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13012     allowFunctions : false,
13013     
13014 /**
13015  * Adds an item to the collection.
13016  * @param {String} key The key to associate with the item
13017  * @param {Object} o The item to add.
13018  * @return {Object} The item added.
13019  */
13020     add : function(key, o){
13021         if(arguments.length == 1){
13022             o = arguments[0];
13023             key = this.getKey(o);
13024         }
13025         if(typeof key == "undefined" || key === null){
13026             this.length++;
13027             this.items.push(o);
13028             this.keys.push(null);
13029         }else{
13030             var old = this.map[key];
13031             if(old){
13032                 return this.replace(key, o);
13033             }
13034             this.length++;
13035             this.items.push(o);
13036             this.map[key] = o;
13037             this.keys.push(key);
13038         }
13039         this.fireEvent("add", this.length-1, o, key);
13040         return o;
13041     },
13042        
13043 /**
13044   * MixedCollection has a generic way to fetch keys if you implement getKey.
13045 <pre><code>
13046 // normal way
13047 var mc = new Roo.util.MixedCollection();
13048 mc.add(someEl.dom.id, someEl);
13049 mc.add(otherEl.dom.id, otherEl);
13050 //and so on
13051
13052 // using getKey
13053 var mc = new Roo.util.MixedCollection();
13054 mc.getKey = function(el){
13055    return el.dom.id;
13056 };
13057 mc.add(someEl);
13058 mc.add(otherEl);
13059
13060 // or via the constructor
13061 var mc = new Roo.util.MixedCollection(false, function(el){
13062    return el.dom.id;
13063 });
13064 mc.add(someEl);
13065 mc.add(otherEl);
13066 </code></pre>
13067  * @param o {Object} The item for which to find the key.
13068  * @return {Object} The key for the passed item.
13069  */
13070     getKey : function(o){
13071          return o.id; 
13072     },
13073    
13074 /**
13075  * Replaces an item in the collection.
13076  * @param {String} key The key associated with the item to replace, or the item to replace.
13077  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13078  * @return {Object}  The new item.
13079  */
13080     replace : function(key, o){
13081         if(arguments.length == 1){
13082             o = arguments[0];
13083             key = this.getKey(o);
13084         }
13085         var old = this.item(key);
13086         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13087              return this.add(key, o);
13088         }
13089         var index = this.indexOfKey(key);
13090         this.items[index] = o;
13091         this.map[key] = o;
13092         this.fireEvent("replace", key, old, o);
13093         return o;
13094     },
13095    
13096 /**
13097  * Adds all elements of an Array or an Object to the collection.
13098  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13099  * an Array of values, each of which are added to the collection.
13100  */
13101     addAll : function(objs){
13102         if(arguments.length > 1 || objs instanceof Array){
13103             var args = arguments.length > 1 ? arguments : objs;
13104             for(var i = 0, len = args.length; i < len; i++){
13105                 this.add(args[i]);
13106             }
13107         }else{
13108             for(var key in objs){
13109                 if(this.allowFunctions || typeof objs[key] != "function"){
13110                     this.add(key, objs[key]);
13111                 }
13112             }
13113         }
13114     },
13115    
13116 /**
13117  * Executes the specified function once for every item in the collection, passing each
13118  * item as the first and only parameter. returning false from the function will stop the iteration.
13119  * @param {Function} fn The function to execute for each item.
13120  * @param {Object} scope (optional) The scope in which to execute the function.
13121  */
13122     each : function(fn, scope){
13123         var items = [].concat(this.items); // each safe for removal
13124         for(var i = 0, len = items.length; i < len; i++){
13125             if(fn.call(scope || items[i], items[i], i, len) === false){
13126                 break;
13127             }
13128         }
13129     },
13130    
13131 /**
13132  * Executes the specified function once for every key in the collection, passing each
13133  * key, and its associated item as the first two parameters.
13134  * @param {Function} fn The function to execute for each item.
13135  * @param {Object} scope (optional) The scope in which to execute the function.
13136  */
13137     eachKey : function(fn, scope){
13138         for(var i = 0, len = this.keys.length; i < len; i++){
13139             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13140         }
13141     },
13142    
13143 /**
13144  * Returns the first item in the collection which elicits a true return value from the
13145  * passed selection function.
13146  * @param {Function} fn The selection function to execute for each item.
13147  * @param {Object} scope (optional) The scope in which to execute the function.
13148  * @return {Object} The first item in the collection which returned true from the selection function.
13149  */
13150     find : function(fn, scope){
13151         for(var i = 0, len = this.items.length; i < len; i++){
13152             if(fn.call(scope || window, this.items[i], this.keys[i])){
13153                 return this.items[i];
13154             }
13155         }
13156         return null;
13157     },
13158    
13159 /**
13160  * Inserts an item at the specified index in the collection.
13161  * @param {Number} index The index to insert the item at.
13162  * @param {String} key The key to associate with the new item, or the item itself.
13163  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13164  * @return {Object} The item inserted.
13165  */
13166     insert : function(index, key, o){
13167         if(arguments.length == 2){
13168             o = arguments[1];
13169             key = this.getKey(o);
13170         }
13171         if(index >= this.length){
13172             return this.add(key, o);
13173         }
13174         this.length++;
13175         this.items.splice(index, 0, o);
13176         if(typeof key != "undefined" && key != null){
13177             this.map[key] = o;
13178         }
13179         this.keys.splice(index, 0, key);
13180         this.fireEvent("add", index, o, key);
13181         return o;
13182     },
13183    
13184 /**
13185  * Removed an item from the collection.
13186  * @param {Object} o The item to remove.
13187  * @return {Object} The item removed.
13188  */
13189     remove : function(o){
13190         return this.removeAt(this.indexOf(o));
13191     },
13192    
13193 /**
13194  * Remove an item from a specified index in the collection.
13195  * @param {Number} index The index within the collection of the item to remove.
13196  */
13197     removeAt : function(index){
13198         if(index < this.length && index >= 0){
13199             this.length--;
13200             var o = this.items[index];
13201             this.items.splice(index, 1);
13202             var key = this.keys[index];
13203             if(typeof key != "undefined"){
13204                 delete this.map[key];
13205             }
13206             this.keys.splice(index, 1);
13207             this.fireEvent("remove", o, key);
13208         }
13209     },
13210    
13211 /**
13212  * Removed an item associated with the passed key fom the collection.
13213  * @param {String} key The key of the item to remove.
13214  */
13215     removeKey : function(key){
13216         return this.removeAt(this.indexOfKey(key));
13217     },
13218    
13219 /**
13220  * Returns the number of items in the collection.
13221  * @return {Number} the number of items in the collection.
13222  */
13223     getCount : function(){
13224         return this.length; 
13225     },
13226    
13227 /**
13228  * Returns index within the collection of the passed Object.
13229  * @param {Object} o The item to find the index of.
13230  * @return {Number} index of the item.
13231  */
13232     indexOf : function(o){
13233         if(!this.items.indexOf){
13234             for(var i = 0, len = this.items.length; i < len; i++){
13235                 if(this.items[i] == o) {
13236                     return i;
13237                 }
13238             }
13239             return -1;
13240         }else{
13241             return this.items.indexOf(o);
13242         }
13243     },
13244    
13245 /**
13246  * Returns index within the collection of the passed key.
13247  * @param {String} key The key to find the index of.
13248  * @return {Number} index of the key.
13249  */
13250     indexOfKey : function(key){
13251         if(!this.keys.indexOf){
13252             for(var i = 0, len = this.keys.length; i < len; i++){
13253                 if(this.keys[i] == key) {
13254                     return i;
13255                 }
13256             }
13257             return -1;
13258         }else{
13259             return this.keys.indexOf(key);
13260         }
13261     },
13262    
13263 /**
13264  * Returns the item associated with the passed key OR index. Key has priority over index.
13265  * @param {String/Number} key The key or index of the item.
13266  * @return {Object} The item associated with the passed key.
13267  */
13268     item : function(key){
13269         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13270         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13271     },
13272     
13273 /**
13274  * Returns the item at the specified index.
13275  * @param {Number} index The index of the item.
13276  * @return {Object}
13277  */
13278     itemAt : function(index){
13279         return this.items[index];
13280     },
13281     
13282 /**
13283  * Returns the item associated with the passed key.
13284  * @param {String/Number} key The key of the item.
13285  * @return {Object} The item associated with the passed key.
13286  */
13287     key : function(key){
13288         return this.map[key];
13289     },
13290    
13291 /**
13292  * Returns true if the collection contains the passed Object as an item.
13293  * @param {Object} o  The Object to look for in the collection.
13294  * @return {Boolean} True if the collection contains the Object as an item.
13295  */
13296     contains : function(o){
13297         return this.indexOf(o) != -1;
13298     },
13299    
13300 /**
13301  * Returns true if the collection contains the passed Object as a key.
13302  * @param {String} key The key to look for in the collection.
13303  * @return {Boolean} True if the collection contains the Object as a key.
13304  */
13305     containsKey : function(key){
13306         return typeof this.map[key] != "undefined";
13307     },
13308    
13309 /**
13310  * Removes all items from the collection.
13311  */
13312     clear : function(){
13313         this.length = 0;
13314         this.items = [];
13315         this.keys = [];
13316         this.map = {};
13317         this.fireEvent("clear");
13318     },
13319    
13320 /**
13321  * Returns the first item in the collection.
13322  * @return {Object} the first item in the collection..
13323  */
13324     first : function(){
13325         return this.items[0]; 
13326     },
13327    
13328 /**
13329  * Returns the last item in the collection.
13330  * @return {Object} the last item in the collection..
13331  */
13332     last : function(){
13333         return this.items[this.length-1];   
13334     },
13335     
13336     _sort : function(property, dir, fn){
13337         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13338         fn = fn || function(a, b){
13339             return a-b;
13340         };
13341         var c = [], k = this.keys, items = this.items;
13342         for(var i = 0, len = items.length; i < len; i++){
13343             c[c.length] = {key: k[i], value: items[i], index: i};
13344         }
13345         c.sort(function(a, b){
13346             var v = fn(a[property], b[property]) * dsc;
13347             if(v == 0){
13348                 v = (a.index < b.index ? -1 : 1);
13349             }
13350             return v;
13351         });
13352         for(var i = 0, len = c.length; i < len; i++){
13353             items[i] = c[i].value;
13354             k[i] = c[i].key;
13355         }
13356         this.fireEvent("sort", this);
13357     },
13358     
13359     /**
13360      * Sorts this collection with the passed comparison function
13361      * @param {String} direction (optional) "ASC" or "DESC"
13362      * @param {Function} fn (optional) comparison function
13363      */
13364     sort : function(dir, fn){
13365         this._sort("value", dir, fn);
13366     },
13367     
13368     /**
13369      * Sorts this collection by keys
13370      * @param {String} direction (optional) "ASC" or "DESC"
13371      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13372      */
13373     keySort : function(dir, fn){
13374         this._sort("key", dir, fn || function(a, b){
13375             return String(a).toUpperCase()-String(b).toUpperCase();
13376         });
13377     },
13378     
13379     /**
13380      * Returns a range of items in this collection
13381      * @param {Number} startIndex (optional) defaults to 0
13382      * @param {Number} endIndex (optional) default to the last item
13383      * @return {Array} An array of items
13384      */
13385     getRange : function(start, end){
13386         var items = this.items;
13387         if(items.length < 1){
13388             return [];
13389         }
13390         start = start || 0;
13391         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13392         var r = [];
13393         if(start <= end){
13394             for(var i = start; i <= end; i++) {
13395                     r[r.length] = items[i];
13396             }
13397         }else{
13398             for(var i = start; i >= end; i--) {
13399                     r[r.length] = items[i];
13400             }
13401         }
13402         return r;
13403     },
13404         
13405     /**
13406      * Filter the <i>objects</i> in this collection by a specific property. 
13407      * Returns a new collection that has been filtered.
13408      * @param {String} property A property on your objects
13409      * @param {String/RegExp} value Either string that the property values 
13410      * should start with or a RegExp to test against the property
13411      * @return {MixedCollection} The new filtered collection
13412      */
13413     filter : function(property, value){
13414         if(!value.exec){ // not a regex
13415             value = String(value);
13416             if(value.length == 0){
13417                 return this.clone();
13418             }
13419             value = new RegExp("^" + Roo.escapeRe(value), "i");
13420         }
13421         return this.filterBy(function(o){
13422             return o && value.test(o[property]);
13423         });
13424         },
13425     
13426     /**
13427      * Filter by a function. * Returns a new collection that has been filtered.
13428      * The passed function will be called with each 
13429      * object in the collection. If the function returns true, the value is included 
13430      * otherwise it is filtered.
13431      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13432      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13433      * @return {MixedCollection} The new filtered collection
13434      */
13435     filterBy : function(fn, scope){
13436         var r = new Roo.util.MixedCollection();
13437         r.getKey = this.getKey;
13438         var k = this.keys, it = this.items;
13439         for(var i = 0, len = it.length; i < len; i++){
13440             if(fn.call(scope||this, it[i], k[i])){
13441                                 r.add(k[i], it[i]);
13442                         }
13443         }
13444         return r;
13445     },
13446     
13447     /**
13448      * Creates a duplicate of this collection
13449      * @return {MixedCollection}
13450      */
13451     clone : function(){
13452         var r = new Roo.util.MixedCollection();
13453         var k = this.keys, it = this.items;
13454         for(var i = 0, len = it.length; i < len; i++){
13455             r.add(k[i], it[i]);
13456         }
13457         r.getKey = this.getKey;
13458         return r;
13459     }
13460 });
13461 /**
13462  * Returns the item associated with the passed key or index.
13463  * @method
13464  * @param {String/Number} key The key or index of the item.
13465  * @return {Object} The item associated with the passed key.
13466  */
13467 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13468  * Based on:
13469  * Ext JS Library 1.1.1
13470  * Copyright(c) 2006-2007, Ext JS, LLC.
13471  *
13472  * Originally Released Under LGPL - original licence link has changed is not relivant.
13473  *
13474  * Fork - LGPL
13475  * <script type="text/javascript">
13476  */
13477 /**
13478  * @class Roo.util.JSON
13479  * Modified version of Douglas Crockford"s json.js that doesn"t
13480  * mess with the Object prototype 
13481  * http://www.json.org/js.html
13482  * @singleton
13483  */
13484 Roo.util.JSON = new (function(){
13485     var useHasOwn = {}.hasOwnProperty ? true : false;
13486     
13487     // crashes Safari in some instances
13488     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13489     
13490     var pad = function(n) {
13491         return n < 10 ? "0" + n : n;
13492     };
13493     
13494     var m = {
13495         "\b": '\\b',
13496         "\t": '\\t',
13497         "\n": '\\n',
13498         "\f": '\\f',
13499         "\r": '\\r',
13500         '"' : '\\"',
13501         "\\": '\\\\'
13502     };
13503
13504     var encodeString = function(s){
13505         if (/["\\\x00-\x1f]/.test(s)) {
13506             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13507                 var c = m[b];
13508                 if(c){
13509                     return c;
13510                 }
13511                 c = b.charCodeAt();
13512                 return "\\u00" +
13513                     Math.floor(c / 16).toString(16) +
13514                     (c % 16).toString(16);
13515             }) + '"';
13516         }
13517         return '"' + s + '"';
13518     };
13519     
13520     var encodeArray = function(o){
13521         var a = ["["], b, i, l = o.length, v;
13522             for (i = 0; i < l; i += 1) {
13523                 v = o[i];
13524                 switch (typeof v) {
13525                     case "undefined":
13526                     case "function":
13527                     case "unknown":
13528                         break;
13529                     default:
13530                         if (b) {
13531                             a.push(',');
13532                         }
13533                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13534                         b = true;
13535                 }
13536             }
13537             a.push("]");
13538             return a.join("");
13539     };
13540     
13541     var encodeDate = function(o){
13542         return '"' + o.getFullYear() + "-" +
13543                 pad(o.getMonth() + 1) + "-" +
13544                 pad(o.getDate()) + "T" +
13545                 pad(o.getHours()) + ":" +
13546                 pad(o.getMinutes()) + ":" +
13547                 pad(o.getSeconds()) + '"';
13548     };
13549     
13550     /**
13551      * Encodes an Object, Array or other value
13552      * @param {Mixed} o The variable to encode
13553      * @return {String} The JSON string
13554      */
13555     this.encode = function(o)
13556     {
13557         // should this be extended to fully wrap stringify..
13558         
13559         if(typeof o == "undefined" || o === null){
13560             return "null";
13561         }else if(o instanceof Array){
13562             return encodeArray(o);
13563         }else if(o instanceof Date){
13564             return encodeDate(o);
13565         }else if(typeof o == "string"){
13566             return encodeString(o);
13567         }else if(typeof o == "number"){
13568             return isFinite(o) ? String(o) : "null";
13569         }else if(typeof o == "boolean"){
13570             return String(o);
13571         }else {
13572             var a = ["{"], b, i, v;
13573             for (i in o) {
13574                 if(!useHasOwn || o.hasOwnProperty(i)) {
13575                     v = o[i];
13576                     switch (typeof v) {
13577                     case "undefined":
13578                     case "function":
13579                     case "unknown":
13580                         break;
13581                     default:
13582                         if(b){
13583                             a.push(',');
13584                         }
13585                         a.push(this.encode(i), ":",
13586                                 v === null ? "null" : this.encode(v));
13587                         b = true;
13588                     }
13589                 }
13590             }
13591             a.push("}");
13592             return a.join("");
13593         }
13594     };
13595     
13596     /**
13597      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13598      * @param {String} json The JSON string
13599      * @return {Object} The resulting object
13600      */
13601     this.decode = function(json){
13602         
13603         return  /** eval:var:json */ eval("(" + json + ')');
13604     };
13605 })();
13606 /** 
13607  * Shorthand for {@link Roo.util.JSON#encode}
13608  * @member Roo encode 
13609  * @method */
13610 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13611 /** 
13612  * Shorthand for {@link Roo.util.JSON#decode}
13613  * @member Roo decode 
13614  * @method */
13615 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13616 /*
13617  * Based on:
13618  * Ext JS Library 1.1.1
13619  * Copyright(c) 2006-2007, Ext JS, LLC.
13620  *
13621  * Originally Released Under LGPL - original licence link has changed is not relivant.
13622  *
13623  * Fork - LGPL
13624  * <script type="text/javascript">
13625  */
13626  
13627 /**
13628  * @class Roo.util.Format
13629  * Reusable data formatting functions
13630  * @singleton
13631  */
13632 Roo.util.Format = function(){
13633     var trimRe = /^\s+|\s+$/g;
13634     return {
13635         /**
13636          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13637          * @param {String} value The string to truncate
13638          * @param {Number} length The maximum length to allow before truncating
13639          * @return {String} The converted text
13640          */
13641         ellipsis : function(value, len){
13642             if(value && value.length > len){
13643                 return value.substr(0, len-3)+"...";
13644             }
13645             return value;
13646         },
13647
13648         /**
13649          * Checks a reference and converts it to empty string if it is undefined
13650          * @param {Mixed} value Reference to check
13651          * @return {Mixed} Empty string if converted, otherwise the original value
13652          */
13653         undef : function(value){
13654             return typeof value != "undefined" ? value : "";
13655         },
13656
13657         /**
13658          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13659          * @param {String} value The string to encode
13660          * @return {String} The encoded text
13661          */
13662         htmlEncode : function(value){
13663             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13664         },
13665
13666         /**
13667          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13668          * @param {String} value The string to decode
13669          * @return {String} The decoded text
13670          */
13671         htmlDecode : function(value){
13672             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13673         },
13674
13675         /**
13676          * Trims any whitespace from either side of a string
13677          * @param {String} value The text to trim
13678          * @return {String} The trimmed text
13679          */
13680         trim : function(value){
13681             return String(value).replace(trimRe, "");
13682         },
13683
13684         /**
13685          * Returns a substring from within an original string
13686          * @param {String} value The original text
13687          * @param {Number} start The start index of the substring
13688          * @param {Number} length The length of the substring
13689          * @return {String} The substring
13690          */
13691         substr : function(value, start, length){
13692             return String(value).substr(start, length);
13693         },
13694
13695         /**
13696          * Converts a string to all lower case letters
13697          * @param {String} value The text to convert
13698          * @return {String} The converted text
13699          */
13700         lowercase : function(value){
13701             return String(value).toLowerCase();
13702         },
13703
13704         /**
13705          * Converts a string to all upper case letters
13706          * @param {String} value The text to convert
13707          * @return {String} The converted text
13708          */
13709         uppercase : function(value){
13710             return String(value).toUpperCase();
13711         },
13712
13713         /**
13714          * Converts the first character only of a string to upper case
13715          * @param {String} value The text to convert
13716          * @return {String} The converted text
13717          */
13718         capitalize : function(value){
13719             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13720         },
13721
13722         // private
13723         call : function(value, fn){
13724             if(arguments.length > 2){
13725                 var args = Array.prototype.slice.call(arguments, 2);
13726                 args.unshift(value);
13727                  
13728                 return /** eval:var:value */  eval(fn).apply(window, args);
13729             }else{
13730                 /** eval:var:value */
13731                 return /** eval:var:value */ eval(fn).call(window, value);
13732             }
13733         },
13734
13735        
13736         /**
13737          * safer version of Math.toFixed..??/
13738          * @param {Number/String} value The numeric value to format
13739          * @param {Number/String} value Decimal places 
13740          * @return {String} The formatted currency string
13741          */
13742         toFixed : function(v, n)
13743         {
13744             // why not use to fixed - precision is buggered???
13745             if (!n) {
13746                 return Math.round(v-0);
13747             }
13748             var fact = Math.pow(10,n+1);
13749             v = (Math.round((v-0)*fact))/fact;
13750             var z = (''+fact).substring(2);
13751             if (v == Math.floor(v)) {
13752                 return Math.floor(v) + '.' + z;
13753             }
13754             
13755             // now just padd decimals..
13756             var ps = String(v).split('.');
13757             var fd = (ps[1] + z);
13758             var r = fd.substring(0,n); 
13759             var rm = fd.substring(n); 
13760             if (rm < 5) {
13761                 return ps[0] + '.' + r;
13762             }
13763             r*=1; // turn it into a number;
13764             r++;
13765             if (String(r).length != n) {
13766                 ps[0]*=1;
13767                 ps[0]++;
13768                 r = String(r).substring(1); // chop the end off.
13769             }
13770             
13771             return ps[0] + '.' + r;
13772              
13773         },
13774         
13775         /**
13776          * Format a number as US currency
13777          * @param {Number/String} value The numeric value to format
13778          * @return {String} The formatted currency string
13779          */
13780         usMoney : function(v){
13781             return '$' + Roo.util.Format.number(v);
13782         },
13783         
13784         /**
13785          * Format a number
13786          * eventually this should probably emulate php's number_format
13787          * @param {Number/String} value The numeric value to format
13788          * @param {Number} decimals number of decimal places
13789          * @param {String} delimiter for thousands (default comma)
13790          * @return {String} The formatted currency string
13791          */
13792         number : function(v, decimals, thousandsDelimiter)
13793         {
13794             // multiply and round.
13795             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13796             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13797             
13798             var mul = Math.pow(10, decimals);
13799             var zero = String(mul).substring(1);
13800             v = (Math.round((v-0)*mul))/mul;
13801             
13802             // if it's '0' number.. then
13803             
13804             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13805             v = String(v);
13806             var ps = v.split('.');
13807             var whole = ps[0];
13808             
13809             var r = /(\d+)(\d{3})/;
13810             // add comma's
13811             
13812             if(thousandsDelimiter.length != 0) {
13813                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13814             } 
13815             
13816             var sub = ps[1] ?
13817                     // has decimals..
13818                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13819                     // does not have decimals
13820                     (decimals ? ('.' + zero) : '');
13821             
13822             
13823             return whole + sub ;
13824         },
13825         
13826         /**
13827          * Parse a value into a formatted date using the specified format pattern.
13828          * @param {Mixed} value The value to format
13829          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13830          * @return {String} The formatted date string
13831          */
13832         date : function(v, format){
13833             if(!v){
13834                 return "";
13835             }
13836             if(!(v instanceof Date)){
13837                 v = new Date(Date.parse(v));
13838             }
13839             return v.dateFormat(format || Roo.util.Format.defaults.date);
13840         },
13841
13842         /**
13843          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13844          * @param {String} format Any valid date format string
13845          * @return {Function} The date formatting function
13846          */
13847         dateRenderer : function(format){
13848             return function(v){
13849                 return Roo.util.Format.date(v, format);  
13850             };
13851         },
13852
13853         // private
13854         stripTagsRE : /<\/?[^>]+>/gi,
13855         
13856         /**
13857          * Strips all HTML tags
13858          * @param {Mixed} value The text from which to strip tags
13859          * @return {String} The stripped text
13860          */
13861         stripTags : function(v){
13862             return !v ? v : String(v).replace(this.stripTagsRE, "");
13863         }
13864     };
13865 }();
13866 Roo.util.Format.defaults = {
13867     date : 'd/M/Y'
13868 };/*
13869  * Based on:
13870  * Ext JS Library 1.1.1
13871  * Copyright(c) 2006-2007, Ext JS, LLC.
13872  *
13873  * Originally Released Under LGPL - original licence link has changed is not relivant.
13874  *
13875  * Fork - LGPL
13876  * <script type="text/javascript">
13877  */
13878
13879
13880  
13881
13882 /**
13883  * @class Roo.MasterTemplate
13884  * @extends Roo.Template
13885  * Provides a template that can have child templates. The syntax is:
13886 <pre><code>
13887 var t = new Roo.MasterTemplate(
13888         '&lt;select name="{name}"&gt;',
13889                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13890         '&lt;/select&gt;'
13891 );
13892 t.add('options', {value: 'foo', text: 'bar'});
13893 // or you can add multiple child elements in one shot
13894 t.addAll('options', [
13895     {value: 'foo', text: 'bar'},
13896     {value: 'foo2', text: 'bar2'},
13897     {value: 'foo3', text: 'bar3'}
13898 ]);
13899 // then append, applying the master template values
13900 t.append('my-form', {name: 'my-select'});
13901 </code></pre>
13902 * A name attribute for the child template is not required if you have only one child
13903 * template or you want to refer to them by index.
13904  */
13905 Roo.MasterTemplate = function(){
13906     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13907     this.originalHtml = this.html;
13908     var st = {};
13909     var m, re = this.subTemplateRe;
13910     re.lastIndex = 0;
13911     var subIndex = 0;
13912     while(m = re.exec(this.html)){
13913         var name = m[1], content = m[2];
13914         st[subIndex] = {
13915             name: name,
13916             index: subIndex,
13917             buffer: [],
13918             tpl : new Roo.Template(content)
13919         };
13920         if(name){
13921             st[name] = st[subIndex];
13922         }
13923         st[subIndex].tpl.compile();
13924         st[subIndex].tpl.call = this.call.createDelegate(this);
13925         subIndex++;
13926     }
13927     this.subCount = subIndex;
13928     this.subs = st;
13929 };
13930 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13931     /**
13932     * The regular expression used to match sub templates
13933     * @type RegExp
13934     * @property
13935     */
13936     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13937
13938     /**
13939      * Applies the passed values to a child template.
13940      * @param {String/Number} name (optional) The name or index of the child template
13941      * @param {Array/Object} values The values to be applied to the template
13942      * @return {MasterTemplate} this
13943      */
13944      add : function(name, values){
13945         if(arguments.length == 1){
13946             values = arguments[0];
13947             name = 0;
13948         }
13949         var s = this.subs[name];
13950         s.buffer[s.buffer.length] = s.tpl.apply(values);
13951         return this;
13952     },
13953
13954     /**
13955      * Applies all the passed values to a child template.
13956      * @param {String/Number} name (optional) The name or index of the child template
13957      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13958      * @param {Boolean} reset (optional) True to reset the template first
13959      * @return {MasterTemplate} this
13960      */
13961     fill : function(name, values, reset){
13962         var a = arguments;
13963         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13964             values = a[0];
13965             name = 0;
13966             reset = a[1];
13967         }
13968         if(reset){
13969             this.reset();
13970         }
13971         for(var i = 0, len = values.length; i < len; i++){
13972             this.add(name, values[i]);
13973         }
13974         return this;
13975     },
13976
13977     /**
13978      * Resets the template for reuse
13979      * @return {MasterTemplate} this
13980      */
13981      reset : function(){
13982         var s = this.subs;
13983         for(var i = 0; i < this.subCount; i++){
13984             s[i].buffer = [];
13985         }
13986         return this;
13987     },
13988
13989     applyTemplate : function(values){
13990         var s = this.subs;
13991         var replaceIndex = -1;
13992         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13993             return s[++replaceIndex].buffer.join("");
13994         });
13995         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13996     },
13997
13998     apply : function(){
13999         return this.applyTemplate.apply(this, arguments);
14000     },
14001
14002     compile : function(){return this;}
14003 });
14004
14005 /**
14006  * Alias for fill().
14007  * @method
14008  */
14009 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14010  /**
14011  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14012  * var tpl = Roo.MasterTemplate.from('element-id');
14013  * @param {String/HTMLElement} el
14014  * @param {Object} config
14015  * @static
14016  */
14017 Roo.MasterTemplate.from = function(el, config){
14018     el = Roo.getDom(el);
14019     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14020 };/*
14021  * Based on:
14022  * Ext JS Library 1.1.1
14023  * Copyright(c) 2006-2007, Ext JS, LLC.
14024  *
14025  * Originally Released Under LGPL - original licence link has changed is not relivant.
14026  *
14027  * Fork - LGPL
14028  * <script type="text/javascript">
14029  */
14030
14031  
14032 /**
14033  * @class Roo.util.CSS
14034  * Utility class for manipulating CSS rules
14035  * @singleton
14036  */
14037 Roo.util.CSS = function(){
14038         var rules = null;
14039         var doc = document;
14040
14041     var camelRe = /(-[a-z])/gi;
14042     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14043
14044    return {
14045    /**
14046     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14047     * tag and appended to the HEAD of the document.
14048     * @param {String|Object} cssText The text containing the css rules
14049     * @param {String} id An id to add to the stylesheet for later removal
14050     * @return {StyleSheet}
14051     */
14052     createStyleSheet : function(cssText, id){
14053         var ss;
14054         var head = doc.getElementsByTagName("head")[0];
14055         var nrules = doc.createElement("style");
14056         nrules.setAttribute("type", "text/css");
14057         if(id){
14058             nrules.setAttribute("id", id);
14059         }
14060         if (typeof(cssText) != 'string') {
14061             // support object maps..
14062             // not sure if this a good idea.. 
14063             // perhaps it should be merged with the general css handling
14064             // and handle js style props.
14065             var cssTextNew = [];
14066             for(var n in cssText) {
14067                 var citems = [];
14068                 for(var k in cssText[n]) {
14069                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14070                 }
14071                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14072                 
14073             }
14074             cssText = cssTextNew.join("\n");
14075             
14076         }
14077        
14078        
14079        if(Roo.isIE){
14080            head.appendChild(nrules);
14081            ss = nrules.styleSheet;
14082            ss.cssText = cssText;
14083        }else{
14084            try{
14085                 nrules.appendChild(doc.createTextNode(cssText));
14086            }catch(e){
14087                nrules.cssText = cssText; 
14088            }
14089            head.appendChild(nrules);
14090            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14091        }
14092        this.cacheStyleSheet(ss);
14093        return ss;
14094    },
14095
14096    /**
14097     * Removes a style or link tag by id
14098     * @param {String} id The id of the tag
14099     */
14100    removeStyleSheet : function(id){
14101        var existing = doc.getElementById(id);
14102        if(existing){
14103            existing.parentNode.removeChild(existing);
14104        }
14105    },
14106
14107    /**
14108     * Dynamically swaps an existing stylesheet reference for a new one
14109     * @param {String} id The id of an existing link tag to remove
14110     * @param {String} url The href of the new stylesheet to include
14111     */
14112    swapStyleSheet : function(id, url){
14113        this.removeStyleSheet(id);
14114        var ss = doc.createElement("link");
14115        ss.setAttribute("rel", "stylesheet");
14116        ss.setAttribute("type", "text/css");
14117        ss.setAttribute("id", id);
14118        ss.setAttribute("href", url);
14119        doc.getElementsByTagName("head")[0].appendChild(ss);
14120    },
14121    
14122    /**
14123     * Refresh the rule cache if you have dynamically added stylesheets
14124     * @return {Object} An object (hash) of rules indexed by selector
14125     */
14126    refreshCache : function(){
14127        return this.getRules(true);
14128    },
14129
14130    // private
14131    cacheStyleSheet : function(stylesheet){
14132        if(!rules){
14133            rules = {};
14134        }
14135        try{// try catch for cross domain access issue
14136            var ssRules = stylesheet.cssRules || stylesheet.rules;
14137            for(var j = ssRules.length-1; j >= 0; --j){
14138                rules[ssRules[j].selectorText] = ssRules[j];
14139            }
14140        }catch(e){}
14141    },
14142    
14143    /**
14144     * Gets all css rules for the document
14145     * @param {Boolean} refreshCache true to refresh the internal cache
14146     * @return {Object} An object (hash) of rules indexed by selector
14147     */
14148    getRules : function(refreshCache){
14149                 if(rules == null || refreshCache){
14150                         rules = {};
14151                         var ds = doc.styleSheets;
14152                         for(var i =0, len = ds.length; i < len; i++){
14153                             try{
14154                         this.cacheStyleSheet(ds[i]);
14155                     }catch(e){} 
14156                 }
14157                 }
14158                 return rules;
14159         },
14160         
14161         /**
14162     * Gets an an individual CSS rule by selector(s)
14163     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14164     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14165     * @return {CSSRule} The CSS rule or null if one is not found
14166     */
14167    getRule : function(selector, refreshCache){
14168                 var rs = this.getRules(refreshCache);
14169                 if(!(selector instanceof Array)){
14170                     return rs[selector];
14171                 }
14172                 for(var i = 0; i < selector.length; i++){
14173                         if(rs[selector[i]]){
14174                                 return rs[selector[i]];
14175                         }
14176                 }
14177                 return null;
14178         },
14179         
14180         
14181         /**
14182     * Updates a rule property
14183     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14184     * @param {String} property The css property
14185     * @param {String} value The new value for the property
14186     * @return {Boolean} true If a rule was found and updated
14187     */
14188    updateRule : function(selector, property, value){
14189                 if(!(selector instanceof Array)){
14190                         var rule = this.getRule(selector);
14191                         if(rule){
14192                                 rule.style[property.replace(camelRe, camelFn)] = value;
14193                                 return true;
14194                         }
14195                 }else{
14196                         for(var i = 0; i < selector.length; i++){
14197                                 if(this.updateRule(selector[i], property, value)){
14198                                         return true;
14199                                 }
14200                         }
14201                 }
14202                 return false;
14203         }
14204    };   
14205 }();/*
14206  * Based on:
14207  * Ext JS Library 1.1.1
14208  * Copyright(c) 2006-2007, Ext JS, LLC.
14209  *
14210  * Originally Released Under LGPL - original licence link has changed is not relivant.
14211  *
14212  * Fork - LGPL
14213  * <script type="text/javascript">
14214  */
14215
14216  
14217
14218 /**
14219  * @class Roo.util.ClickRepeater
14220  * @extends Roo.util.Observable
14221  * 
14222  * A wrapper class which can be applied to any element. Fires a "click" event while the
14223  * mouse is pressed. The interval between firings may be specified in the config but
14224  * defaults to 10 milliseconds.
14225  * 
14226  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14227  * 
14228  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14229  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14230  * Similar to an autorepeat key delay.
14231  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14232  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14233  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14234  *           "interval" and "delay" are ignored. "immediate" is honored.
14235  * @cfg {Boolean} preventDefault True to prevent the default click event
14236  * @cfg {Boolean} stopDefault True to stop the default click event
14237  * 
14238  * @history
14239  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14240  *     2007-02-02 jvs Renamed to ClickRepeater
14241  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14242  *
14243  *  @constructor
14244  * @param {String/HTMLElement/Element} el The element to listen on
14245  * @param {Object} config
14246  **/
14247 Roo.util.ClickRepeater = function(el, config)
14248 {
14249     this.el = Roo.get(el);
14250     this.el.unselectable();
14251
14252     Roo.apply(this, config);
14253
14254     this.addEvents({
14255     /**
14256      * @event mousedown
14257      * Fires when the mouse button is depressed.
14258      * @param {Roo.util.ClickRepeater} this
14259      */
14260         "mousedown" : true,
14261     /**
14262      * @event click
14263      * Fires on a specified interval during the time the element is pressed.
14264      * @param {Roo.util.ClickRepeater} this
14265      */
14266         "click" : true,
14267     /**
14268      * @event mouseup
14269      * Fires when the mouse key is released.
14270      * @param {Roo.util.ClickRepeater} this
14271      */
14272         "mouseup" : true
14273     });
14274
14275     this.el.on("mousedown", this.handleMouseDown, this);
14276     if(this.preventDefault || this.stopDefault){
14277         this.el.on("click", function(e){
14278             if(this.preventDefault){
14279                 e.preventDefault();
14280             }
14281             if(this.stopDefault){
14282                 e.stopEvent();
14283             }
14284         }, this);
14285     }
14286
14287     // allow inline handler
14288     if(this.handler){
14289         this.on("click", this.handler,  this.scope || this);
14290     }
14291
14292     Roo.util.ClickRepeater.superclass.constructor.call(this);
14293 };
14294
14295 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14296     interval : 20,
14297     delay: 250,
14298     preventDefault : true,
14299     stopDefault : false,
14300     timer : 0,
14301
14302     // private
14303     handleMouseDown : function(){
14304         clearTimeout(this.timer);
14305         this.el.blur();
14306         if(this.pressClass){
14307             this.el.addClass(this.pressClass);
14308         }
14309         this.mousedownTime = new Date();
14310
14311         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14312         this.el.on("mouseout", this.handleMouseOut, this);
14313
14314         this.fireEvent("mousedown", this);
14315         this.fireEvent("click", this);
14316         
14317         this.timer = this.click.defer(this.delay || this.interval, this);
14318     },
14319
14320     // private
14321     click : function(){
14322         this.fireEvent("click", this);
14323         this.timer = this.click.defer(this.getInterval(), this);
14324     },
14325
14326     // private
14327     getInterval: function(){
14328         if(!this.accelerate){
14329             return this.interval;
14330         }
14331         var pressTime = this.mousedownTime.getElapsed();
14332         if(pressTime < 500){
14333             return 400;
14334         }else if(pressTime < 1700){
14335             return 320;
14336         }else if(pressTime < 2600){
14337             return 250;
14338         }else if(pressTime < 3500){
14339             return 180;
14340         }else if(pressTime < 4400){
14341             return 140;
14342         }else if(pressTime < 5300){
14343             return 80;
14344         }else if(pressTime < 6200){
14345             return 50;
14346         }else{
14347             return 10;
14348         }
14349     },
14350
14351     // private
14352     handleMouseOut : function(){
14353         clearTimeout(this.timer);
14354         if(this.pressClass){
14355             this.el.removeClass(this.pressClass);
14356         }
14357         this.el.on("mouseover", this.handleMouseReturn, this);
14358     },
14359
14360     // private
14361     handleMouseReturn : function(){
14362         this.el.un("mouseover", this.handleMouseReturn);
14363         if(this.pressClass){
14364             this.el.addClass(this.pressClass);
14365         }
14366         this.click();
14367     },
14368
14369     // private
14370     handleMouseUp : function(){
14371         clearTimeout(this.timer);
14372         this.el.un("mouseover", this.handleMouseReturn);
14373         this.el.un("mouseout", this.handleMouseOut);
14374         Roo.get(document).un("mouseup", this.handleMouseUp);
14375         this.el.removeClass(this.pressClass);
14376         this.fireEvent("mouseup", this);
14377     }
14378 });/*
14379  * Based on:
14380  * Ext JS Library 1.1.1
14381  * Copyright(c) 2006-2007, Ext JS, LLC.
14382  *
14383  * Originally Released Under LGPL - original licence link has changed is not relivant.
14384  *
14385  * Fork - LGPL
14386  * <script type="text/javascript">
14387  */
14388
14389  
14390 /**
14391  * @class Roo.KeyNav
14392  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14393  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14394  * way to implement custom navigation schemes for any UI component.</p>
14395  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14396  * pageUp, pageDown, del, home, end.  Usage:</p>
14397  <pre><code>
14398 var nav = new Roo.KeyNav("my-element", {
14399     "left" : function(e){
14400         this.moveLeft(e.ctrlKey);
14401     },
14402     "right" : function(e){
14403         this.moveRight(e.ctrlKey);
14404     },
14405     "enter" : function(e){
14406         this.save();
14407     },
14408     scope : this
14409 });
14410 </code></pre>
14411  * @constructor
14412  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14413  * @param {Object} config The config
14414  */
14415 Roo.KeyNav = function(el, config){
14416     this.el = Roo.get(el);
14417     Roo.apply(this, config);
14418     if(!this.disabled){
14419         this.disabled = true;
14420         this.enable();
14421     }
14422 };
14423
14424 Roo.KeyNav.prototype = {
14425     /**
14426      * @cfg {Boolean} disabled
14427      * True to disable this KeyNav instance (defaults to false)
14428      */
14429     disabled : false,
14430     /**
14431      * @cfg {String} defaultEventAction
14432      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14433      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14434      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14435      */
14436     defaultEventAction: "stopEvent",
14437     /**
14438      * @cfg {Boolean} forceKeyDown
14439      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14440      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14441      * handle keydown instead of keypress.
14442      */
14443     forceKeyDown : false,
14444
14445     // private
14446     prepareEvent : function(e){
14447         var k = e.getKey();
14448         var h = this.keyToHandler[k];
14449         //if(h && this[h]){
14450         //    e.stopPropagation();
14451         //}
14452         if(Roo.isSafari && h && k >= 37 && k <= 40){
14453             e.stopEvent();
14454         }
14455     },
14456
14457     // private
14458     relay : function(e){
14459         var k = e.getKey();
14460         var h = this.keyToHandler[k];
14461         if(h && this[h]){
14462             if(this.doRelay(e, this[h], h) !== true){
14463                 e[this.defaultEventAction]();
14464             }
14465         }
14466     },
14467
14468     // private
14469     doRelay : function(e, h, hname){
14470         return h.call(this.scope || this, e);
14471     },
14472
14473     // possible handlers
14474     enter : false,
14475     left : false,
14476     right : false,
14477     up : false,
14478     down : false,
14479     tab : false,
14480     esc : false,
14481     pageUp : false,
14482     pageDown : false,
14483     del : false,
14484     home : false,
14485     end : false,
14486
14487     // quick lookup hash
14488     keyToHandler : {
14489         37 : "left",
14490         39 : "right",
14491         38 : "up",
14492         40 : "down",
14493         33 : "pageUp",
14494         34 : "pageDown",
14495         46 : "del",
14496         36 : "home",
14497         35 : "end",
14498         13 : "enter",
14499         27 : "esc",
14500         9  : "tab"
14501     },
14502
14503         /**
14504          * Enable this KeyNav
14505          */
14506         enable: function(){
14507                 if(this.disabled){
14508             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14509             // the EventObject will normalize Safari automatically
14510             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14511                 this.el.on("keydown", this.relay,  this);
14512             }else{
14513                 this.el.on("keydown", this.prepareEvent,  this);
14514                 this.el.on("keypress", this.relay,  this);
14515             }
14516                     this.disabled = false;
14517                 }
14518         },
14519
14520         /**
14521          * Disable this KeyNav
14522          */
14523         disable: function(){
14524                 if(!this.disabled){
14525                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14526                 this.el.un("keydown", this.relay);
14527             }else{
14528                 this.el.un("keydown", this.prepareEvent);
14529                 this.el.un("keypress", this.relay);
14530             }
14531                     this.disabled = true;
14532                 }
14533         }
14534 };/*
14535  * Based on:
14536  * Ext JS Library 1.1.1
14537  * Copyright(c) 2006-2007, Ext JS, LLC.
14538  *
14539  * Originally Released Under LGPL - original licence link has changed is not relivant.
14540  *
14541  * Fork - LGPL
14542  * <script type="text/javascript">
14543  */
14544
14545  
14546 /**
14547  * @class Roo.KeyMap
14548  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14549  * The constructor accepts the same config object as defined by {@link #addBinding}.
14550  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14551  * combination it will call the function with this signature (if the match is a multi-key
14552  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14553  * A KeyMap can also handle a string representation of keys.<br />
14554  * Usage:
14555  <pre><code>
14556 // map one key by key code
14557 var map = new Roo.KeyMap("my-element", {
14558     key: 13, // or Roo.EventObject.ENTER
14559     fn: myHandler,
14560     scope: myObject
14561 });
14562
14563 // map multiple keys to one action by string
14564 var map = new Roo.KeyMap("my-element", {
14565     key: "a\r\n\t",
14566     fn: myHandler,
14567     scope: myObject
14568 });
14569
14570 // map multiple keys to multiple actions by strings and array of codes
14571 var map = new Roo.KeyMap("my-element", [
14572     {
14573         key: [10,13],
14574         fn: function(){ alert("Return was pressed"); }
14575     }, {
14576         key: "abc",
14577         fn: function(){ alert('a, b or c was pressed'); }
14578     }, {
14579         key: "\t",
14580         ctrl:true,
14581         shift:true,
14582         fn: function(){ alert('Control + shift + tab was pressed.'); }
14583     }
14584 ]);
14585 </code></pre>
14586  * <b>Note: A KeyMap starts enabled</b>
14587  * @constructor
14588  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14589  * @param {Object} config The config (see {@link #addBinding})
14590  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14591  */
14592 Roo.KeyMap = function(el, config, eventName){
14593     this.el  = Roo.get(el);
14594     this.eventName = eventName || "keydown";
14595     this.bindings = [];
14596     if(config){
14597         this.addBinding(config);
14598     }
14599     this.enable();
14600 };
14601
14602 Roo.KeyMap.prototype = {
14603     /**
14604      * True to stop the event from bubbling and prevent the default browser action if the
14605      * key was handled by the KeyMap (defaults to false)
14606      * @type Boolean
14607      */
14608     stopEvent : false,
14609
14610     /**
14611      * Add a new binding to this KeyMap. The following config object properties are supported:
14612      * <pre>
14613 Property    Type             Description
14614 ----------  ---------------  ----------------------------------------------------------------------
14615 key         String/Array     A single keycode or an array of keycodes to handle
14616 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14617 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14618 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14619 fn          Function         The function to call when KeyMap finds the expected key combination
14620 scope       Object           The scope of the callback function
14621 </pre>
14622      *
14623      * Usage:
14624      * <pre><code>
14625 // Create a KeyMap
14626 var map = new Roo.KeyMap(document, {
14627     key: Roo.EventObject.ENTER,
14628     fn: handleKey,
14629     scope: this
14630 });
14631
14632 //Add a new binding to the existing KeyMap later
14633 map.addBinding({
14634     key: 'abc',
14635     shift: true,
14636     fn: handleKey,
14637     scope: this
14638 });
14639 </code></pre>
14640      * @param {Object/Array} config A single KeyMap config or an array of configs
14641      */
14642         addBinding : function(config){
14643         if(config instanceof Array){
14644             for(var i = 0, len = config.length; i < len; i++){
14645                 this.addBinding(config[i]);
14646             }
14647             return;
14648         }
14649         var keyCode = config.key,
14650             shift = config.shift, 
14651             ctrl = config.ctrl, 
14652             alt = config.alt,
14653             fn = config.fn,
14654             scope = config.scope;
14655         if(typeof keyCode == "string"){
14656             var ks = [];
14657             var keyString = keyCode.toUpperCase();
14658             for(var j = 0, len = keyString.length; j < len; j++){
14659                 ks.push(keyString.charCodeAt(j));
14660             }
14661             keyCode = ks;
14662         }
14663         var keyArray = keyCode instanceof Array;
14664         var handler = function(e){
14665             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14666                 var k = e.getKey();
14667                 if(keyArray){
14668                     for(var i = 0, len = keyCode.length; i < len; i++){
14669                         if(keyCode[i] == k){
14670                           if(this.stopEvent){
14671                               e.stopEvent();
14672                           }
14673                           fn.call(scope || window, k, e);
14674                           return;
14675                         }
14676                     }
14677                 }else{
14678                     if(k == keyCode){
14679                         if(this.stopEvent){
14680                            e.stopEvent();
14681                         }
14682                         fn.call(scope || window, k, e);
14683                     }
14684                 }
14685             }
14686         };
14687         this.bindings.push(handler);  
14688         },
14689
14690     /**
14691      * Shorthand for adding a single key listener
14692      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14693      * following options:
14694      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14695      * @param {Function} fn The function to call
14696      * @param {Object} scope (optional) The scope of the function
14697      */
14698     on : function(key, fn, scope){
14699         var keyCode, shift, ctrl, alt;
14700         if(typeof key == "object" && !(key instanceof Array)){
14701             keyCode = key.key;
14702             shift = key.shift;
14703             ctrl = key.ctrl;
14704             alt = key.alt;
14705         }else{
14706             keyCode = key;
14707         }
14708         this.addBinding({
14709             key: keyCode,
14710             shift: shift,
14711             ctrl: ctrl,
14712             alt: alt,
14713             fn: fn,
14714             scope: scope
14715         })
14716     },
14717
14718     // private
14719     handleKeyDown : function(e){
14720             if(this.enabled){ //just in case
14721             var b = this.bindings;
14722             for(var i = 0, len = b.length; i < len; i++){
14723                 b[i].call(this, e);
14724             }
14725             }
14726         },
14727         
14728         /**
14729          * Returns true if this KeyMap is enabled
14730          * @return {Boolean} 
14731          */
14732         isEnabled : function(){
14733             return this.enabled;  
14734         },
14735         
14736         /**
14737          * Enables this KeyMap
14738          */
14739         enable: function(){
14740                 if(!this.enabled){
14741                     this.el.on(this.eventName, this.handleKeyDown, this);
14742                     this.enabled = true;
14743                 }
14744         },
14745
14746         /**
14747          * Disable this KeyMap
14748          */
14749         disable: function(){
14750                 if(this.enabled){
14751                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14752                     this.enabled = false;
14753                 }
14754         }
14755 };/*
14756  * Based on:
14757  * Ext JS Library 1.1.1
14758  * Copyright(c) 2006-2007, Ext JS, LLC.
14759  *
14760  * Originally Released Under LGPL - original licence link has changed is not relivant.
14761  *
14762  * Fork - LGPL
14763  * <script type="text/javascript">
14764  */
14765
14766  
14767 /**
14768  * @class Roo.util.TextMetrics
14769  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14770  * wide, in pixels, a given block of text will be.
14771  * @singleton
14772  */
14773 Roo.util.TextMetrics = function(){
14774     var shared;
14775     return {
14776         /**
14777          * Measures the size of the specified text
14778          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14779          * that can affect the size of the rendered text
14780          * @param {String} text The text to measure
14781          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14782          * in order to accurately measure the text height
14783          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14784          */
14785         measure : function(el, text, fixedWidth){
14786             if(!shared){
14787                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14788             }
14789             shared.bind(el);
14790             shared.setFixedWidth(fixedWidth || 'auto');
14791             return shared.getSize(text);
14792         },
14793
14794         /**
14795          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14796          * the overhead of multiple calls to initialize the style properties on each measurement.
14797          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14798          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14799          * in order to accurately measure the text height
14800          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14801          */
14802         createInstance : function(el, fixedWidth){
14803             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14804         }
14805     };
14806 }();
14807
14808  
14809
14810 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14811     var ml = new Roo.Element(document.createElement('div'));
14812     document.body.appendChild(ml.dom);
14813     ml.position('absolute');
14814     ml.setLeftTop(-1000, -1000);
14815     ml.hide();
14816
14817     if(fixedWidth){
14818         ml.setWidth(fixedWidth);
14819     }
14820      
14821     var instance = {
14822         /**
14823          * Returns the size of the specified text based on the internal element's style and width properties
14824          * @memberOf Roo.util.TextMetrics.Instance#
14825          * @param {String} text The text to measure
14826          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14827          */
14828         getSize : function(text){
14829             ml.update(text);
14830             var s = ml.getSize();
14831             ml.update('');
14832             return s;
14833         },
14834
14835         /**
14836          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14837          * that can affect the size of the rendered text
14838          * @memberOf Roo.util.TextMetrics.Instance#
14839          * @param {String/HTMLElement} el The element, dom node or id
14840          */
14841         bind : function(el){
14842             ml.setStyle(
14843                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14844             );
14845         },
14846
14847         /**
14848          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14849          * to set a fixed width in order to accurately measure the text height.
14850          * @memberOf Roo.util.TextMetrics.Instance#
14851          * @param {Number} width The width to set on the element
14852          */
14853         setFixedWidth : function(width){
14854             ml.setWidth(width);
14855         },
14856
14857         /**
14858          * Returns the measured width of the specified text
14859          * @memberOf Roo.util.TextMetrics.Instance#
14860          * @param {String} text The text to measure
14861          * @return {Number} width The width in pixels
14862          */
14863         getWidth : function(text){
14864             ml.dom.style.width = 'auto';
14865             return this.getSize(text).width;
14866         },
14867
14868         /**
14869          * Returns the measured height of the specified text.  For multiline text, be sure to call
14870          * {@link #setFixedWidth} if necessary.
14871          * @memberOf Roo.util.TextMetrics.Instance#
14872          * @param {String} text The text to measure
14873          * @return {Number} height The height in pixels
14874          */
14875         getHeight : function(text){
14876             return this.getSize(text).height;
14877         }
14878     };
14879
14880     instance.bind(bindTo);
14881
14882     return instance;
14883 };
14884
14885 // backwards compat
14886 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14887  * Based on:
14888  * Ext JS Library 1.1.1
14889  * Copyright(c) 2006-2007, Ext JS, LLC.
14890  *
14891  * Originally Released Under LGPL - original licence link has changed is not relivant.
14892  *
14893  * Fork - LGPL
14894  * <script type="text/javascript">
14895  */
14896
14897 /**
14898  * @class Roo.state.Provider
14899  * Abstract base class for state provider implementations. This class provides methods
14900  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14901  * Provider interface.
14902  */
14903 Roo.state.Provider = function(){
14904     /**
14905      * @event statechange
14906      * Fires when a state change occurs.
14907      * @param {Provider} this This state provider
14908      * @param {String} key The state key which was changed
14909      * @param {String} value The encoded value for the state
14910      */
14911     this.addEvents({
14912         "statechange": true
14913     });
14914     this.state = {};
14915     Roo.state.Provider.superclass.constructor.call(this);
14916 };
14917 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14918     /**
14919      * Returns the current value for a key
14920      * @param {String} name The key name
14921      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14922      * @return {Mixed} The state data
14923      */
14924     get : function(name, defaultValue){
14925         return typeof this.state[name] == "undefined" ?
14926             defaultValue : this.state[name];
14927     },
14928     
14929     /**
14930      * Clears a value from the state
14931      * @param {String} name The key name
14932      */
14933     clear : function(name){
14934         delete this.state[name];
14935         this.fireEvent("statechange", this, name, null);
14936     },
14937     
14938     /**
14939      * Sets the value for a key
14940      * @param {String} name The key name
14941      * @param {Mixed} value The value to set
14942      */
14943     set : function(name, value){
14944         this.state[name] = value;
14945         this.fireEvent("statechange", this, name, value);
14946     },
14947     
14948     /**
14949      * Decodes a string previously encoded with {@link #encodeValue}.
14950      * @param {String} value The value to decode
14951      * @return {Mixed} The decoded value
14952      */
14953     decodeValue : function(cookie){
14954         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14955         var matches = re.exec(unescape(cookie));
14956         if(!matches || !matches[1]) {
14957             return; // non state cookie
14958         }
14959         var type = matches[1];
14960         var v = matches[2];
14961         switch(type){
14962             case "n":
14963                 return parseFloat(v);
14964             case "d":
14965                 return new Date(Date.parse(v));
14966             case "b":
14967                 return (v == "1");
14968             case "a":
14969                 var all = [];
14970                 var values = v.split("^");
14971                 for(var i = 0, len = values.length; i < len; i++){
14972                     all.push(this.decodeValue(values[i]));
14973                 }
14974                 return all;
14975            case "o":
14976                 var all = {};
14977                 var values = v.split("^");
14978                 for(var i = 0, len = values.length; i < len; i++){
14979                     var kv = values[i].split("=");
14980                     all[kv[0]] = this.decodeValue(kv[1]);
14981                 }
14982                 return all;
14983            default:
14984                 return v;
14985         }
14986     },
14987     
14988     /**
14989      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14990      * @param {Mixed} value The value to encode
14991      * @return {String} The encoded value
14992      */
14993     encodeValue : function(v){
14994         var enc;
14995         if(typeof v == "number"){
14996             enc = "n:" + v;
14997         }else if(typeof v == "boolean"){
14998             enc = "b:" + (v ? "1" : "0");
14999         }else if(v instanceof Date){
15000             enc = "d:" + v.toGMTString();
15001         }else if(v instanceof Array){
15002             var flat = "";
15003             for(var i = 0, len = v.length; i < len; i++){
15004                 flat += this.encodeValue(v[i]);
15005                 if(i != len-1) {
15006                     flat += "^";
15007                 }
15008             }
15009             enc = "a:" + flat;
15010         }else if(typeof v == "object"){
15011             var flat = "";
15012             for(var key in v){
15013                 if(typeof v[key] != "function"){
15014                     flat += key + "=" + this.encodeValue(v[key]) + "^";
15015                 }
15016             }
15017             enc = "o:" + flat.substring(0, flat.length-1);
15018         }else{
15019             enc = "s:" + v;
15020         }
15021         return escape(enc);        
15022     }
15023 });
15024
15025 /*
15026  * Based on:
15027  * Ext JS Library 1.1.1
15028  * Copyright(c) 2006-2007, Ext JS, LLC.
15029  *
15030  * Originally Released Under LGPL - original licence link has changed is not relivant.
15031  *
15032  * Fork - LGPL
15033  * <script type="text/javascript">
15034  */
15035 /**
15036  * @class Roo.state.Manager
15037  * This is the global state manager. By default all components that are "state aware" check this class
15038  * for state information if you don't pass them a custom state provider. In order for this class
15039  * to be useful, it must be initialized with a provider when your application initializes.
15040  <pre><code>
15041 // in your initialization function
15042 init : function(){
15043    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15044    ...
15045    // supposed you have a {@link Roo.BorderLayout}
15046    var layout = new Roo.BorderLayout(...);
15047    layout.restoreState();
15048    // or a {Roo.BasicDialog}
15049    var dialog = new Roo.BasicDialog(...);
15050    dialog.restoreState();
15051  </code></pre>
15052  * @singleton
15053  */
15054 Roo.state.Manager = function(){
15055     var provider = new Roo.state.Provider();
15056     
15057     return {
15058         /**
15059          * Configures the default state provider for your application
15060          * @param {Provider} stateProvider The state provider to set
15061          */
15062         setProvider : function(stateProvider){
15063             provider = stateProvider;
15064         },
15065         
15066         /**
15067          * Returns the current value for a key
15068          * @param {String} name The key name
15069          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15070          * @return {Mixed} The state data
15071          */
15072         get : function(key, defaultValue){
15073             return provider.get(key, defaultValue);
15074         },
15075         
15076         /**
15077          * Sets the value for a key
15078          * @param {String} name The key name
15079          * @param {Mixed} value The state data
15080          */
15081          set : function(key, value){
15082             provider.set(key, value);
15083         },
15084         
15085         /**
15086          * Clears a value from the state
15087          * @param {String} name The key name
15088          */
15089         clear : function(key){
15090             provider.clear(key);
15091         },
15092         
15093         /**
15094          * Gets the currently configured state provider
15095          * @return {Provider} The state provider
15096          */
15097         getProvider : function(){
15098             return provider;
15099         }
15100     };
15101 }();
15102 /*
15103  * Based on:
15104  * Ext JS Library 1.1.1
15105  * Copyright(c) 2006-2007, Ext JS, LLC.
15106  *
15107  * Originally Released Under LGPL - original licence link has changed is not relivant.
15108  *
15109  * Fork - LGPL
15110  * <script type="text/javascript">
15111  */
15112 /**
15113  * @class Roo.state.CookieProvider
15114  * @extends Roo.state.Provider
15115  * The default Provider implementation which saves state via cookies.
15116  * <br />Usage:
15117  <pre><code>
15118    var cp = new Roo.state.CookieProvider({
15119        path: "/cgi-bin/",
15120        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15121        domain: "roojs.com"
15122    })
15123    Roo.state.Manager.setProvider(cp);
15124  </code></pre>
15125  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15126  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15127  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15128  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15129  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15130  * domain the page is running on including the 'www' like 'www.roojs.com')
15131  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15132  * @constructor
15133  * Create a new CookieProvider
15134  * @param {Object} config The configuration object
15135  */
15136 Roo.state.CookieProvider = function(config){
15137     Roo.state.CookieProvider.superclass.constructor.call(this);
15138     this.path = "/";
15139     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15140     this.domain = null;
15141     this.secure = false;
15142     Roo.apply(this, config);
15143     this.state = this.readCookies();
15144 };
15145
15146 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15147     // private
15148     set : function(name, value){
15149         if(typeof value == "undefined" || value === null){
15150             this.clear(name);
15151             return;
15152         }
15153         this.setCookie(name, value);
15154         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15155     },
15156
15157     // private
15158     clear : function(name){
15159         this.clearCookie(name);
15160         Roo.state.CookieProvider.superclass.clear.call(this, name);
15161     },
15162
15163     // private
15164     readCookies : function(){
15165         var cookies = {};
15166         var c = document.cookie + ";";
15167         var re = /\s?(.*?)=(.*?);/g;
15168         var matches;
15169         while((matches = re.exec(c)) != null){
15170             var name = matches[1];
15171             var value = matches[2];
15172             if(name && name.substring(0,3) == "ys-"){
15173                 cookies[name.substr(3)] = this.decodeValue(value);
15174             }
15175         }
15176         return cookies;
15177     },
15178
15179     // private
15180     setCookie : function(name, value){
15181         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15182            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15183            ((this.path == null) ? "" : ("; path=" + this.path)) +
15184            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15185            ((this.secure == true) ? "; secure" : "");
15186     },
15187
15188     // private
15189     clearCookie : function(name){
15190         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15191            ((this.path == null) ? "" : ("; path=" + this.path)) +
15192            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15193            ((this.secure == true) ? "; secure" : "");
15194     }
15195 });/*
15196  * Based on:
15197  * Ext JS Library 1.1.1
15198  * Copyright(c) 2006-2007, Ext JS, LLC.
15199  *
15200  * Originally Released Under LGPL - original licence link has changed is not relivant.
15201  *
15202  * Fork - LGPL
15203  * <script type="text/javascript">
15204  */
15205  
15206
15207 /**
15208  * @class Roo.ComponentMgr
15209  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15210  * @singleton
15211  */
15212 Roo.ComponentMgr = function(){
15213     var all = new Roo.util.MixedCollection();
15214
15215     return {
15216         /**
15217          * Registers a component.
15218          * @param {Roo.Component} c The component
15219          */
15220         register : function(c){
15221             all.add(c);
15222         },
15223
15224         /**
15225          * Unregisters a component.
15226          * @param {Roo.Component} c The component
15227          */
15228         unregister : function(c){
15229             all.remove(c);
15230         },
15231
15232         /**
15233          * Returns a component by id
15234          * @param {String} id The component id
15235          */
15236         get : function(id){
15237             return all.get(id);
15238         },
15239
15240         /**
15241          * Registers a function that will be called when a specified component is added to ComponentMgr
15242          * @param {String} id The component id
15243          * @param {Funtction} fn The callback function
15244          * @param {Object} scope The scope of the callback
15245          */
15246         onAvailable : function(id, fn, scope){
15247             all.on("add", function(index, o){
15248                 if(o.id == id){
15249                     fn.call(scope || o, o);
15250                     all.un("add", fn, scope);
15251                 }
15252             });
15253         }
15254     };
15255 }();/*
15256  * Based on:
15257  * Ext JS Library 1.1.1
15258  * Copyright(c) 2006-2007, Ext JS, LLC.
15259  *
15260  * Originally Released Under LGPL - original licence link has changed is not relivant.
15261  *
15262  * Fork - LGPL
15263  * <script type="text/javascript">
15264  */
15265  
15266 /**
15267  * @class Roo.Component
15268  * @extends Roo.util.Observable
15269  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15270  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15271  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15272  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15273  * All visual components (widgets) that require rendering into a layout should subclass Component.
15274  * @constructor
15275  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15276  * 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
15277  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15278  */
15279 Roo.Component = function(config){
15280     config = config || {};
15281     if(config.tagName || config.dom || typeof config == "string"){ // element object
15282         config = {el: config, id: config.id || config};
15283     }
15284     this.initialConfig = config;
15285
15286     Roo.apply(this, config);
15287     this.addEvents({
15288         /**
15289          * @event disable
15290          * Fires after the component is disabled.
15291              * @param {Roo.Component} this
15292              */
15293         disable : true,
15294         /**
15295          * @event enable
15296          * Fires after the component is enabled.
15297              * @param {Roo.Component} this
15298              */
15299         enable : true,
15300         /**
15301          * @event beforeshow
15302          * Fires before the component is shown.  Return false to stop the show.
15303              * @param {Roo.Component} this
15304              */
15305         beforeshow : true,
15306         /**
15307          * @event show
15308          * Fires after the component is shown.
15309              * @param {Roo.Component} this
15310              */
15311         show : true,
15312         /**
15313          * @event beforehide
15314          * Fires before the component is hidden. Return false to stop the hide.
15315              * @param {Roo.Component} this
15316              */
15317         beforehide : true,
15318         /**
15319          * @event hide
15320          * Fires after the component is hidden.
15321              * @param {Roo.Component} this
15322              */
15323         hide : true,
15324         /**
15325          * @event beforerender
15326          * Fires before the component is rendered. Return false to stop the render.
15327              * @param {Roo.Component} this
15328              */
15329         beforerender : true,
15330         /**
15331          * @event render
15332          * Fires after the component is rendered.
15333              * @param {Roo.Component} this
15334              */
15335         render : true,
15336         /**
15337          * @event beforedestroy
15338          * Fires before the component is destroyed. Return false to stop the destroy.
15339              * @param {Roo.Component} this
15340              */
15341         beforedestroy : true,
15342         /**
15343          * @event destroy
15344          * Fires after the component is destroyed.
15345              * @param {Roo.Component} this
15346              */
15347         destroy : true
15348     });
15349     if(!this.id){
15350         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15351     }
15352     Roo.ComponentMgr.register(this);
15353     Roo.Component.superclass.constructor.call(this);
15354     this.initComponent();
15355     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15356         this.render(this.renderTo);
15357         delete this.renderTo;
15358     }
15359 };
15360
15361 /** @private */
15362 Roo.Component.AUTO_ID = 1000;
15363
15364 Roo.extend(Roo.Component, Roo.util.Observable, {
15365     /**
15366      * @scope Roo.Component.prototype
15367      * @type {Boolean}
15368      * true if this component is hidden. Read-only.
15369      */
15370     hidden : false,
15371     /**
15372      * @type {Boolean}
15373      * true if this component is disabled. Read-only.
15374      */
15375     disabled : false,
15376     /**
15377      * @type {Boolean}
15378      * true if this component has been rendered. Read-only.
15379      */
15380     rendered : false,
15381     
15382     /** @cfg {String} disableClass
15383      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15384      */
15385     disabledClass : "x-item-disabled",
15386         /** @cfg {Boolean} allowDomMove
15387          * Whether the component can move the Dom node when rendering (defaults to true).
15388          */
15389     allowDomMove : true,
15390     /** @cfg {String} hideMode (display|visibility)
15391      * How this component should hidden. Supported values are
15392      * "visibility" (css visibility), "offsets" (negative offset position) and
15393      * "display" (css display) - defaults to "display".
15394      */
15395     hideMode: 'display',
15396
15397     /** @private */
15398     ctype : "Roo.Component",
15399
15400     /**
15401      * @cfg {String} actionMode 
15402      * which property holds the element that used for  hide() / show() / disable() / enable()
15403      * default is 'el' 
15404      */
15405     actionMode : "el",
15406
15407     /** @private */
15408     getActionEl : function(){
15409         return this[this.actionMode];
15410     },
15411
15412     initComponent : Roo.emptyFn,
15413     /**
15414      * If this is a lazy rendering component, render it to its container element.
15415      * @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.
15416      */
15417     render : function(container, position){
15418         
15419         if(this.rendered){
15420             return this;
15421         }
15422         
15423         if(this.fireEvent("beforerender", this) === false){
15424             return false;
15425         }
15426         
15427         if(!container && this.el){
15428             this.el = Roo.get(this.el);
15429             container = this.el.dom.parentNode;
15430             this.allowDomMove = false;
15431         }
15432         this.container = Roo.get(container);
15433         this.rendered = true;
15434         if(position !== undefined){
15435             if(typeof position == 'number'){
15436                 position = this.container.dom.childNodes[position];
15437             }else{
15438                 position = Roo.getDom(position);
15439             }
15440         }
15441         this.onRender(this.container, position || null);
15442         if(this.cls){
15443             this.el.addClass(this.cls);
15444             delete this.cls;
15445         }
15446         if(this.style){
15447             this.el.applyStyles(this.style);
15448             delete this.style;
15449         }
15450         this.fireEvent("render", this);
15451         this.afterRender(this.container);
15452         if(this.hidden){
15453             this.hide();
15454         }
15455         if(this.disabled){
15456             this.disable();
15457         }
15458
15459         return this;
15460         
15461     },
15462
15463     /** @private */
15464     // default function is not really useful
15465     onRender : function(ct, position){
15466         if(this.el){
15467             this.el = Roo.get(this.el);
15468             if(this.allowDomMove !== false){
15469                 ct.dom.insertBefore(this.el.dom, position);
15470             }
15471         }
15472     },
15473
15474     /** @private */
15475     getAutoCreate : function(){
15476         var cfg = typeof this.autoCreate == "object" ?
15477                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15478         if(this.id && !cfg.id){
15479             cfg.id = this.id;
15480         }
15481         return cfg;
15482     },
15483
15484     /** @private */
15485     afterRender : Roo.emptyFn,
15486
15487     /**
15488      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15489      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15490      */
15491     destroy : function(){
15492         if(this.fireEvent("beforedestroy", this) !== false){
15493             this.purgeListeners();
15494             this.beforeDestroy();
15495             if(this.rendered){
15496                 this.el.removeAllListeners();
15497                 this.el.remove();
15498                 if(this.actionMode == "container"){
15499                     this.container.remove();
15500                 }
15501             }
15502             this.onDestroy();
15503             Roo.ComponentMgr.unregister(this);
15504             this.fireEvent("destroy", this);
15505         }
15506     },
15507
15508         /** @private */
15509     beforeDestroy : function(){
15510
15511     },
15512
15513         /** @private */
15514         onDestroy : function(){
15515
15516     },
15517
15518     /**
15519      * Returns the underlying {@link Roo.Element}.
15520      * @return {Roo.Element} The element
15521      */
15522     getEl : function(){
15523         return this.el;
15524     },
15525
15526     /**
15527      * Returns the id of this component.
15528      * @return {String}
15529      */
15530     getId : function(){
15531         return this.id;
15532     },
15533
15534     /**
15535      * Try to focus this component.
15536      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15537      * @return {Roo.Component} this
15538      */
15539     focus : function(selectText){
15540         if(this.rendered){
15541             this.el.focus();
15542             if(selectText === true){
15543                 this.el.dom.select();
15544             }
15545         }
15546         return this;
15547     },
15548
15549     /** @private */
15550     blur : function(){
15551         if(this.rendered){
15552             this.el.blur();
15553         }
15554         return this;
15555     },
15556
15557     /**
15558      * Disable this component.
15559      * @return {Roo.Component} this
15560      */
15561     disable : function(){
15562         if(this.rendered){
15563             this.onDisable();
15564         }
15565         this.disabled = true;
15566         this.fireEvent("disable", this);
15567         return this;
15568     },
15569
15570         // private
15571     onDisable : function(){
15572         this.getActionEl().addClass(this.disabledClass);
15573         this.el.dom.disabled = true;
15574     },
15575
15576     /**
15577      * Enable this component.
15578      * @return {Roo.Component} this
15579      */
15580     enable : function(){
15581         if(this.rendered){
15582             this.onEnable();
15583         }
15584         this.disabled = false;
15585         this.fireEvent("enable", this);
15586         return this;
15587     },
15588
15589         // private
15590     onEnable : function(){
15591         this.getActionEl().removeClass(this.disabledClass);
15592         this.el.dom.disabled = false;
15593     },
15594
15595     /**
15596      * Convenience function for setting disabled/enabled by boolean.
15597      * @param {Boolean} disabled
15598      */
15599     setDisabled : function(disabled){
15600         this[disabled ? "disable" : "enable"]();
15601     },
15602
15603     /**
15604      * Show this component.
15605      * @return {Roo.Component} this
15606      */
15607     show: function(){
15608         if(this.fireEvent("beforeshow", this) !== false){
15609             this.hidden = false;
15610             if(this.rendered){
15611                 this.onShow();
15612             }
15613             this.fireEvent("show", this);
15614         }
15615         return this;
15616     },
15617
15618     // private
15619     onShow : function(){
15620         var ae = this.getActionEl();
15621         if(this.hideMode == 'visibility'){
15622             ae.dom.style.visibility = "visible";
15623         }else if(this.hideMode == 'offsets'){
15624             ae.removeClass('x-hidden');
15625         }else{
15626             ae.dom.style.display = "";
15627         }
15628     },
15629
15630     /**
15631      * Hide this component.
15632      * @return {Roo.Component} this
15633      */
15634     hide: function(){
15635         if(this.fireEvent("beforehide", this) !== false){
15636             this.hidden = true;
15637             if(this.rendered){
15638                 this.onHide();
15639             }
15640             this.fireEvent("hide", this);
15641         }
15642         return this;
15643     },
15644
15645     // private
15646     onHide : function(){
15647         var ae = this.getActionEl();
15648         if(this.hideMode == 'visibility'){
15649             ae.dom.style.visibility = "hidden";
15650         }else if(this.hideMode == 'offsets'){
15651             ae.addClass('x-hidden');
15652         }else{
15653             ae.dom.style.display = "none";
15654         }
15655     },
15656
15657     /**
15658      * Convenience function to hide or show this component by boolean.
15659      * @param {Boolean} visible True to show, false to hide
15660      * @return {Roo.Component} this
15661      */
15662     setVisible: function(visible){
15663         if(visible) {
15664             this.show();
15665         }else{
15666             this.hide();
15667         }
15668         return this;
15669     },
15670
15671     /**
15672      * Returns true if this component is visible.
15673      */
15674     isVisible : function(){
15675         return this.getActionEl().isVisible();
15676     },
15677
15678     cloneConfig : function(overrides){
15679         overrides = overrides || {};
15680         var id = overrides.id || Roo.id();
15681         var cfg = Roo.applyIf(overrides, this.initialConfig);
15682         cfg.id = id; // prevent dup id
15683         return new this.constructor(cfg);
15684     }
15685 });/*
15686  * Based on:
15687  * Ext JS Library 1.1.1
15688  * Copyright(c) 2006-2007, Ext JS, LLC.
15689  *
15690  * Originally Released Under LGPL - original licence link has changed is not relivant.
15691  *
15692  * Fork - LGPL
15693  * <script type="text/javascript">
15694  */
15695
15696 /**
15697  * @class Roo.BoxComponent
15698  * @extends Roo.Component
15699  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15700  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15701  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15702  * layout containers.
15703  * @constructor
15704  * @param {Roo.Element/String/Object} config The configuration options.
15705  */
15706 Roo.BoxComponent = function(config){
15707     Roo.Component.call(this, config);
15708     this.addEvents({
15709         /**
15710          * @event resize
15711          * Fires after the component is resized.
15712              * @param {Roo.Component} this
15713              * @param {Number} adjWidth The box-adjusted width that was set
15714              * @param {Number} adjHeight The box-adjusted height that was set
15715              * @param {Number} rawWidth The width that was originally specified
15716              * @param {Number} rawHeight The height that was originally specified
15717              */
15718         resize : true,
15719         /**
15720          * @event move
15721          * Fires after the component is moved.
15722              * @param {Roo.Component} this
15723              * @param {Number} x The new x position
15724              * @param {Number} y The new y position
15725              */
15726         move : true
15727     });
15728 };
15729
15730 Roo.extend(Roo.BoxComponent, Roo.Component, {
15731     // private, set in afterRender to signify that the component has been rendered
15732     boxReady : false,
15733     // private, used to defer height settings to subclasses
15734     deferHeight: false,
15735     /** @cfg {Number} width
15736      * width (optional) size of component
15737      */
15738      /** @cfg {Number} height
15739      * height (optional) size of component
15740      */
15741      
15742     /**
15743      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15744      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15745      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15746      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15747      * @return {Roo.BoxComponent} this
15748      */
15749     setSize : function(w, h){
15750         // support for standard size objects
15751         if(typeof w == 'object'){
15752             h = w.height;
15753             w = w.width;
15754         }
15755         // not rendered
15756         if(!this.boxReady){
15757             this.width = w;
15758             this.height = h;
15759             return this;
15760         }
15761
15762         // prevent recalcs when not needed
15763         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15764             return this;
15765         }
15766         this.lastSize = {width: w, height: h};
15767
15768         var adj = this.adjustSize(w, h);
15769         var aw = adj.width, ah = adj.height;
15770         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15771             var rz = this.getResizeEl();
15772             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15773                 rz.setSize(aw, ah);
15774             }else if(!this.deferHeight && ah !== undefined){
15775                 rz.setHeight(ah);
15776             }else if(aw !== undefined){
15777                 rz.setWidth(aw);
15778             }
15779             this.onResize(aw, ah, w, h);
15780             this.fireEvent('resize', this, aw, ah, w, h);
15781         }
15782         return this;
15783     },
15784
15785     /**
15786      * Gets the current size of the component's underlying element.
15787      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15788      */
15789     getSize : function(){
15790         return this.el.getSize();
15791     },
15792
15793     /**
15794      * Gets the current XY position of the component's underlying element.
15795      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15796      * @return {Array} The XY position of the element (e.g., [100, 200])
15797      */
15798     getPosition : function(local){
15799         if(local === true){
15800             return [this.el.getLeft(true), this.el.getTop(true)];
15801         }
15802         return this.xy || this.el.getXY();
15803     },
15804
15805     /**
15806      * Gets the current box measurements of the component's underlying element.
15807      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15808      * @returns {Object} box An object in the format {x, y, width, height}
15809      */
15810     getBox : function(local){
15811         var s = this.el.getSize();
15812         if(local){
15813             s.x = this.el.getLeft(true);
15814             s.y = this.el.getTop(true);
15815         }else{
15816             var xy = this.xy || this.el.getXY();
15817             s.x = xy[0];
15818             s.y = xy[1];
15819         }
15820         return s;
15821     },
15822
15823     /**
15824      * Sets the current box measurements of the component's underlying element.
15825      * @param {Object} box An object in the format {x, y, width, height}
15826      * @returns {Roo.BoxComponent} this
15827      */
15828     updateBox : function(box){
15829         this.setSize(box.width, box.height);
15830         this.setPagePosition(box.x, box.y);
15831         return this;
15832     },
15833
15834     // protected
15835     getResizeEl : function(){
15836         return this.resizeEl || this.el;
15837     },
15838
15839     // protected
15840     getPositionEl : function(){
15841         return this.positionEl || this.el;
15842     },
15843
15844     /**
15845      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15846      * This method fires the move event.
15847      * @param {Number} left The new left
15848      * @param {Number} top The new top
15849      * @returns {Roo.BoxComponent} this
15850      */
15851     setPosition : function(x, y){
15852         this.x = x;
15853         this.y = y;
15854         if(!this.boxReady){
15855             return this;
15856         }
15857         var adj = this.adjustPosition(x, y);
15858         var ax = adj.x, ay = adj.y;
15859
15860         var el = this.getPositionEl();
15861         if(ax !== undefined || ay !== undefined){
15862             if(ax !== undefined && ay !== undefined){
15863                 el.setLeftTop(ax, ay);
15864             }else if(ax !== undefined){
15865                 el.setLeft(ax);
15866             }else if(ay !== undefined){
15867                 el.setTop(ay);
15868             }
15869             this.onPosition(ax, ay);
15870             this.fireEvent('move', this, ax, ay);
15871         }
15872         return this;
15873     },
15874
15875     /**
15876      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15877      * This method fires the move event.
15878      * @param {Number} x The new x position
15879      * @param {Number} y The new y position
15880      * @returns {Roo.BoxComponent} this
15881      */
15882     setPagePosition : function(x, y){
15883         this.pageX = x;
15884         this.pageY = y;
15885         if(!this.boxReady){
15886             return;
15887         }
15888         if(x === undefined || y === undefined){ // cannot translate undefined points
15889             return;
15890         }
15891         var p = this.el.translatePoints(x, y);
15892         this.setPosition(p.left, p.top);
15893         return this;
15894     },
15895
15896     // private
15897     onRender : function(ct, position){
15898         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15899         if(this.resizeEl){
15900             this.resizeEl = Roo.get(this.resizeEl);
15901         }
15902         if(this.positionEl){
15903             this.positionEl = Roo.get(this.positionEl);
15904         }
15905     },
15906
15907     // private
15908     afterRender : function(){
15909         Roo.BoxComponent.superclass.afterRender.call(this);
15910         this.boxReady = true;
15911         this.setSize(this.width, this.height);
15912         if(this.x || this.y){
15913             this.setPosition(this.x, this.y);
15914         }
15915         if(this.pageX || this.pageY){
15916             this.setPagePosition(this.pageX, this.pageY);
15917         }
15918     },
15919
15920     /**
15921      * Force the component's size to recalculate based on the underlying element's current height and width.
15922      * @returns {Roo.BoxComponent} this
15923      */
15924     syncSize : function(){
15925         delete this.lastSize;
15926         this.setSize(this.el.getWidth(), this.el.getHeight());
15927         return this;
15928     },
15929
15930     /**
15931      * Called after the component is resized, this method is empty by default but can be implemented by any
15932      * subclass that needs to perform custom logic after a resize occurs.
15933      * @param {Number} adjWidth The box-adjusted width that was set
15934      * @param {Number} adjHeight The box-adjusted height that was set
15935      * @param {Number} rawWidth The width that was originally specified
15936      * @param {Number} rawHeight The height that was originally specified
15937      */
15938     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15939
15940     },
15941
15942     /**
15943      * Called after the component is moved, this method is empty by default but can be implemented by any
15944      * subclass that needs to perform custom logic after a move occurs.
15945      * @param {Number} x The new x position
15946      * @param {Number} y The new y position
15947      */
15948     onPosition : function(x, y){
15949
15950     },
15951
15952     // private
15953     adjustSize : function(w, h){
15954         if(this.autoWidth){
15955             w = 'auto';
15956         }
15957         if(this.autoHeight){
15958             h = 'auto';
15959         }
15960         return {width : w, height: h};
15961     },
15962
15963     // private
15964     adjustPosition : function(x, y){
15965         return {x : x, y: y};
15966     }
15967 });/*
15968  * Original code for Roojs - LGPL
15969  * <script type="text/javascript">
15970  */
15971  
15972 /**
15973  * @class Roo.XComponent
15974  * A delayed Element creator...
15975  * Or a way to group chunks of interface together.
15976  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15977  *  used in conjunction with XComponent.build() it will create an instance of each element,
15978  *  then call addxtype() to build the User interface.
15979  * 
15980  * Mypart.xyx = new Roo.XComponent({
15981
15982     parent : 'Mypart.xyz', // empty == document.element.!!
15983     order : '001',
15984     name : 'xxxx'
15985     region : 'xxxx'
15986     disabled : function() {} 
15987      
15988     tree : function() { // return an tree of xtype declared components
15989         var MODULE = this;
15990         return 
15991         {
15992             xtype : 'NestedLayoutPanel',
15993             // technicall
15994         }
15995      ]
15996  *})
15997  *
15998  *
15999  * It can be used to build a big heiracy, with parent etc.
16000  * or you can just use this to render a single compoent to a dom element
16001  * MYPART.render(Roo.Element | String(id) | dom_element )
16002  *
16003  *
16004  * Usage patterns.
16005  *
16006  * Classic Roo
16007  *
16008  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16009  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16010  *
16011  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16012  *
16013  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16014  * - if mulitple topModules exist, the last one is defined as the top module.
16015  *
16016  * Embeded Roo
16017  * 
16018  * When the top level or multiple modules are to embedded into a existing HTML page,
16019  * the parent element can container '#id' of the element where the module will be drawn.
16020  *
16021  * Bootstrap Roo
16022  *
16023  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16024  * it relies more on a include mechanism, where sub modules are included into an outer page.
16025  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16026  * 
16027  * Bootstrap Roo Included elements
16028  *
16029  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16030  * hence confusing the component builder as it thinks there are multiple top level elements. 
16031  *
16032  * String Over-ride & Translations
16033  *
16034  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16035  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16036  * are needed. @see Roo.XComponent.overlayString  
16037  * 
16038  * 
16039  * 
16040  * @extends Roo.util.Observable
16041  * @constructor
16042  * @param cfg {Object} configuration of component
16043  * 
16044  */
16045 Roo.XComponent = function(cfg) {
16046     Roo.apply(this, cfg);
16047     this.addEvents({ 
16048         /**
16049              * @event built
16050              * Fires when this the componnt is built
16051              * @param {Roo.XComponent} c the component
16052              */
16053         'built' : true
16054         
16055     });
16056     this.region = this.region || 'center'; // default..
16057     Roo.XComponent.register(this);
16058     this.modules = false;
16059     this.el = false; // where the layout goes..
16060     
16061     
16062 }
16063 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16064     /**
16065      * @property el
16066      * The created element (with Roo.factory())
16067      * @type {Roo.Layout}
16068      */
16069     el  : false,
16070     
16071     /**
16072      * @property el
16073      * for BC  - use el in new code
16074      * @type {Roo.Layout}
16075      */
16076     panel : false,
16077     
16078     /**
16079      * @property layout
16080      * for BC  - use el in new code
16081      * @type {Roo.Layout}
16082      */
16083     layout : false,
16084     
16085      /**
16086      * @cfg {Function|boolean} disabled
16087      * If this module is disabled by some rule, return true from the funtion
16088      */
16089     disabled : false,
16090     
16091     /**
16092      * @cfg {String} parent 
16093      * Name of parent element which it get xtype added to..
16094      */
16095     parent: false,
16096     
16097     /**
16098      * @cfg {String} order
16099      * Used to set the order in which elements are created (usefull for multiple tabs)
16100      */
16101     
16102     order : false,
16103     /**
16104      * @cfg {String} name
16105      * String to display while loading.
16106      */
16107     name : false,
16108     /**
16109      * @cfg {String} region
16110      * Region to render component to (defaults to center)
16111      */
16112     region : 'center',
16113     
16114     /**
16115      * @cfg {Array} items
16116      * A single item array - the first element is the root of the tree..
16117      * It's done this way to stay compatible with the Xtype system...
16118      */
16119     items : false,
16120     
16121     /**
16122      * @property _tree
16123      * The method that retuns the tree of parts that make up this compoennt 
16124      * @type {function}
16125      */
16126     _tree  : false,
16127     
16128      /**
16129      * render
16130      * render element to dom or tree
16131      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16132      */
16133     
16134     render : function(el)
16135     {
16136         
16137         el = el || false;
16138         var hp = this.parent ? 1 : 0;
16139         Roo.debug &&  Roo.log(this);
16140         
16141         var tree = this._tree ? this._tree() : this.tree();
16142
16143         
16144         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16145             // if parent is a '#.....' string, then let's use that..
16146             var ename = this.parent.substr(1);
16147             this.parent = false;
16148             Roo.debug && Roo.log(ename);
16149             switch (ename) {
16150                 case 'bootstrap-body':
16151                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16152                         // this is the BorderLayout standard?
16153                        this.parent = { el : true };
16154                        break;
16155                     }
16156                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16157                         // need to insert stuff...
16158                         this.parent =  {
16159                              el : new Roo.bootstrap.layout.Border({
16160                                  el : document.body, 
16161                      
16162                                  center: {
16163                                     titlebar: false,
16164                                     autoScroll:false,
16165                                     closeOnTab: true,
16166                                     tabPosition: 'top',
16167                                       //resizeTabs: true,
16168                                     alwaysShowTabs: true,
16169                                     hideTabs: false
16170                                      //minTabWidth: 140
16171                                  }
16172                              })
16173                         
16174                          };
16175                          break;
16176                     }
16177                          
16178                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16179                         this.parent = { el :  new  Roo.bootstrap.Body() };
16180                         Roo.debug && Roo.log("setting el to doc body");
16181                          
16182                     } else {
16183                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16184                     }
16185                     break;
16186                 case 'bootstrap':
16187                     this.parent = { el : true};
16188                     // fall through
16189                 default:
16190                     el = Roo.get(ename);
16191                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16192                         this.parent = { el : true};
16193                     }
16194                     
16195                     break;
16196             }
16197                 
16198             
16199             if (!el && !this.parent) {
16200                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16201                 return;
16202             }
16203         }
16204         
16205         Roo.debug && Roo.log("EL:");
16206         Roo.debug && Roo.log(el);
16207         Roo.debug && Roo.log("this.parent.el:");
16208         Roo.debug && Roo.log(this.parent.el);
16209         
16210
16211         // altertive root elements ??? - we need a better way to indicate these.
16212         var is_alt = Roo.XComponent.is_alt ||
16213                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16214                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16215                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16216         
16217         
16218         
16219         if (!this.parent && is_alt) {
16220             //el = Roo.get(document.body);
16221             this.parent = { el : true };
16222         }
16223             
16224             
16225         
16226         if (!this.parent) {
16227             
16228             Roo.debug && Roo.log("no parent - creating one");
16229             
16230             el = el ? Roo.get(el) : false;      
16231             
16232             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16233                 
16234                 this.parent =  {
16235                     el : new Roo.bootstrap.layout.Border({
16236                         el: el || document.body,
16237                     
16238                         center: {
16239                             titlebar: false,
16240                             autoScroll:false,
16241                             closeOnTab: true,
16242                             tabPosition: 'top',
16243                              //resizeTabs: true,
16244                             alwaysShowTabs: false,
16245                             hideTabs: true,
16246                             minTabWidth: 140,
16247                             overflow: 'visible'
16248                          }
16249                      })
16250                 };
16251             } else {
16252             
16253                 // it's a top level one..
16254                 this.parent =  {
16255                     el : new Roo.BorderLayout(el || document.body, {
16256                         center: {
16257                             titlebar: false,
16258                             autoScroll:false,
16259                             closeOnTab: true,
16260                             tabPosition: 'top',
16261                              //resizeTabs: true,
16262                             alwaysShowTabs: el && hp? false :  true,
16263                             hideTabs: el || !hp ? true :  false,
16264                             minTabWidth: 140
16265                          }
16266                     })
16267                 };
16268             }
16269         }
16270         
16271         if (!this.parent.el) {
16272                 // probably an old style ctor, which has been disabled.
16273                 return;
16274
16275         }
16276                 // The 'tree' method is  '_tree now' 
16277             
16278         tree.region = tree.region || this.region;
16279         var is_body = false;
16280         if (this.parent.el === true) {
16281             // bootstrap... - body..
16282             if (el) {
16283                 tree.el = el;
16284             }
16285             this.parent.el = Roo.factory(tree);
16286             is_body = true;
16287         }
16288         
16289         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16290         this.fireEvent('built', this);
16291         
16292         this.panel = this.el;
16293         this.layout = this.panel.layout;
16294         this.parentLayout = this.parent.layout  || false;  
16295          
16296     }
16297     
16298 });
16299
16300 Roo.apply(Roo.XComponent, {
16301     /**
16302      * @property  hideProgress
16303      * true to disable the building progress bar.. usefull on single page renders.
16304      * @type Boolean
16305      */
16306     hideProgress : false,
16307     /**
16308      * @property  buildCompleted
16309      * True when the builder has completed building the interface.
16310      * @type Boolean
16311      */
16312     buildCompleted : false,
16313      
16314     /**
16315      * @property  topModule
16316      * the upper most module - uses document.element as it's constructor.
16317      * @type Object
16318      */
16319      
16320     topModule  : false,
16321       
16322     /**
16323      * @property  modules
16324      * array of modules to be created by registration system.
16325      * @type {Array} of Roo.XComponent
16326      */
16327     
16328     modules : [],
16329     /**
16330      * @property  elmodules
16331      * array of modules to be created by which use #ID 
16332      * @type {Array} of Roo.XComponent
16333      */
16334      
16335     elmodules : [],
16336
16337      /**
16338      * @property  is_alt
16339      * Is an alternative Root - normally used by bootstrap or other systems,
16340      *    where the top element in the tree can wrap 'body' 
16341      * @type {boolean}  (default false)
16342      */
16343      
16344     is_alt : false,
16345     /**
16346      * @property  build_from_html
16347      * Build elements from html - used by bootstrap HTML stuff 
16348      *    - this is cleared after build is completed
16349      * @type {boolean}    (default false)
16350      */
16351      
16352     build_from_html : false,
16353     /**
16354      * Register components to be built later.
16355      *
16356      * This solves the following issues
16357      * - Building is not done on page load, but after an authentication process has occured.
16358      * - Interface elements are registered on page load
16359      * - Parent Interface elements may not be loaded before child, so this handles that..
16360      * 
16361      *
16362      * example:
16363      * 
16364      * MyApp.register({
16365           order : '000001',
16366           module : 'Pman.Tab.projectMgr',
16367           region : 'center',
16368           parent : 'Pman.layout',
16369           disabled : false,  // or use a function..
16370         })
16371      
16372      * * @param {Object} details about module
16373      */
16374     register : function(obj) {
16375                 
16376         Roo.XComponent.event.fireEvent('register', obj);
16377         switch(typeof(obj.disabled) ) {
16378                 
16379             case 'undefined':
16380                 break;
16381             
16382             case 'function':
16383                 if ( obj.disabled() ) {
16384                         return;
16385                 }
16386                 break;
16387             
16388             default:
16389                 if (obj.disabled) {
16390                         return;
16391                 }
16392                 break;
16393         }
16394                 
16395         this.modules.push(obj);
16396          
16397     },
16398     /**
16399      * convert a string to an object..
16400      * eg. 'AAA.BBB' -> finds AAA.BBB
16401
16402      */
16403     
16404     toObject : function(str)
16405     {
16406         if (!str || typeof(str) == 'object') {
16407             return str;
16408         }
16409         if (str.substring(0,1) == '#') {
16410             return str;
16411         }
16412
16413         var ar = str.split('.');
16414         var rt, o;
16415         rt = ar.shift();
16416             /** eval:var:o */
16417         try {
16418             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16419         } catch (e) {
16420             throw "Module not found : " + str;
16421         }
16422         
16423         if (o === false) {
16424             throw "Module not found : " + str;
16425         }
16426         Roo.each(ar, function(e) {
16427             if (typeof(o[e]) == 'undefined') {
16428                 throw "Module not found : " + str;
16429             }
16430             o = o[e];
16431         });
16432         
16433         return o;
16434         
16435     },
16436     
16437     
16438     /**
16439      * move modules into their correct place in the tree..
16440      * 
16441      */
16442     preBuild : function ()
16443     {
16444         var _t = this;
16445         Roo.each(this.modules , function (obj)
16446         {
16447             Roo.XComponent.event.fireEvent('beforebuild', obj);
16448             
16449             var opar = obj.parent;
16450             try { 
16451                 obj.parent = this.toObject(opar);
16452             } catch(e) {
16453                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16454                 return;
16455             }
16456             
16457             if (!obj.parent) {
16458                 Roo.debug && Roo.log("GOT top level module");
16459                 Roo.debug && Roo.log(obj);
16460                 obj.modules = new Roo.util.MixedCollection(false, 
16461                     function(o) { return o.order + '' }
16462                 );
16463                 this.topModule = obj;
16464                 return;
16465             }
16466                         // parent is a string (usually a dom element name..)
16467             if (typeof(obj.parent) == 'string') {
16468                 this.elmodules.push(obj);
16469                 return;
16470             }
16471             if (obj.parent.constructor != Roo.XComponent) {
16472                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16473             }
16474             if (!obj.parent.modules) {
16475                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16476                     function(o) { return o.order + '' }
16477                 );
16478             }
16479             if (obj.parent.disabled) {
16480                 obj.disabled = true;
16481             }
16482             obj.parent.modules.add(obj);
16483         }, this);
16484     },
16485     
16486      /**
16487      * make a list of modules to build.
16488      * @return {Array} list of modules. 
16489      */ 
16490     
16491     buildOrder : function()
16492     {
16493         var _this = this;
16494         var cmp = function(a,b) {   
16495             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16496         };
16497         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16498             throw "No top level modules to build";
16499         }
16500         
16501         // make a flat list in order of modules to build.
16502         var mods = this.topModule ? [ this.topModule ] : [];
16503                 
16504         
16505         // elmodules (is a list of DOM based modules )
16506         Roo.each(this.elmodules, function(e) {
16507             mods.push(e);
16508             if (!this.topModule &&
16509                 typeof(e.parent) == 'string' &&
16510                 e.parent.substring(0,1) == '#' &&
16511                 Roo.get(e.parent.substr(1))
16512                ) {
16513                 
16514                 _this.topModule = e;
16515             }
16516             
16517         });
16518
16519         
16520         // add modules to their parents..
16521         var addMod = function(m) {
16522             Roo.debug && Roo.log("build Order: add: " + m.name);
16523                 
16524             mods.push(m);
16525             if (m.modules && !m.disabled) {
16526                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16527                 m.modules.keySort('ASC',  cmp );
16528                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16529     
16530                 m.modules.each(addMod);
16531             } else {
16532                 Roo.debug && Roo.log("build Order: no child modules");
16533             }
16534             // not sure if this is used any more..
16535             if (m.finalize) {
16536                 m.finalize.name = m.name + " (clean up) ";
16537                 mods.push(m.finalize);
16538             }
16539             
16540         }
16541         if (this.topModule && this.topModule.modules) { 
16542             this.topModule.modules.keySort('ASC',  cmp );
16543             this.topModule.modules.each(addMod);
16544         } 
16545         return mods;
16546     },
16547     
16548      /**
16549      * Build the registered modules.
16550      * @param {Object} parent element.
16551      * @param {Function} optional method to call after module has been added.
16552      * 
16553      */ 
16554    
16555     build : function(opts) 
16556     {
16557         
16558         if (typeof(opts) != 'undefined') {
16559             Roo.apply(this,opts);
16560         }
16561         
16562         this.preBuild();
16563         var mods = this.buildOrder();
16564       
16565         //this.allmods = mods;
16566         //Roo.debug && Roo.log(mods);
16567         //return;
16568         if (!mods.length) { // should not happen
16569             throw "NO modules!!!";
16570         }
16571         
16572         
16573         var msg = "Building Interface...";
16574         // flash it up as modal - so we store the mask!?
16575         if (!this.hideProgress && Roo.MessageBox) {
16576             Roo.MessageBox.show({ title: 'loading' });
16577             Roo.MessageBox.show({
16578                title: "Please wait...",
16579                msg: msg,
16580                width:450,
16581                progress:true,
16582                closable:false,
16583                modal: false
16584               
16585             });
16586         }
16587         var total = mods.length;
16588         
16589         var _this = this;
16590         var progressRun = function() {
16591             if (!mods.length) {
16592                 Roo.debug && Roo.log('hide?');
16593                 if (!this.hideProgress && Roo.MessageBox) {
16594                     Roo.MessageBox.hide();
16595                 }
16596                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16597                 
16598                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16599                 
16600                 // THE END...
16601                 return false;   
16602             }
16603             
16604             var m = mods.shift();
16605             
16606             
16607             Roo.debug && Roo.log(m);
16608             // not sure if this is supported any more.. - modules that are are just function
16609             if (typeof(m) == 'function') { 
16610                 m.call(this);
16611                 return progressRun.defer(10, _this);
16612             } 
16613             
16614             
16615             msg = "Building Interface " + (total  - mods.length) + 
16616                     " of " + total + 
16617                     (m.name ? (' - ' + m.name) : '');
16618                         Roo.debug && Roo.log(msg);
16619             if (!_this.hideProgress &&  Roo.MessageBox) { 
16620                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16621             }
16622             
16623          
16624             // is the module disabled?
16625             var disabled = (typeof(m.disabled) == 'function') ?
16626                 m.disabled.call(m.module.disabled) : m.disabled;    
16627             
16628             
16629             if (disabled) {
16630                 return progressRun(); // we do not update the display!
16631             }
16632             
16633             // now build 
16634             
16635                         
16636                         
16637             m.render();
16638             // it's 10 on top level, and 1 on others??? why...
16639             return progressRun.defer(10, _this);
16640              
16641         }
16642         progressRun.defer(1, _this);
16643      
16644         
16645         
16646     },
16647     /**
16648      * Overlay a set of modified strings onto a component
16649      * This is dependant on our builder exporting the strings and 'named strings' elements.
16650      * 
16651      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
16652      * @param {Object} associative array of 'named' string and it's new value.
16653      * 
16654      */
16655         overlayStrings : function( component, strings )
16656     {
16657         if (typeof(component['_named_strings']) == 'undefined') {
16658             throw "ERROR: component does not have _named_strings";
16659         }
16660         for ( var k in strings ) {
16661             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
16662             if (md !== false) {
16663                 component['_strings'][md] = strings[k];
16664             } else {
16665                 Roo.log('could not find named string: ' + k + ' in');
16666                 Roo.log(component);
16667             }
16668             
16669         }
16670         
16671     },
16672     
16673         
16674         /**
16675          * Event Object.
16676          *
16677          *
16678          */
16679         event: false, 
16680     /**
16681          * wrapper for event.on - aliased later..  
16682          * Typically use to register a event handler for register:
16683          *
16684          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16685          *
16686          */
16687     on : false
16688    
16689     
16690     
16691 });
16692
16693 Roo.XComponent.event = new Roo.util.Observable({
16694                 events : { 
16695                         /**
16696                          * @event register
16697                          * Fires when an Component is registered,
16698                          * set the disable property on the Component to stop registration.
16699                          * @param {Roo.XComponent} c the component being registerd.
16700                          * 
16701                          */
16702                         'register' : true,
16703             /**
16704                          * @event beforebuild
16705                          * Fires before each Component is built
16706                          * can be used to apply permissions.
16707                          * @param {Roo.XComponent} c the component being registerd.
16708                          * 
16709                          */
16710                         'beforebuild' : true,
16711                         /**
16712                          * @event buildcomplete
16713                          * Fires on the top level element when all elements have been built
16714                          * @param {Roo.XComponent} the top level component.
16715                          */
16716                         'buildcomplete' : true
16717                         
16718                 }
16719 });
16720
16721 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16722  //
16723  /**
16724  * marked - a markdown parser
16725  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16726  * https://github.com/chjj/marked
16727  */
16728
16729
16730 /**
16731  *
16732  * Roo.Markdown - is a very crude wrapper around marked..
16733  *
16734  * usage:
16735  * 
16736  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16737  * 
16738  * Note: move the sample code to the bottom of this
16739  * file before uncommenting it.
16740  *
16741  */
16742
16743 Roo.Markdown = {};
16744 Roo.Markdown.toHtml = function(text) {
16745     
16746     var c = new Roo.Markdown.marked.setOptions({
16747             renderer: new Roo.Markdown.marked.Renderer(),
16748             gfm: true,
16749             tables: true,
16750             breaks: false,
16751             pedantic: false,
16752             sanitize: false,
16753             smartLists: true,
16754             smartypants: false
16755           });
16756     // A FEW HACKS!!?
16757     
16758     text = text.replace(/\\\n/g,' ');
16759     return Roo.Markdown.marked(text);
16760 };
16761 //
16762 // converter
16763 //
16764 // Wraps all "globals" so that the only thing
16765 // exposed is makeHtml().
16766 //
16767 (function() {
16768     
16769     /**
16770      * Block-Level Grammar
16771      */
16772     
16773     var block = {
16774       newline: /^\n+/,
16775       code: /^( {4}[^\n]+\n*)+/,
16776       fences: noop,
16777       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16778       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16779       nptable: noop,
16780       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16781       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16782       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16783       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16784       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16785       table: noop,
16786       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16787       text: /^[^\n]+/
16788     };
16789     
16790     block.bullet = /(?:[*+-]|\d+\.)/;
16791     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16792     block.item = replace(block.item, 'gm')
16793       (/bull/g, block.bullet)
16794       ();
16795     
16796     block.list = replace(block.list)
16797       (/bull/g, block.bullet)
16798       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16799       ('def', '\\n+(?=' + block.def.source + ')')
16800       ();
16801     
16802     block.blockquote = replace(block.blockquote)
16803       ('def', block.def)
16804       ();
16805     
16806     block._tag = '(?!(?:'
16807       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16808       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16809       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16810     
16811     block.html = replace(block.html)
16812       ('comment', /<!--[\s\S]*?-->/)
16813       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16814       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16815       (/tag/g, block._tag)
16816       ();
16817     
16818     block.paragraph = replace(block.paragraph)
16819       ('hr', block.hr)
16820       ('heading', block.heading)
16821       ('lheading', block.lheading)
16822       ('blockquote', block.blockquote)
16823       ('tag', '<' + block._tag)
16824       ('def', block.def)
16825       ();
16826     
16827     /**
16828      * Normal Block Grammar
16829      */
16830     
16831     block.normal = merge({}, block);
16832     
16833     /**
16834      * GFM Block Grammar
16835      */
16836     
16837     block.gfm = merge({}, block.normal, {
16838       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16839       paragraph: /^/,
16840       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16841     });
16842     
16843     block.gfm.paragraph = replace(block.paragraph)
16844       ('(?!', '(?!'
16845         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16846         + block.list.source.replace('\\1', '\\3') + '|')
16847       ();
16848     
16849     /**
16850      * GFM + Tables Block Grammar
16851      */
16852     
16853     block.tables = merge({}, block.gfm, {
16854       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16855       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16856     });
16857     
16858     /**
16859      * Block Lexer
16860      */
16861     
16862     function Lexer(options) {
16863       this.tokens = [];
16864       this.tokens.links = {};
16865       this.options = options || marked.defaults;
16866       this.rules = block.normal;
16867     
16868       if (this.options.gfm) {
16869         if (this.options.tables) {
16870           this.rules = block.tables;
16871         } else {
16872           this.rules = block.gfm;
16873         }
16874       }
16875     }
16876     
16877     /**
16878      * Expose Block Rules
16879      */
16880     
16881     Lexer.rules = block;
16882     
16883     /**
16884      * Static Lex Method
16885      */
16886     
16887     Lexer.lex = function(src, options) {
16888       var lexer = new Lexer(options);
16889       return lexer.lex(src);
16890     };
16891     
16892     /**
16893      * Preprocessing
16894      */
16895     
16896     Lexer.prototype.lex = function(src) {
16897       src = src
16898         .replace(/\r\n|\r/g, '\n')
16899         .replace(/\t/g, '    ')
16900         .replace(/\u00a0/g, ' ')
16901         .replace(/\u2424/g, '\n');
16902     
16903       return this.token(src, true);
16904     };
16905     
16906     /**
16907      * Lexing
16908      */
16909     
16910     Lexer.prototype.token = function(src, top, bq) {
16911       var src = src.replace(/^ +$/gm, '')
16912         , next
16913         , loose
16914         , cap
16915         , bull
16916         , b
16917         , item
16918         , space
16919         , i
16920         , l;
16921     
16922       while (src) {
16923         // newline
16924         if (cap = this.rules.newline.exec(src)) {
16925           src = src.substring(cap[0].length);
16926           if (cap[0].length > 1) {
16927             this.tokens.push({
16928               type: 'space'
16929             });
16930           }
16931         }
16932     
16933         // code
16934         if (cap = this.rules.code.exec(src)) {
16935           src = src.substring(cap[0].length);
16936           cap = cap[0].replace(/^ {4}/gm, '');
16937           this.tokens.push({
16938             type: 'code',
16939             text: !this.options.pedantic
16940               ? cap.replace(/\n+$/, '')
16941               : cap
16942           });
16943           continue;
16944         }
16945     
16946         // fences (gfm)
16947         if (cap = this.rules.fences.exec(src)) {
16948           src = src.substring(cap[0].length);
16949           this.tokens.push({
16950             type: 'code',
16951             lang: cap[2],
16952             text: cap[3] || ''
16953           });
16954           continue;
16955         }
16956     
16957         // heading
16958         if (cap = this.rules.heading.exec(src)) {
16959           src = src.substring(cap[0].length);
16960           this.tokens.push({
16961             type: 'heading',
16962             depth: cap[1].length,
16963             text: cap[2]
16964           });
16965           continue;
16966         }
16967     
16968         // table no leading pipe (gfm)
16969         if (top && (cap = this.rules.nptable.exec(src))) {
16970           src = src.substring(cap[0].length);
16971     
16972           item = {
16973             type: 'table',
16974             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16975             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16976             cells: cap[3].replace(/\n$/, '').split('\n')
16977           };
16978     
16979           for (i = 0; i < item.align.length; i++) {
16980             if (/^ *-+: *$/.test(item.align[i])) {
16981               item.align[i] = 'right';
16982             } else if (/^ *:-+: *$/.test(item.align[i])) {
16983               item.align[i] = 'center';
16984             } else if (/^ *:-+ *$/.test(item.align[i])) {
16985               item.align[i] = 'left';
16986             } else {
16987               item.align[i] = null;
16988             }
16989           }
16990     
16991           for (i = 0; i < item.cells.length; i++) {
16992             item.cells[i] = item.cells[i].split(/ *\| */);
16993           }
16994     
16995           this.tokens.push(item);
16996     
16997           continue;
16998         }
16999     
17000         // lheading
17001         if (cap = this.rules.lheading.exec(src)) {
17002           src = src.substring(cap[0].length);
17003           this.tokens.push({
17004             type: 'heading',
17005             depth: cap[2] === '=' ? 1 : 2,
17006             text: cap[1]
17007           });
17008           continue;
17009         }
17010     
17011         // hr
17012         if (cap = this.rules.hr.exec(src)) {
17013           src = src.substring(cap[0].length);
17014           this.tokens.push({
17015             type: 'hr'
17016           });
17017           continue;
17018         }
17019     
17020         // blockquote
17021         if (cap = this.rules.blockquote.exec(src)) {
17022           src = src.substring(cap[0].length);
17023     
17024           this.tokens.push({
17025             type: 'blockquote_start'
17026           });
17027     
17028           cap = cap[0].replace(/^ *> ?/gm, '');
17029     
17030           // Pass `top` to keep the current
17031           // "toplevel" state. This is exactly
17032           // how markdown.pl works.
17033           this.token(cap, top, true);
17034     
17035           this.tokens.push({
17036             type: 'blockquote_end'
17037           });
17038     
17039           continue;
17040         }
17041     
17042         // list
17043         if (cap = this.rules.list.exec(src)) {
17044           src = src.substring(cap[0].length);
17045           bull = cap[2];
17046     
17047           this.tokens.push({
17048             type: 'list_start',
17049             ordered: bull.length > 1
17050           });
17051     
17052           // Get each top-level item.
17053           cap = cap[0].match(this.rules.item);
17054     
17055           next = false;
17056           l = cap.length;
17057           i = 0;
17058     
17059           for (; i < l; i++) {
17060             item = cap[i];
17061     
17062             // Remove the list item's bullet
17063             // so it is seen as the next token.
17064             space = item.length;
17065             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17066     
17067             // Outdent whatever the
17068             // list item contains. Hacky.
17069             if (~item.indexOf('\n ')) {
17070               space -= item.length;
17071               item = !this.options.pedantic
17072                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17073                 : item.replace(/^ {1,4}/gm, '');
17074             }
17075     
17076             // Determine whether the next list item belongs here.
17077             // Backpedal if it does not belong in this list.
17078             if (this.options.smartLists && i !== l - 1) {
17079               b = block.bullet.exec(cap[i + 1])[0];
17080               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17081                 src = cap.slice(i + 1).join('\n') + src;
17082                 i = l - 1;
17083               }
17084             }
17085     
17086             // Determine whether item is loose or not.
17087             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17088             // for discount behavior.
17089             loose = next || /\n\n(?!\s*$)/.test(item);
17090             if (i !== l - 1) {
17091               next = item.charAt(item.length - 1) === '\n';
17092               if (!loose) { loose = next; }
17093             }
17094     
17095             this.tokens.push({
17096               type: loose
17097                 ? 'loose_item_start'
17098                 : 'list_item_start'
17099             });
17100     
17101             // Recurse.
17102             this.token(item, false, bq);
17103     
17104             this.tokens.push({
17105               type: 'list_item_end'
17106             });
17107           }
17108     
17109           this.tokens.push({
17110             type: 'list_end'
17111           });
17112     
17113           continue;
17114         }
17115     
17116         // html
17117         if (cap = this.rules.html.exec(src)) {
17118           src = src.substring(cap[0].length);
17119           this.tokens.push({
17120             type: this.options.sanitize
17121               ? 'paragraph'
17122               : 'html',
17123             pre: !this.options.sanitizer
17124               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17125             text: cap[0]
17126           });
17127           continue;
17128         }
17129     
17130         // def
17131         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17132           src = src.substring(cap[0].length);
17133           this.tokens.links[cap[1].toLowerCase()] = {
17134             href: cap[2],
17135             title: cap[3]
17136           };
17137           continue;
17138         }
17139     
17140         // table (gfm)
17141         if (top && (cap = this.rules.table.exec(src))) {
17142           src = src.substring(cap[0].length);
17143     
17144           item = {
17145             type: 'table',
17146             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17147             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17148             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17149           };
17150     
17151           for (i = 0; i < item.align.length; i++) {
17152             if (/^ *-+: *$/.test(item.align[i])) {
17153               item.align[i] = 'right';
17154             } else if (/^ *:-+: *$/.test(item.align[i])) {
17155               item.align[i] = 'center';
17156             } else if (/^ *:-+ *$/.test(item.align[i])) {
17157               item.align[i] = 'left';
17158             } else {
17159               item.align[i] = null;
17160             }
17161           }
17162     
17163           for (i = 0; i < item.cells.length; i++) {
17164             item.cells[i] = item.cells[i]
17165               .replace(/^ *\| *| *\| *$/g, '')
17166               .split(/ *\| */);
17167           }
17168     
17169           this.tokens.push(item);
17170     
17171           continue;
17172         }
17173     
17174         // top-level paragraph
17175         if (top && (cap = this.rules.paragraph.exec(src))) {
17176           src = src.substring(cap[0].length);
17177           this.tokens.push({
17178             type: 'paragraph',
17179             text: cap[1].charAt(cap[1].length - 1) === '\n'
17180               ? cap[1].slice(0, -1)
17181               : cap[1]
17182           });
17183           continue;
17184         }
17185     
17186         // text
17187         if (cap = this.rules.text.exec(src)) {
17188           // Top-level should never reach here.
17189           src = src.substring(cap[0].length);
17190           this.tokens.push({
17191             type: 'text',
17192             text: cap[0]
17193           });
17194           continue;
17195         }
17196     
17197         if (src) {
17198           throw new
17199             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17200         }
17201       }
17202     
17203       return this.tokens;
17204     };
17205     
17206     /**
17207      * Inline-Level Grammar
17208      */
17209     
17210     var inline = {
17211       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17212       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17213       url: noop,
17214       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17215       link: /^!?\[(inside)\]\(href\)/,
17216       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17217       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17218       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17219       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17220       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17221       br: /^ {2,}\n(?!\s*$)/,
17222       del: noop,
17223       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17224     };
17225     
17226     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17227     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17228     
17229     inline.link = replace(inline.link)
17230       ('inside', inline._inside)
17231       ('href', inline._href)
17232       ();
17233     
17234     inline.reflink = replace(inline.reflink)
17235       ('inside', inline._inside)
17236       ();
17237     
17238     /**
17239      * Normal Inline Grammar
17240      */
17241     
17242     inline.normal = merge({}, inline);
17243     
17244     /**
17245      * Pedantic Inline Grammar
17246      */
17247     
17248     inline.pedantic = merge({}, inline.normal, {
17249       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17250       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17251     });
17252     
17253     /**
17254      * GFM Inline Grammar
17255      */
17256     
17257     inline.gfm = merge({}, inline.normal, {
17258       escape: replace(inline.escape)('])', '~|])')(),
17259       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17260       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17261       text: replace(inline.text)
17262         (']|', '~]|')
17263         ('|', '|https?://|')
17264         ()
17265     });
17266     
17267     /**
17268      * GFM + Line Breaks Inline Grammar
17269      */
17270     
17271     inline.breaks = merge({}, inline.gfm, {
17272       br: replace(inline.br)('{2,}', '*')(),
17273       text: replace(inline.gfm.text)('{2,}', '*')()
17274     });
17275     
17276     /**
17277      * Inline Lexer & Compiler
17278      */
17279     
17280     function InlineLexer(links, options) {
17281       this.options = options || marked.defaults;
17282       this.links = links;
17283       this.rules = inline.normal;
17284       this.renderer = this.options.renderer || new Renderer;
17285       this.renderer.options = this.options;
17286     
17287       if (!this.links) {
17288         throw new
17289           Error('Tokens array requires a `links` property.');
17290       }
17291     
17292       if (this.options.gfm) {
17293         if (this.options.breaks) {
17294           this.rules = inline.breaks;
17295         } else {
17296           this.rules = inline.gfm;
17297         }
17298       } else if (this.options.pedantic) {
17299         this.rules = inline.pedantic;
17300       }
17301     }
17302     
17303     /**
17304      * Expose Inline Rules
17305      */
17306     
17307     InlineLexer.rules = inline;
17308     
17309     /**
17310      * Static Lexing/Compiling Method
17311      */
17312     
17313     InlineLexer.output = function(src, links, options) {
17314       var inline = new InlineLexer(links, options);
17315       return inline.output(src);
17316     };
17317     
17318     /**
17319      * Lexing/Compiling
17320      */
17321     
17322     InlineLexer.prototype.output = function(src) {
17323       var out = ''
17324         , link
17325         , text
17326         , href
17327         , cap;
17328     
17329       while (src) {
17330         // escape
17331         if (cap = this.rules.escape.exec(src)) {
17332           src = src.substring(cap[0].length);
17333           out += cap[1];
17334           continue;
17335         }
17336     
17337         // autolink
17338         if (cap = this.rules.autolink.exec(src)) {
17339           src = src.substring(cap[0].length);
17340           if (cap[2] === '@') {
17341             text = cap[1].charAt(6) === ':'
17342               ? this.mangle(cap[1].substring(7))
17343               : this.mangle(cap[1]);
17344             href = this.mangle('mailto:') + text;
17345           } else {
17346             text = escape(cap[1]);
17347             href = text;
17348           }
17349           out += this.renderer.link(href, null, text);
17350           continue;
17351         }
17352     
17353         // url (gfm)
17354         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17355           src = src.substring(cap[0].length);
17356           text = escape(cap[1]);
17357           href = text;
17358           out += this.renderer.link(href, null, text);
17359           continue;
17360         }
17361     
17362         // tag
17363         if (cap = this.rules.tag.exec(src)) {
17364           if (!this.inLink && /^<a /i.test(cap[0])) {
17365             this.inLink = true;
17366           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17367             this.inLink = false;
17368           }
17369           src = src.substring(cap[0].length);
17370           out += this.options.sanitize
17371             ? this.options.sanitizer
17372               ? this.options.sanitizer(cap[0])
17373               : escape(cap[0])
17374             : cap[0];
17375           continue;
17376         }
17377     
17378         // link
17379         if (cap = this.rules.link.exec(src)) {
17380           src = src.substring(cap[0].length);
17381           this.inLink = true;
17382           out += this.outputLink(cap, {
17383             href: cap[2],
17384             title: cap[3]
17385           });
17386           this.inLink = false;
17387           continue;
17388         }
17389     
17390         // reflink, nolink
17391         if ((cap = this.rules.reflink.exec(src))
17392             || (cap = this.rules.nolink.exec(src))) {
17393           src = src.substring(cap[0].length);
17394           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17395           link = this.links[link.toLowerCase()];
17396           if (!link || !link.href) {
17397             out += cap[0].charAt(0);
17398             src = cap[0].substring(1) + src;
17399             continue;
17400           }
17401           this.inLink = true;
17402           out += this.outputLink(cap, link);
17403           this.inLink = false;
17404           continue;
17405         }
17406     
17407         // strong
17408         if (cap = this.rules.strong.exec(src)) {
17409           src = src.substring(cap[0].length);
17410           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17411           continue;
17412         }
17413     
17414         // em
17415         if (cap = this.rules.em.exec(src)) {
17416           src = src.substring(cap[0].length);
17417           out += this.renderer.em(this.output(cap[2] || cap[1]));
17418           continue;
17419         }
17420     
17421         // code
17422         if (cap = this.rules.code.exec(src)) {
17423           src = src.substring(cap[0].length);
17424           out += this.renderer.codespan(escape(cap[2], true));
17425           continue;
17426         }
17427     
17428         // br
17429         if (cap = this.rules.br.exec(src)) {
17430           src = src.substring(cap[0].length);
17431           out += this.renderer.br();
17432           continue;
17433         }
17434     
17435         // del (gfm)
17436         if (cap = this.rules.del.exec(src)) {
17437           src = src.substring(cap[0].length);
17438           out += this.renderer.del(this.output(cap[1]));
17439           continue;
17440         }
17441     
17442         // text
17443         if (cap = this.rules.text.exec(src)) {
17444           src = src.substring(cap[0].length);
17445           out += this.renderer.text(escape(this.smartypants(cap[0])));
17446           continue;
17447         }
17448     
17449         if (src) {
17450           throw new
17451             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17452         }
17453       }
17454     
17455       return out;
17456     };
17457     
17458     /**
17459      * Compile Link
17460      */
17461     
17462     InlineLexer.prototype.outputLink = function(cap, link) {
17463       var href = escape(link.href)
17464         , title = link.title ? escape(link.title) : null;
17465     
17466       return cap[0].charAt(0) !== '!'
17467         ? this.renderer.link(href, title, this.output(cap[1]))
17468         : this.renderer.image(href, title, escape(cap[1]));
17469     };
17470     
17471     /**
17472      * Smartypants Transformations
17473      */
17474     
17475     InlineLexer.prototype.smartypants = function(text) {
17476       if (!this.options.smartypants)  { return text; }
17477       return text
17478         // em-dashes
17479         .replace(/---/g, '\u2014')
17480         // en-dashes
17481         .replace(/--/g, '\u2013')
17482         // opening singles
17483         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17484         // closing singles & apostrophes
17485         .replace(/'/g, '\u2019')
17486         // opening doubles
17487         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17488         // closing doubles
17489         .replace(/"/g, '\u201d')
17490         // ellipses
17491         .replace(/\.{3}/g, '\u2026');
17492     };
17493     
17494     /**
17495      * Mangle Links
17496      */
17497     
17498     InlineLexer.prototype.mangle = function(text) {
17499       if (!this.options.mangle) { return text; }
17500       var out = ''
17501         , l = text.length
17502         , i = 0
17503         , ch;
17504     
17505       for (; i < l; i++) {
17506         ch = text.charCodeAt(i);
17507         if (Math.random() > 0.5) {
17508           ch = 'x' + ch.toString(16);
17509         }
17510         out += '&#' + ch + ';';
17511       }
17512     
17513       return out;
17514     };
17515     
17516     /**
17517      * Renderer
17518      */
17519     
17520     function Renderer(options) {
17521       this.options = options || {};
17522     }
17523     
17524     Renderer.prototype.code = function(code, lang, escaped) {
17525       if (this.options.highlight) {
17526         var out = this.options.highlight(code, lang);
17527         if (out != null && out !== code) {
17528           escaped = true;
17529           code = out;
17530         }
17531       } else {
17532             // hack!!! - it's already escapeD?
17533             escaped = true;
17534       }
17535     
17536       if (!lang) {
17537         return '<pre><code>'
17538           + (escaped ? code : escape(code, true))
17539           + '\n</code></pre>';
17540       }
17541     
17542       return '<pre><code class="'
17543         + this.options.langPrefix
17544         + escape(lang, true)
17545         + '">'
17546         + (escaped ? code : escape(code, true))
17547         + '\n</code></pre>\n';
17548     };
17549     
17550     Renderer.prototype.blockquote = function(quote) {
17551       return '<blockquote>\n' + quote + '</blockquote>\n';
17552     };
17553     
17554     Renderer.prototype.html = function(html) {
17555       return html;
17556     };
17557     
17558     Renderer.prototype.heading = function(text, level, raw) {
17559       return '<h'
17560         + level
17561         + ' id="'
17562         + this.options.headerPrefix
17563         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17564         + '">'
17565         + text
17566         + '</h'
17567         + level
17568         + '>\n';
17569     };
17570     
17571     Renderer.prototype.hr = function() {
17572       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17573     };
17574     
17575     Renderer.prototype.list = function(body, ordered) {
17576       var type = ordered ? 'ol' : 'ul';
17577       return '<' + type + '>\n' + body + '</' + type + '>\n';
17578     };
17579     
17580     Renderer.prototype.listitem = function(text) {
17581       return '<li>' + text + '</li>\n';
17582     };
17583     
17584     Renderer.prototype.paragraph = function(text) {
17585       return '<p>' + text + '</p>\n';
17586     };
17587     
17588     Renderer.prototype.table = function(header, body) {
17589       return '<table class="table table-striped">\n'
17590         + '<thead>\n'
17591         + header
17592         + '</thead>\n'
17593         + '<tbody>\n'
17594         + body
17595         + '</tbody>\n'
17596         + '</table>\n';
17597     };
17598     
17599     Renderer.prototype.tablerow = function(content) {
17600       return '<tr>\n' + content + '</tr>\n';
17601     };
17602     
17603     Renderer.prototype.tablecell = function(content, flags) {
17604       var type = flags.header ? 'th' : 'td';
17605       var tag = flags.align
17606         ? '<' + type + ' style="text-align:' + flags.align + '">'
17607         : '<' + type + '>';
17608       return tag + content + '</' + type + '>\n';
17609     };
17610     
17611     // span level renderer
17612     Renderer.prototype.strong = function(text) {
17613       return '<strong>' + text + '</strong>';
17614     };
17615     
17616     Renderer.prototype.em = function(text) {
17617       return '<em>' + text + '</em>';
17618     };
17619     
17620     Renderer.prototype.codespan = function(text) {
17621       return '<code>' + text + '</code>';
17622     };
17623     
17624     Renderer.prototype.br = function() {
17625       return this.options.xhtml ? '<br/>' : '<br>';
17626     };
17627     
17628     Renderer.prototype.del = function(text) {
17629       return '<del>' + text + '</del>';
17630     };
17631     
17632     Renderer.prototype.link = function(href, title, text) {
17633       if (this.options.sanitize) {
17634         try {
17635           var prot = decodeURIComponent(unescape(href))
17636             .replace(/[^\w:]/g, '')
17637             .toLowerCase();
17638         } catch (e) {
17639           return '';
17640         }
17641         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17642           return '';
17643         }
17644       }
17645       var out = '<a href="' + href + '"';
17646       if (title) {
17647         out += ' title="' + title + '"';
17648       }
17649       out += '>' + text + '</a>';
17650       return out;
17651     };
17652     
17653     Renderer.prototype.image = function(href, title, text) {
17654       var out = '<img src="' + href + '" alt="' + text + '"';
17655       if (title) {
17656         out += ' title="' + title + '"';
17657       }
17658       out += this.options.xhtml ? '/>' : '>';
17659       return out;
17660     };
17661     
17662     Renderer.prototype.text = function(text) {
17663       return text;
17664     };
17665     
17666     /**
17667      * Parsing & Compiling
17668      */
17669     
17670     function Parser(options) {
17671       this.tokens = [];
17672       this.token = null;
17673       this.options = options || marked.defaults;
17674       this.options.renderer = this.options.renderer || new Renderer;
17675       this.renderer = this.options.renderer;
17676       this.renderer.options = this.options;
17677     }
17678     
17679     /**
17680      * Static Parse Method
17681      */
17682     
17683     Parser.parse = function(src, options, renderer) {
17684       var parser = new Parser(options, renderer);
17685       return parser.parse(src);
17686     };
17687     
17688     /**
17689      * Parse Loop
17690      */
17691     
17692     Parser.prototype.parse = function(src) {
17693       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17694       this.tokens = src.reverse();
17695     
17696       var out = '';
17697       while (this.next()) {
17698         out += this.tok();
17699       }
17700     
17701       return out;
17702     };
17703     
17704     /**
17705      * Next Token
17706      */
17707     
17708     Parser.prototype.next = function() {
17709       return this.token = this.tokens.pop();
17710     };
17711     
17712     /**
17713      * Preview Next Token
17714      */
17715     
17716     Parser.prototype.peek = function() {
17717       return this.tokens[this.tokens.length - 1] || 0;
17718     };
17719     
17720     /**
17721      * Parse Text Tokens
17722      */
17723     
17724     Parser.prototype.parseText = function() {
17725       var body = this.token.text;
17726     
17727       while (this.peek().type === 'text') {
17728         body += '\n' + this.next().text;
17729       }
17730     
17731       return this.inline.output(body);
17732     };
17733     
17734     /**
17735      * Parse Current Token
17736      */
17737     
17738     Parser.prototype.tok = function() {
17739       switch (this.token.type) {
17740         case 'space': {
17741           return '';
17742         }
17743         case 'hr': {
17744           return this.renderer.hr();
17745         }
17746         case 'heading': {
17747           return this.renderer.heading(
17748             this.inline.output(this.token.text),
17749             this.token.depth,
17750             this.token.text);
17751         }
17752         case 'code': {
17753           return this.renderer.code(this.token.text,
17754             this.token.lang,
17755             this.token.escaped);
17756         }
17757         case 'table': {
17758           var header = ''
17759             , body = ''
17760             , i
17761             , row
17762             , cell
17763             , flags
17764             , j;
17765     
17766           // header
17767           cell = '';
17768           for (i = 0; i < this.token.header.length; i++) {
17769             flags = { header: true, align: this.token.align[i] };
17770             cell += this.renderer.tablecell(
17771               this.inline.output(this.token.header[i]),
17772               { header: true, align: this.token.align[i] }
17773             );
17774           }
17775           header += this.renderer.tablerow(cell);
17776     
17777           for (i = 0; i < this.token.cells.length; i++) {
17778             row = this.token.cells[i];
17779     
17780             cell = '';
17781             for (j = 0; j < row.length; j++) {
17782               cell += this.renderer.tablecell(
17783                 this.inline.output(row[j]),
17784                 { header: false, align: this.token.align[j] }
17785               );
17786             }
17787     
17788             body += this.renderer.tablerow(cell);
17789           }
17790           return this.renderer.table(header, body);
17791         }
17792         case 'blockquote_start': {
17793           var body = '';
17794     
17795           while (this.next().type !== 'blockquote_end') {
17796             body += this.tok();
17797           }
17798     
17799           return this.renderer.blockquote(body);
17800         }
17801         case 'list_start': {
17802           var body = ''
17803             , ordered = this.token.ordered;
17804     
17805           while (this.next().type !== 'list_end') {
17806             body += this.tok();
17807           }
17808     
17809           return this.renderer.list(body, ordered);
17810         }
17811         case 'list_item_start': {
17812           var body = '';
17813     
17814           while (this.next().type !== 'list_item_end') {
17815             body += this.token.type === 'text'
17816               ? this.parseText()
17817               : this.tok();
17818           }
17819     
17820           return this.renderer.listitem(body);
17821         }
17822         case 'loose_item_start': {
17823           var body = '';
17824     
17825           while (this.next().type !== 'list_item_end') {
17826             body += this.tok();
17827           }
17828     
17829           return this.renderer.listitem(body);
17830         }
17831         case 'html': {
17832           var html = !this.token.pre && !this.options.pedantic
17833             ? this.inline.output(this.token.text)
17834             : this.token.text;
17835           return this.renderer.html(html);
17836         }
17837         case 'paragraph': {
17838           return this.renderer.paragraph(this.inline.output(this.token.text));
17839         }
17840         case 'text': {
17841           return this.renderer.paragraph(this.parseText());
17842         }
17843       }
17844     };
17845     
17846     /**
17847      * Helpers
17848      */
17849     
17850     function escape(html, encode) {
17851       return html
17852         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17853         .replace(/</g, '&lt;')
17854         .replace(/>/g, '&gt;')
17855         .replace(/"/g, '&quot;')
17856         .replace(/'/g, '&#39;');
17857     }
17858     
17859     function unescape(html) {
17860         // explicitly match decimal, hex, and named HTML entities 
17861       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17862         n = n.toLowerCase();
17863         if (n === 'colon') { return ':'; }
17864         if (n.charAt(0) === '#') {
17865           return n.charAt(1) === 'x'
17866             ? String.fromCharCode(parseInt(n.substring(2), 16))
17867             : String.fromCharCode(+n.substring(1));
17868         }
17869         return '';
17870       });
17871     }
17872     
17873     function replace(regex, opt) {
17874       regex = regex.source;
17875       opt = opt || '';
17876       return function self(name, val) {
17877         if (!name) { return new RegExp(regex, opt); }
17878         val = val.source || val;
17879         val = val.replace(/(^|[^\[])\^/g, '$1');
17880         regex = regex.replace(name, val);
17881         return self;
17882       };
17883     }
17884     
17885     function noop() {}
17886     noop.exec = noop;
17887     
17888     function merge(obj) {
17889       var i = 1
17890         , target
17891         , key;
17892     
17893       for (; i < arguments.length; i++) {
17894         target = arguments[i];
17895         for (key in target) {
17896           if (Object.prototype.hasOwnProperty.call(target, key)) {
17897             obj[key] = target[key];
17898           }
17899         }
17900       }
17901     
17902       return obj;
17903     }
17904     
17905     
17906     /**
17907      * Marked
17908      */
17909     
17910     function marked(src, opt, callback) {
17911       if (callback || typeof opt === 'function') {
17912         if (!callback) {
17913           callback = opt;
17914           opt = null;
17915         }
17916     
17917         opt = merge({}, marked.defaults, opt || {});
17918     
17919         var highlight = opt.highlight
17920           , tokens
17921           , pending
17922           , i = 0;
17923     
17924         try {
17925           tokens = Lexer.lex(src, opt)
17926         } catch (e) {
17927           return callback(e);
17928         }
17929     
17930         pending = tokens.length;
17931     
17932         var done = function(err) {
17933           if (err) {
17934             opt.highlight = highlight;
17935             return callback(err);
17936           }
17937     
17938           var out;
17939     
17940           try {
17941             out = Parser.parse(tokens, opt);
17942           } catch (e) {
17943             err = e;
17944           }
17945     
17946           opt.highlight = highlight;
17947     
17948           return err
17949             ? callback(err)
17950             : callback(null, out);
17951         };
17952     
17953         if (!highlight || highlight.length < 3) {
17954           return done();
17955         }
17956     
17957         delete opt.highlight;
17958     
17959         if (!pending) { return done(); }
17960     
17961         for (; i < tokens.length; i++) {
17962           (function(token) {
17963             if (token.type !== 'code') {
17964               return --pending || done();
17965             }
17966             return highlight(token.text, token.lang, function(err, code) {
17967               if (err) { return done(err); }
17968               if (code == null || code === token.text) {
17969                 return --pending || done();
17970               }
17971               token.text = code;
17972               token.escaped = true;
17973               --pending || done();
17974             });
17975           })(tokens[i]);
17976         }
17977     
17978         return;
17979       }
17980       try {
17981         if (opt) { opt = merge({}, marked.defaults, opt); }
17982         return Parser.parse(Lexer.lex(src, opt), opt);
17983       } catch (e) {
17984         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17985         if ((opt || marked.defaults).silent) {
17986           return '<p>An error occured:</p><pre>'
17987             + escape(e.message + '', true)
17988             + '</pre>';
17989         }
17990         throw e;
17991       }
17992     }
17993     
17994     /**
17995      * Options
17996      */
17997     
17998     marked.options =
17999     marked.setOptions = function(opt) {
18000       merge(marked.defaults, opt);
18001       return marked;
18002     };
18003     
18004     marked.defaults = {
18005       gfm: true,
18006       tables: true,
18007       breaks: false,
18008       pedantic: false,
18009       sanitize: false,
18010       sanitizer: null,
18011       mangle: true,
18012       smartLists: false,
18013       silent: false,
18014       highlight: null,
18015       langPrefix: 'lang-',
18016       smartypants: false,
18017       headerPrefix: '',
18018       renderer: new Renderer,
18019       xhtml: false
18020     };
18021     
18022     /**
18023      * Expose
18024      */
18025     
18026     marked.Parser = Parser;
18027     marked.parser = Parser.parse;
18028     
18029     marked.Renderer = Renderer;
18030     
18031     marked.Lexer = Lexer;
18032     marked.lexer = Lexer.lex;
18033     
18034     marked.InlineLexer = InlineLexer;
18035     marked.inlineLexer = InlineLexer.output;
18036     
18037     marked.parse = marked;
18038     
18039     Roo.Markdown.marked = marked;
18040
18041 })();/*
18042  * Based on:
18043  * Ext JS Library 1.1.1
18044  * Copyright(c) 2006-2007, Ext JS, LLC.
18045  *
18046  * Originally Released Under LGPL - original licence link has changed is not relivant.
18047  *
18048  * Fork - LGPL
18049  * <script type="text/javascript">
18050  */
18051
18052
18053
18054 /*
18055  * These classes are derivatives of the similarly named classes in the YUI Library.
18056  * The original license:
18057  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18058  * Code licensed under the BSD License:
18059  * http://developer.yahoo.net/yui/license.txt
18060  */
18061
18062 (function() {
18063
18064 var Event=Roo.EventManager;
18065 var Dom=Roo.lib.Dom;
18066
18067 /**
18068  * @class Roo.dd.DragDrop
18069  * @extends Roo.util.Observable
18070  * Defines the interface and base operation of items that that can be
18071  * dragged or can be drop targets.  It was designed to be extended, overriding
18072  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18073  * Up to three html elements can be associated with a DragDrop instance:
18074  * <ul>
18075  * <li>linked element: the element that is passed into the constructor.
18076  * This is the element which defines the boundaries for interaction with
18077  * other DragDrop objects.</li>
18078  * <li>handle element(s): The drag operation only occurs if the element that
18079  * was clicked matches a handle element.  By default this is the linked
18080  * element, but there are times that you will want only a portion of the
18081  * linked element to initiate the drag operation, and the setHandleElId()
18082  * method provides a way to define this.</li>
18083  * <li>drag element: this represents the element that would be moved along
18084  * with the cursor during a drag operation.  By default, this is the linked
18085  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18086  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18087  * </li>
18088  * </ul>
18089  * This class should not be instantiated until the onload event to ensure that
18090  * the associated elements are available.
18091  * The following would define a DragDrop obj that would interact with any
18092  * other DragDrop obj in the "group1" group:
18093  * <pre>
18094  *  dd = new Roo.dd.DragDrop("div1", "group1");
18095  * </pre>
18096  * Since none of the event handlers have been implemented, nothing would
18097  * actually happen if you were to run the code above.  Normally you would
18098  * override this class or one of the default implementations, but you can
18099  * also override the methods you want on an instance of the class...
18100  * <pre>
18101  *  dd.onDragDrop = function(e, id) {
18102  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18103  *  }
18104  * </pre>
18105  * @constructor
18106  * @param {String} id of the element that is linked to this instance
18107  * @param {String} sGroup the group of related DragDrop objects
18108  * @param {object} config an object containing configurable attributes
18109  *                Valid properties for DragDrop:
18110  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18111  */
18112 Roo.dd.DragDrop = function(id, sGroup, config) {
18113     if (id) {
18114         this.init(id, sGroup, config);
18115     }
18116     
18117 };
18118
18119 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18120
18121     /**
18122      * The id of the element associated with this object.  This is what we
18123      * refer to as the "linked element" because the size and position of
18124      * this element is used to determine when the drag and drop objects have
18125      * interacted.
18126      * @property id
18127      * @type String
18128      */
18129     id: null,
18130
18131     /**
18132      * Configuration attributes passed into the constructor
18133      * @property config
18134      * @type object
18135      */
18136     config: null,
18137
18138     /**
18139      * The id of the element that will be dragged.  By default this is same
18140      * as the linked element , but could be changed to another element. Ex:
18141      * Roo.dd.DDProxy
18142      * @property dragElId
18143      * @type String
18144      * @private
18145      */
18146     dragElId: null,
18147
18148     /**
18149      * the id of the element that initiates the drag operation.  By default
18150      * this is the linked element, but could be changed to be a child of this
18151      * element.  This lets us do things like only starting the drag when the
18152      * header element within the linked html element is clicked.
18153      * @property handleElId
18154      * @type String
18155      * @private
18156      */
18157     handleElId: null,
18158
18159     /**
18160      * An associative array of HTML tags that will be ignored if clicked.
18161      * @property invalidHandleTypes
18162      * @type {string: string}
18163      */
18164     invalidHandleTypes: null,
18165
18166     /**
18167      * An associative array of ids for elements that will be ignored if clicked
18168      * @property invalidHandleIds
18169      * @type {string: string}
18170      */
18171     invalidHandleIds: null,
18172
18173     /**
18174      * An indexted array of css class names for elements that will be ignored
18175      * if clicked.
18176      * @property invalidHandleClasses
18177      * @type string[]
18178      */
18179     invalidHandleClasses: null,
18180
18181     /**
18182      * The linked element's absolute X position at the time the drag was
18183      * started
18184      * @property startPageX
18185      * @type int
18186      * @private
18187      */
18188     startPageX: 0,
18189
18190     /**
18191      * The linked element's absolute X position at the time the drag was
18192      * started
18193      * @property startPageY
18194      * @type int
18195      * @private
18196      */
18197     startPageY: 0,
18198
18199     /**
18200      * The group defines a logical collection of DragDrop objects that are
18201      * related.  Instances only get events when interacting with other
18202      * DragDrop object in the same group.  This lets us define multiple
18203      * groups using a single DragDrop subclass if we want.
18204      * @property groups
18205      * @type {string: string}
18206      */
18207     groups: null,
18208
18209     /**
18210      * Individual drag/drop instances can be locked.  This will prevent
18211      * onmousedown start drag.
18212      * @property locked
18213      * @type boolean
18214      * @private
18215      */
18216     locked: false,
18217
18218     /**
18219      * Lock this instance
18220      * @method lock
18221      */
18222     lock: function() { this.locked = true; },
18223
18224     /**
18225      * Unlock this instace
18226      * @method unlock
18227      */
18228     unlock: function() { this.locked = false; },
18229
18230     /**
18231      * By default, all insances can be a drop target.  This can be disabled by
18232      * setting isTarget to false.
18233      * @method isTarget
18234      * @type boolean
18235      */
18236     isTarget: true,
18237
18238     /**
18239      * The padding configured for this drag and drop object for calculating
18240      * the drop zone intersection with this object.
18241      * @method padding
18242      * @type int[]
18243      */
18244     padding: null,
18245
18246     /**
18247      * Cached reference to the linked element
18248      * @property _domRef
18249      * @private
18250      */
18251     _domRef: null,
18252
18253     /**
18254      * Internal typeof flag
18255      * @property __ygDragDrop
18256      * @private
18257      */
18258     __ygDragDrop: true,
18259
18260     /**
18261      * Set to true when horizontal contraints are applied
18262      * @property constrainX
18263      * @type boolean
18264      * @private
18265      */
18266     constrainX: false,
18267
18268     /**
18269      * Set to true when vertical contraints are applied
18270      * @property constrainY
18271      * @type boolean
18272      * @private
18273      */
18274     constrainY: false,
18275
18276     /**
18277      * The left constraint
18278      * @property minX
18279      * @type int
18280      * @private
18281      */
18282     minX: 0,
18283
18284     /**
18285      * The right constraint
18286      * @property maxX
18287      * @type int
18288      * @private
18289      */
18290     maxX: 0,
18291
18292     /**
18293      * The up constraint
18294      * @property minY
18295      * @type int
18296      * @type int
18297      * @private
18298      */
18299     minY: 0,
18300
18301     /**
18302      * The down constraint
18303      * @property maxY
18304      * @type int
18305      * @private
18306      */
18307     maxY: 0,
18308
18309     /**
18310      * Maintain offsets when we resetconstraints.  Set to true when you want
18311      * the position of the element relative to its parent to stay the same
18312      * when the page changes
18313      *
18314      * @property maintainOffset
18315      * @type boolean
18316      */
18317     maintainOffset: false,
18318
18319     /**
18320      * Array of pixel locations the element will snap to if we specified a
18321      * horizontal graduation/interval.  This array is generated automatically
18322      * when you define a tick interval.
18323      * @property xTicks
18324      * @type int[]
18325      */
18326     xTicks: null,
18327
18328     /**
18329      * Array of pixel locations the element will snap to if we specified a
18330      * vertical graduation/interval.  This array is generated automatically
18331      * when you define a tick interval.
18332      * @property yTicks
18333      * @type int[]
18334      */
18335     yTicks: null,
18336
18337     /**
18338      * By default the drag and drop instance will only respond to the primary
18339      * button click (left button for a right-handed mouse).  Set to true to
18340      * allow drag and drop to start with any mouse click that is propogated
18341      * by the browser
18342      * @property primaryButtonOnly
18343      * @type boolean
18344      */
18345     primaryButtonOnly: true,
18346
18347     /**
18348      * The availabe property is false until the linked dom element is accessible.
18349      * @property available
18350      * @type boolean
18351      */
18352     available: false,
18353
18354     /**
18355      * By default, drags can only be initiated if the mousedown occurs in the
18356      * region the linked element is.  This is done in part to work around a
18357      * bug in some browsers that mis-report the mousedown if the previous
18358      * mouseup happened outside of the window.  This property is set to true
18359      * if outer handles are defined.
18360      *
18361      * @property hasOuterHandles
18362      * @type boolean
18363      * @default false
18364      */
18365     hasOuterHandles: false,
18366
18367     /**
18368      * Code that executes immediately before the startDrag event
18369      * @method b4StartDrag
18370      * @private
18371      */
18372     b4StartDrag: function(x, y) { },
18373
18374     /**
18375      * Abstract method called after a drag/drop object is clicked
18376      * and the drag or mousedown time thresholds have beeen met.
18377      * @method startDrag
18378      * @param {int} X click location
18379      * @param {int} Y click location
18380      */
18381     startDrag: function(x, y) { /* override this */ },
18382
18383     /**
18384      * Code that executes immediately before the onDrag event
18385      * @method b4Drag
18386      * @private
18387      */
18388     b4Drag: function(e) { },
18389
18390     /**
18391      * Abstract method called during the onMouseMove event while dragging an
18392      * object.
18393      * @method onDrag
18394      * @param {Event} e the mousemove event
18395      */
18396     onDrag: function(e) { /* override this */ },
18397
18398     /**
18399      * Abstract method called when this element fist begins hovering over
18400      * another DragDrop obj
18401      * @method onDragEnter
18402      * @param {Event} e the mousemove event
18403      * @param {String|DragDrop[]} id In POINT mode, the element
18404      * id this is hovering over.  In INTERSECT mode, an array of one or more
18405      * dragdrop items being hovered over.
18406      */
18407     onDragEnter: function(e, id) { /* override this */ },
18408
18409     /**
18410      * Code that executes immediately before the onDragOver event
18411      * @method b4DragOver
18412      * @private
18413      */
18414     b4DragOver: function(e) { },
18415
18416     /**
18417      * Abstract method called when this element is hovering over another
18418      * DragDrop obj
18419      * @method onDragOver
18420      * @param {Event} e the mousemove event
18421      * @param {String|DragDrop[]} id In POINT mode, the element
18422      * id this is hovering over.  In INTERSECT mode, an array of dd items
18423      * being hovered over.
18424      */
18425     onDragOver: function(e, id) { /* override this */ },
18426
18427     /**
18428      * Code that executes immediately before the onDragOut event
18429      * @method b4DragOut
18430      * @private
18431      */
18432     b4DragOut: function(e) { },
18433
18434     /**
18435      * Abstract method called when we are no longer hovering over an element
18436      * @method onDragOut
18437      * @param {Event} e the mousemove event
18438      * @param {String|DragDrop[]} id In POINT mode, the element
18439      * id this was hovering over.  In INTERSECT mode, an array of dd items
18440      * that the mouse is no longer over.
18441      */
18442     onDragOut: function(e, id) { /* override this */ },
18443
18444     /**
18445      * Code that executes immediately before the onDragDrop event
18446      * @method b4DragDrop
18447      * @private
18448      */
18449     b4DragDrop: function(e) { },
18450
18451     /**
18452      * Abstract method called when this item is dropped on another DragDrop
18453      * obj
18454      * @method onDragDrop
18455      * @param {Event} e the mouseup event
18456      * @param {String|DragDrop[]} id In POINT mode, the element
18457      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18458      * was dropped on.
18459      */
18460     onDragDrop: function(e, id) { /* override this */ },
18461
18462     /**
18463      * Abstract method called when this item is dropped on an area with no
18464      * drop target
18465      * @method onInvalidDrop
18466      * @param {Event} e the mouseup event
18467      */
18468     onInvalidDrop: function(e) { /* override this */ },
18469
18470     /**
18471      * Code that executes immediately before the endDrag event
18472      * @method b4EndDrag
18473      * @private
18474      */
18475     b4EndDrag: function(e) { },
18476
18477     /**
18478      * Fired when we are done dragging the object
18479      * @method endDrag
18480      * @param {Event} e the mouseup event
18481      */
18482     endDrag: function(e) { /* override this */ },
18483
18484     /**
18485      * Code executed immediately before the onMouseDown event
18486      * @method b4MouseDown
18487      * @param {Event} e the mousedown event
18488      * @private
18489      */
18490     b4MouseDown: function(e) {  },
18491
18492     /**
18493      * Event handler that fires when a drag/drop obj gets a mousedown
18494      * @method onMouseDown
18495      * @param {Event} e the mousedown event
18496      */
18497     onMouseDown: function(e) { /* override this */ },
18498
18499     /**
18500      * Event handler that fires when a drag/drop obj gets a mouseup
18501      * @method onMouseUp
18502      * @param {Event} e the mouseup event
18503      */
18504     onMouseUp: function(e) { /* override this */ },
18505
18506     /**
18507      * Override the onAvailable method to do what is needed after the initial
18508      * position was determined.
18509      * @method onAvailable
18510      */
18511     onAvailable: function () {
18512     },
18513
18514     /*
18515      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18516      * @type Object
18517      */
18518     defaultPadding : {left:0, right:0, top:0, bottom:0},
18519
18520     /*
18521      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18522  *
18523  * Usage:
18524  <pre><code>
18525  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18526                 { dragElId: "existingProxyDiv" });
18527  dd.startDrag = function(){
18528      this.constrainTo("parent-id");
18529  };
18530  </code></pre>
18531  * Or you can initalize it using the {@link Roo.Element} object:
18532  <pre><code>
18533  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18534      startDrag : function(){
18535          this.constrainTo("parent-id");
18536      }
18537  });
18538  </code></pre>
18539      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18540      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18541      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18542      * an object containing the sides to pad. For example: {right:10, bottom:10}
18543      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18544      */
18545     constrainTo : function(constrainTo, pad, inContent){
18546         if(typeof pad == "number"){
18547             pad = {left: pad, right:pad, top:pad, bottom:pad};
18548         }
18549         pad = pad || this.defaultPadding;
18550         var b = Roo.get(this.getEl()).getBox();
18551         var ce = Roo.get(constrainTo);
18552         var s = ce.getScroll();
18553         var c, cd = ce.dom;
18554         if(cd == document.body){
18555             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18556         }else{
18557             xy = ce.getXY();
18558             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18559         }
18560
18561
18562         var topSpace = b.y - c.y;
18563         var leftSpace = b.x - c.x;
18564
18565         this.resetConstraints();
18566         this.setXConstraint(leftSpace - (pad.left||0), // left
18567                 c.width - leftSpace - b.width - (pad.right||0) //right
18568         );
18569         this.setYConstraint(topSpace - (pad.top||0), //top
18570                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18571         );
18572     },
18573
18574     /**
18575      * Returns a reference to the linked element
18576      * @method getEl
18577      * @return {HTMLElement} the html element
18578      */
18579     getEl: function() {
18580         if (!this._domRef) {
18581             this._domRef = Roo.getDom(this.id);
18582         }
18583
18584         return this._domRef;
18585     },
18586
18587     /**
18588      * Returns a reference to the actual element to drag.  By default this is
18589      * the same as the html element, but it can be assigned to another
18590      * element. An example of this can be found in Roo.dd.DDProxy
18591      * @method getDragEl
18592      * @return {HTMLElement} the html element
18593      */
18594     getDragEl: function() {
18595         return Roo.getDom(this.dragElId);
18596     },
18597
18598     /**
18599      * Sets up the DragDrop object.  Must be called in the constructor of any
18600      * Roo.dd.DragDrop subclass
18601      * @method init
18602      * @param id the id of the linked element
18603      * @param {String} sGroup the group of related items
18604      * @param {object} config configuration attributes
18605      */
18606     init: function(id, sGroup, config) {
18607         this.initTarget(id, sGroup, config);
18608         if (!Roo.isTouch) {
18609             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18610         }
18611         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18612         // Event.on(this.id, "selectstart", Event.preventDefault);
18613     },
18614
18615     /**
18616      * Initializes Targeting functionality only... the object does not
18617      * get a mousedown handler.
18618      * @method initTarget
18619      * @param id the id of the linked element
18620      * @param {String} sGroup the group of related items
18621      * @param {object} config configuration attributes
18622      */
18623     initTarget: function(id, sGroup, config) {
18624
18625         // configuration attributes
18626         this.config = config || {};
18627
18628         // create a local reference to the drag and drop manager
18629         this.DDM = Roo.dd.DDM;
18630         // initialize the groups array
18631         this.groups = {};
18632
18633         // assume that we have an element reference instead of an id if the
18634         // parameter is not a string
18635         if (typeof id !== "string") {
18636             id = Roo.id(id);
18637         }
18638
18639         // set the id
18640         this.id = id;
18641
18642         // add to an interaction group
18643         this.addToGroup((sGroup) ? sGroup : "default");
18644
18645         // We don't want to register this as the handle with the manager
18646         // so we just set the id rather than calling the setter.
18647         this.handleElId = id;
18648
18649         // the linked element is the element that gets dragged by default
18650         this.setDragElId(id);
18651
18652         // by default, clicked anchors will not start drag operations.
18653         this.invalidHandleTypes = { A: "A" };
18654         this.invalidHandleIds = {};
18655         this.invalidHandleClasses = [];
18656
18657         this.applyConfig();
18658
18659         this.handleOnAvailable();
18660     },
18661
18662     /**
18663      * Applies the configuration parameters that were passed into the constructor.
18664      * This is supposed to happen at each level through the inheritance chain.  So
18665      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18666      * DragDrop in order to get all of the parameters that are available in
18667      * each object.
18668      * @method applyConfig
18669      */
18670     applyConfig: function() {
18671
18672         // configurable properties:
18673         //    padding, isTarget, maintainOffset, primaryButtonOnly
18674         this.padding           = this.config.padding || [0, 0, 0, 0];
18675         this.isTarget          = (this.config.isTarget !== false);
18676         this.maintainOffset    = (this.config.maintainOffset);
18677         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18678
18679     },
18680
18681     /**
18682      * Executed when the linked element is available
18683      * @method handleOnAvailable
18684      * @private
18685      */
18686     handleOnAvailable: function() {
18687         this.available = true;
18688         this.resetConstraints();
18689         this.onAvailable();
18690     },
18691
18692      /**
18693      * Configures the padding for the target zone in px.  Effectively expands
18694      * (or reduces) the virtual object size for targeting calculations.
18695      * Supports css-style shorthand; if only one parameter is passed, all sides
18696      * will have that padding, and if only two are passed, the top and bottom
18697      * will have the first param, the left and right the second.
18698      * @method setPadding
18699      * @param {int} iTop    Top pad
18700      * @param {int} iRight  Right pad
18701      * @param {int} iBot    Bot pad
18702      * @param {int} iLeft   Left pad
18703      */
18704     setPadding: function(iTop, iRight, iBot, iLeft) {
18705         // this.padding = [iLeft, iRight, iTop, iBot];
18706         if (!iRight && 0 !== iRight) {
18707             this.padding = [iTop, iTop, iTop, iTop];
18708         } else if (!iBot && 0 !== iBot) {
18709             this.padding = [iTop, iRight, iTop, iRight];
18710         } else {
18711             this.padding = [iTop, iRight, iBot, iLeft];
18712         }
18713     },
18714
18715     /**
18716      * Stores the initial placement of the linked element.
18717      * @method setInitialPosition
18718      * @param {int} diffX   the X offset, default 0
18719      * @param {int} diffY   the Y offset, default 0
18720      */
18721     setInitPosition: function(diffX, diffY) {
18722         var el = this.getEl();
18723
18724         if (!this.DDM.verifyEl(el)) {
18725             return;
18726         }
18727
18728         var dx = diffX || 0;
18729         var dy = diffY || 0;
18730
18731         var p = Dom.getXY( el );
18732
18733         this.initPageX = p[0] - dx;
18734         this.initPageY = p[1] - dy;
18735
18736         this.lastPageX = p[0];
18737         this.lastPageY = p[1];
18738
18739
18740         this.setStartPosition(p);
18741     },
18742
18743     /**
18744      * Sets the start position of the element.  This is set when the obj
18745      * is initialized, the reset when a drag is started.
18746      * @method setStartPosition
18747      * @param pos current position (from previous lookup)
18748      * @private
18749      */
18750     setStartPosition: function(pos) {
18751         var p = pos || Dom.getXY( this.getEl() );
18752         this.deltaSetXY = null;
18753
18754         this.startPageX = p[0];
18755         this.startPageY = p[1];
18756     },
18757
18758     /**
18759      * Add this instance to a group of related drag/drop objects.  All
18760      * instances belong to at least one group, and can belong to as many
18761      * groups as needed.
18762      * @method addToGroup
18763      * @param sGroup {string} the name of the group
18764      */
18765     addToGroup: function(sGroup) {
18766         this.groups[sGroup] = true;
18767         this.DDM.regDragDrop(this, sGroup);
18768     },
18769
18770     /**
18771      * Remove's this instance from the supplied interaction group
18772      * @method removeFromGroup
18773      * @param {string}  sGroup  The group to drop
18774      */
18775     removeFromGroup: function(sGroup) {
18776         if (this.groups[sGroup]) {
18777             delete this.groups[sGroup];
18778         }
18779
18780         this.DDM.removeDDFromGroup(this, sGroup);
18781     },
18782
18783     /**
18784      * Allows you to specify that an element other than the linked element
18785      * will be moved with the cursor during a drag
18786      * @method setDragElId
18787      * @param id {string} the id of the element that will be used to initiate the drag
18788      */
18789     setDragElId: function(id) {
18790         this.dragElId = id;
18791     },
18792
18793     /**
18794      * Allows you to specify a child of the linked element that should be
18795      * used to initiate the drag operation.  An example of this would be if
18796      * you have a content div with text and links.  Clicking anywhere in the
18797      * content area would normally start the drag operation.  Use this method
18798      * to specify that an element inside of the content div is the element
18799      * that starts the drag operation.
18800      * @method setHandleElId
18801      * @param id {string} the id of the element that will be used to
18802      * initiate the drag.
18803      */
18804     setHandleElId: function(id) {
18805         if (typeof id !== "string") {
18806             id = Roo.id(id);
18807         }
18808         this.handleElId = id;
18809         this.DDM.regHandle(this.id, id);
18810     },
18811
18812     /**
18813      * Allows you to set an element outside of the linked element as a drag
18814      * handle
18815      * @method setOuterHandleElId
18816      * @param id the id of the element that will be used to initiate the drag
18817      */
18818     setOuterHandleElId: function(id) {
18819         if (typeof id !== "string") {
18820             id = Roo.id(id);
18821         }
18822         Event.on(id, "mousedown",
18823                 this.handleMouseDown, this);
18824         this.setHandleElId(id);
18825
18826         this.hasOuterHandles = true;
18827     },
18828
18829     /**
18830      * Remove all drag and drop hooks for this element
18831      * @method unreg
18832      */
18833     unreg: function() {
18834         Event.un(this.id, "mousedown",
18835                 this.handleMouseDown);
18836         Event.un(this.id, "touchstart",
18837                 this.handleMouseDown);
18838         this._domRef = null;
18839         this.DDM._remove(this);
18840     },
18841
18842     destroy : function(){
18843         this.unreg();
18844     },
18845
18846     /**
18847      * Returns true if this instance is locked, or the drag drop mgr is locked
18848      * (meaning that all drag/drop is disabled on the page.)
18849      * @method isLocked
18850      * @return {boolean} true if this obj or all drag/drop is locked, else
18851      * false
18852      */
18853     isLocked: function() {
18854         return (this.DDM.isLocked() || this.locked);
18855     },
18856
18857     /**
18858      * Fired when this object is clicked
18859      * @method handleMouseDown
18860      * @param {Event} e
18861      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18862      * @private
18863      */
18864     handleMouseDown: function(e, oDD){
18865      
18866         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18867             //Roo.log('not touch/ button !=0');
18868             return;
18869         }
18870         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18871             return; // double touch..
18872         }
18873         
18874
18875         if (this.isLocked()) {
18876             //Roo.log('locked');
18877             return;
18878         }
18879
18880         this.DDM.refreshCache(this.groups);
18881 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18882         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18883         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18884             //Roo.log('no outer handes or not over target');
18885                 // do nothing.
18886         } else {
18887 //            Roo.log('check validator');
18888             if (this.clickValidator(e)) {
18889 //                Roo.log('validate success');
18890                 // set the initial element position
18891                 this.setStartPosition();
18892
18893
18894                 this.b4MouseDown(e);
18895                 this.onMouseDown(e);
18896
18897                 this.DDM.handleMouseDown(e, this);
18898
18899                 this.DDM.stopEvent(e);
18900             } else {
18901
18902
18903             }
18904         }
18905     },
18906
18907     clickValidator: function(e) {
18908         var target = e.getTarget();
18909         return ( this.isValidHandleChild(target) &&
18910                     (this.id == this.handleElId ||
18911                         this.DDM.handleWasClicked(target, this.id)) );
18912     },
18913
18914     /**
18915      * Allows you to specify a tag name that should not start a drag operation
18916      * when clicked.  This is designed to facilitate embedding links within a
18917      * drag handle that do something other than start the drag.
18918      * @method addInvalidHandleType
18919      * @param {string} tagName the type of element to exclude
18920      */
18921     addInvalidHandleType: function(tagName) {
18922         var type = tagName.toUpperCase();
18923         this.invalidHandleTypes[type] = type;
18924     },
18925
18926     /**
18927      * Lets you to specify an element id for a child of a drag handle
18928      * that should not initiate a drag
18929      * @method addInvalidHandleId
18930      * @param {string} id the element id of the element you wish to ignore
18931      */
18932     addInvalidHandleId: function(id) {
18933         if (typeof id !== "string") {
18934             id = Roo.id(id);
18935         }
18936         this.invalidHandleIds[id] = id;
18937     },
18938
18939     /**
18940      * Lets you specify a css class of elements that will not initiate a drag
18941      * @method addInvalidHandleClass
18942      * @param {string} cssClass the class of the elements you wish to ignore
18943      */
18944     addInvalidHandleClass: function(cssClass) {
18945         this.invalidHandleClasses.push(cssClass);
18946     },
18947
18948     /**
18949      * Unsets an excluded tag name set by addInvalidHandleType
18950      * @method removeInvalidHandleType
18951      * @param {string} tagName the type of element to unexclude
18952      */
18953     removeInvalidHandleType: function(tagName) {
18954         var type = tagName.toUpperCase();
18955         // this.invalidHandleTypes[type] = null;
18956         delete this.invalidHandleTypes[type];
18957     },
18958
18959     /**
18960      * Unsets an invalid handle id
18961      * @method removeInvalidHandleId
18962      * @param {string} id the id of the element to re-enable
18963      */
18964     removeInvalidHandleId: function(id) {
18965         if (typeof id !== "string") {
18966             id = Roo.id(id);
18967         }
18968         delete this.invalidHandleIds[id];
18969     },
18970
18971     /**
18972      * Unsets an invalid css class
18973      * @method removeInvalidHandleClass
18974      * @param {string} cssClass the class of the element(s) you wish to
18975      * re-enable
18976      */
18977     removeInvalidHandleClass: function(cssClass) {
18978         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18979             if (this.invalidHandleClasses[i] == cssClass) {
18980                 delete this.invalidHandleClasses[i];
18981             }
18982         }
18983     },
18984
18985     /**
18986      * Checks the tag exclusion list to see if this click should be ignored
18987      * @method isValidHandleChild
18988      * @param {HTMLElement} node the HTMLElement to evaluate
18989      * @return {boolean} true if this is a valid tag type, false if not
18990      */
18991     isValidHandleChild: function(node) {
18992
18993         var valid = true;
18994         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18995         var nodeName;
18996         try {
18997             nodeName = node.nodeName.toUpperCase();
18998         } catch(e) {
18999             nodeName = node.nodeName;
19000         }
19001         valid = valid && !this.invalidHandleTypes[nodeName];
19002         valid = valid && !this.invalidHandleIds[node.id];
19003
19004         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19005             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19006         }
19007
19008
19009         return valid;
19010
19011     },
19012
19013     /**
19014      * Create the array of horizontal tick marks if an interval was specified
19015      * in setXConstraint().
19016      * @method setXTicks
19017      * @private
19018      */
19019     setXTicks: function(iStartX, iTickSize) {
19020         this.xTicks = [];
19021         this.xTickSize = iTickSize;
19022
19023         var tickMap = {};
19024
19025         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19026             if (!tickMap[i]) {
19027                 this.xTicks[this.xTicks.length] = i;
19028                 tickMap[i] = true;
19029             }
19030         }
19031
19032         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19033             if (!tickMap[i]) {
19034                 this.xTicks[this.xTicks.length] = i;
19035                 tickMap[i] = true;
19036             }
19037         }
19038
19039         this.xTicks.sort(this.DDM.numericSort) ;
19040     },
19041
19042     /**
19043      * Create the array of vertical tick marks if an interval was specified in
19044      * setYConstraint().
19045      * @method setYTicks
19046      * @private
19047      */
19048     setYTicks: function(iStartY, iTickSize) {
19049         this.yTicks = [];
19050         this.yTickSize = iTickSize;
19051
19052         var tickMap = {};
19053
19054         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19055             if (!tickMap[i]) {
19056                 this.yTicks[this.yTicks.length] = i;
19057                 tickMap[i] = true;
19058             }
19059         }
19060
19061         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19062             if (!tickMap[i]) {
19063                 this.yTicks[this.yTicks.length] = i;
19064                 tickMap[i] = true;
19065             }
19066         }
19067
19068         this.yTicks.sort(this.DDM.numericSort) ;
19069     },
19070
19071     /**
19072      * By default, the element can be dragged any place on the screen.  Use
19073      * this method to limit the horizontal travel of the element.  Pass in
19074      * 0,0 for the parameters if you want to lock the drag to the y axis.
19075      * @method setXConstraint
19076      * @param {int} iLeft the number of pixels the element can move to the left
19077      * @param {int} iRight the number of pixels the element can move to the
19078      * right
19079      * @param {int} iTickSize optional parameter for specifying that the
19080      * element
19081      * should move iTickSize pixels at a time.
19082      */
19083     setXConstraint: function(iLeft, iRight, iTickSize) {
19084         this.leftConstraint = iLeft;
19085         this.rightConstraint = iRight;
19086
19087         this.minX = this.initPageX - iLeft;
19088         this.maxX = this.initPageX + iRight;
19089         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19090
19091         this.constrainX = true;
19092     },
19093
19094     /**
19095      * Clears any constraints applied to this instance.  Also clears ticks
19096      * since they can't exist independent of a constraint at this time.
19097      * @method clearConstraints
19098      */
19099     clearConstraints: function() {
19100         this.constrainX = false;
19101         this.constrainY = false;
19102         this.clearTicks();
19103     },
19104
19105     /**
19106      * Clears any tick interval defined for this instance
19107      * @method clearTicks
19108      */
19109     clearTicks: function() {
19110         this.xTicks = null;
19111         this.yTicks = null;
19112         this.xTickSize = 0;
19113         this.yTickSize = 0;
19114     },
19115
19116     /**
19117      * By default, the element can be dragged any place on the screen.  Set
19118      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19119      * parameters if you want to lock the drag to the x axis.
19120      * @method setYConstraint
19121      * @param {int} iUp the number of pixels the element can move up
19122      * @param {int} iDown the number of pixels the element can move down
19123      * @param {int} iTickSize optional parameter for specifying that the
19124      * element should move iTickSize pixels at a time.
19125      */
19126     setYConstraint: function(iUp, iDown, iTickSize) {
19127         this.topConstraint = iUp;
19128         this.bottomConstraint = iDown;
19129
19130         this.minY = this.initPageY - iUp;
19131         this.maxY = this.initPageY + iDown;
19132         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19133
19134         this.constrainY = true;
19135
19136     },
19137
19138     /**
19139      * resetConstraints must be called if you manually reposition a dd element.
19140      * @method resetConstraints
19141      * @param {boolean} maintainOffset
19142      */
19143     resetConstraints: function() {
19144
19145
19146         // Maintain offsets if necessary
19147         if (this.initPageX || this.initPageX === 0) {
19148             // figure out how much this thing has moved
19149             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19150             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19151
19152             this.setInitPosition(dx, dy);
19153
19154         // This is the first time we have detected the element's position
19155         } else {
19156             this.setInitPosition();
19157         }
19158
19159         if (this.constrainX) {
19160             this.setXConstraint( this.leftConstraint,
19161                                  this.rightConstraint,
19162                                  this.xTickSize        );
19163         }
19164
19165         if (this.constrainY) {
19166             this.setYConstraint( this.topConstraint,
19167                                  this.bottomConstraint,
19168                                  this.yTickSize         );
19169         }
19170     },
19171
19172     /**
19173      * Normally the drag element is moved pixel by pixel, but we can specify
19174      * that it move a number of pixels at a time.  This method resolves the
19175      * location when we have it set up like this.
19176      * @method getTick
19177      * @param {int} val where we want to place the object
19178      * @param {int[]} tickArray sorted array of valid points
19179      * @return {int} the closest tick
19180      * @private
19181      */
19182     getTick: function(val, tickArray) {
19183
19184         if (!tickArray) {
19185             // If tick interval is not defined, it is effectively 1 pixel,
19186             // so we return the value passed to us.
19187             return val;
19188         } else if (tickArray[0] >= val) {
19189             // The value is lower than the first tick, so we return the first
19190             // tick.
19191             return tickArray[0];
19192         } else {
19193             for (var i=0, len=tickArray.length; i<len; ++i) {
19194                 var next = i + 1;
19195                 if (tickArray[next] && tickArray[next] >= val) {
19196                     var diff1 = val - tickArray[i];
19197                     var diff2 = tickArray[next] - val;
19198                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19199                 }
19200             }
19201
19202             // The value is larger than the last tick, so we return the last
19203             // tick.
19204             return tickArray[tickArray.length - 1];
19205         }
19206     },
19207
19208     /**
19209      * toString method
19210      * @method toString
19211      * @return {string} string representation of the dd obj
19212      */
19213     toString: function() {
19214         return ("DragDrop " + this.id);
19215     }
19216
19217 });
19218
19219 })();
19220 /*
19221  * Based on:
19222  * Ext JS Library 1.1.1
19223  * Copyright(c) 2006-2007, Ext JS, LLC.
19224  *
19225  * Originally Released Under LGPL - original licence link has changed is not relivant.
19226  *
19227  * Fork - LGPL
19228  * <script type="text/javascript">
19229  */
19230
19231
19232 /**
19233  * The drag and drop utility provides a framework for building drag and drop
19234  * applications.  In addition to enabling drag and drop for specific elements,
19235  * the drag and drop elements are tracked by the manager class, and the
19236  * interactions between the various elements are tracked during the drag and
19237  * the implementing code is notified about these important moments.
19238  */
19239
19240 // Only load the library once.  Rewriting the manager class would orphan
19241 // existing drag and drop instances.
19242 if (!Roo.dd.DragDropMgr) {
19243
19244 /**
19245  * @class Roo.dd.DragDropMgr
19246  * DragDropMgr is a singleton that tracks the element interaction for
19247  * all DragDrop items in the window.  Generally, you will not call
19248  * this class directly, but it does have helper methods that could
19249  * be useful in your DragDrop implementations.
19250  * @singleton
19251  */
19252 Roo.dd.DragDropMgr = function() {
19253
19254     var Event = Roo.EventManager;
19255
19256     return {
19257
19258         /**
19259          * Two dimensional Array of registered DragDrop objects.  The first
19260          * dimension is the DragDrop item group, the second the DragDrop
19261          * object.
19262          * @property ids
19263          * @type {string: string}
19264          * @private
19265          * @static
19266          */
19267         ids: {},
19268
19269         /**
19270          * Array of element ids defined as drag handles.  Used to determine
19271          * if the element that generated the mousedown event is actually the
19272          * handle and not the html element itself.
19273          * @property handleIds
19274          * @type {string: string}
19275          * @private
19276          * @static
19277          */
19278         handleIds: {},
19279
19280         /**
19281          * the DragDrop object that is currently being dragged
19282          * @property dragCurrent
19283          * @type DragDrop
19284          * @private
19285          * @static
19286          **/
19287         dragCurrent: null,
19288
19289         /**
19290          * the DragDrop object(s) that are being hovered over
19291          * @property dragOvers
19292          * @type Array
19293          * @private
19294          * @static
19295          */
19296         dragOvers: {},
19297
19298         /**
19299          * the X distance between the cursor and the object being dragged
19300          * @property deltaX
19301          * @type int
19302          * @private
19303          * @static
19304          */
19305         deltaX: 0,
19306
19307         /**
19308          * the Y distance between the cursor and the object being dragged
19309          * @property deltaY
19310          * @type int
19311          * @private
19312          * @static
19313          */
19314         deltaY: 0,
19315
19316         /**
19317          * Flag to determine if we should prevent the default behavior of the
19318          * events we define. By default this is true, but this can be set to
19319          * false if you need the default behavior (not recommended)
19320          * @property preventDefault
19321          * @type boolean
19322          * @static
19323          */
19324         preventDefault: true,
19325
19326         /**
19327          * Flag to determine if we should stop the propagation of the events
19328          * we generate. This is true by default but you may want to set it to
19329          * false if the html element contains other features that require the
19330          * mouse click.
19331          * @property stopPropagation
19332          * @type boolean
19333          * @static
19334          */
19335         stopPropagation: true,
19336
19337         /**
19338          * Internal flag that is set to true when drag and drop has been
19339          * intialized
19340          * @property initialized
19341          * @private
19342          * @static
19343          */
19344         initalized: false,
19345
19346         /**
19347          * All drag and drop can be disabled.
19348          * @property locked
19349          * @private
19350          * @static
19351          */
19352         locked: false,
19353
19354         /**
19355          * Called the first time an element is registered.
19356          * @method init
19357          * @private
19358          * @static
19359          */
19360         init: function() {
19361             this.initialized = true;
19362         },
19363
19364         /**
19365          * In point mode, drag and drop interaction is defined by the
19366          * location of the cursor during the drag/drop
19367          * @property POINT
19368          * @type int
19369          * @static
19370          */
19371         POINT: 0,
19372
19373         /**
19374          * In intersect mode, drag and drop interactio nis defined by the
19375          * overlap of two or more drag and drop objects.
19376          * @property INTERSECT
19377          * @type int
19378          * @static
19379          */
19380         INTERSECT: 1,
19381
19382         /**
19383          * The current drag and drop mode.  Default: POINT
19384          * @property mode
19385          * @type int
19386          * @static
19387          */
19388         mode: 0,
19389
19390         /**
19391          * Runs method on all drag and drop objects
19392          * @method _execOnAll
19393          * @private
19394          * @static
19395          */
19396         _execOnAll: function(sMethod, args) {
19397             for (var i in this.ids) {
19398                 for (var j in this.ids[i]) {
19399                     var oDD = this.ids[i][j];
19400                     if (! this.isTypeOfDD(oDD)) {
19401                         continue;
19402                     }
19403                     oDD[sMethod].apply(oDD, args);
19404                 }
19405             }
19406         },
19407
19408         /**
19409          * Drag and drop initialization.  Sets up the global event handlers
19410          * @method _onLoad
19411          * @private
19412          * @static
19413          */
19414         _onLoad: function() {
19415
19416             this.init();
19417
19418             if (!Roo.isTouch) {
19419                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19420                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19421             }
19422             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19423             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19424             
19425             Event.on(window,   "unload",    this._onUnload, this, true);
19426             Event.on(window,   "resize",    this._onResize, this, true);
19427             // Event.on(window,   "mouseout",    this._test);
19428
19429         },
19430
19431         /**
19432          * Reset constraints on all drag and drop objs
19433          * @method _onResize
19434          * @private
19435          * @static
19436          */
19437         _onResize: function(e) {
19438             this._execOnAll("resetConstraints", []);
19439         },
19440
19441         /**
19442          * Lock all drag and drop functionality
19443          * @method lock
19444          * @static
19445          */
19446         lock: function() { this.locked = true; },
19447
19448         /**
19449          * Unlock all drag and drop functionality
19450          * @method unlock
19451          * @static
19452          */
19453         unlock: function() { this.locked = false; },
19454
19455         /**
19456          * Is drag and drop locked?
19457          * @method isLocked
19458          * @return {boolean} True if drag and drop is locked, false otherwise.
19459          * @static
19460          */
19461         isLocked: function() { return this.locked; },
19462
19463         /**
19464          * Location cache that is set for all drag drop objects when a drag is
19465          * initiated, cleared when the drag is finished.
19466          * @property locationCache
19467          * @private
19468          * @static
19469          */
19470         locationCache: {},
19471
19472         /**
19473          * Set useCache to false if you want to force object the lookup of each
19474          * drag and drop linked element constantly during a drag.
19475          * @property useCache
19476          * @type boolean
19477          * @static
19478          */
19479         useCache: true,
19480
19481         /**
19482          * The number of pixels that the mouse needs to move after the
19483          * mousedown before the drag is initiated.  Default=3;
19484          * @property clickPixelThresh
19485          * @type int
19486          * @static
19487          */
19488         clickPixelThresh: 3,
19489
19490         /**
19491          * The number of milliseconds after the mousedown event to initiate the
19492          * drag if we don't get a mouseup event. Default=1000
19493          * @property clickTimeThresh
19494          * @type int
19495          * @static
19496          */
19497         clickTimeThresh: 350,
19498
19499         /**
19500          * Flag that indicates that either the drag pixel threshold or the
19501          * mousdown time threshold has been met
19502          * @property dragThreshMet
19503          * @type boolean
19504          * @private
19505          * @static
19506          */
19507         dragThreshMet: false,
19508
19509         /**
19510          * Timeout used for the click time threshold
19511          * @property clickTimeout
19512          * @type Object
19513          * @private
19514          * @static
19515          */
19516         clickTimeout: null,
19517
19518         /**
19519          * The X position of the mousedown event stored for later use when a
19520          * drag threshold is met.
19521          * @property startX
19522          * @type int
19523          * @private
19524          * @static
19525          */
19526         startX: 0,
19527
19528         /**
19529          * The Y position of the mousedown event stored for later use when a
19530          * drag threshold is met.
19531          * @property startY
19532          * @type int
19533          * @private
19534          * @static
19535          */
19536         startY: 0,
19537
19538         /**
19539          * Each DragDrop instance must be registered with the DragDropMgr.
19540          * This is executed in DragDrop.init()
19541          * @method regDragDrop
19542          * @param {DragDrop} oDD the DragDrop object to register
19543          * @param {String} sGroup the name of the group this element belongs to
19544          * @static
19545          */
19546         regDragDrop: function(oDD, sGroup) {
19547             if (!this.initialized) { this.init(); }
19548
19549             if (!this.ids[sGroup]) {
19550                 this.ids[sGroup] = {};
19551             }
19552             this.ids[sGroup][oDD.id] = oDD;
19553         },
19554
19555         /**
19556          * Removes the supplied dd instance from the supplied group. Executed
19557          * by DragDrop.removeFromGroup, so don't call this function directly.
19558          * @method removeDDFromGroup
19559          * @private
19560          * @static
19561          */
19562         removeDDFromGroup: function(oDD, sGroup) {
19563             if (!this.ids[sGroup]) {
19564                 this.ids[sGroup] = {};
19565             }
19566
19567             var obj = this.ids[sGroup];
19568             if (obj && obj[oDD.id]) {
19569                 delete obj[oDD.id];
19570             }
19571         },
19572
19573         /**
19574          * Unregisters a drag and drop item.  This is executed in
19575          * DragDrop.unreg, use that method instead of calling this directly.
19576          * @method _remove
19577          * @private
19578          * @static
19579          */
19580         _remove: function(oDD) {
19581             for (var g in oDD.groups) {
19582                 if (g && this.ids[g][oDD.id]) {
19583                     delete this.ids[g][oDD.id];
19584                 }
19585             }
19586             delete this.handleIds[oDD.id];
19587         },
19588
19589         /**
19590          * Each DragDrop handle element must be registered.  This is done
19591          * automatically when executing DragDrop.setHandleElId()
19592          * @method regHandle
19593          * @param {String} sDDId the DragDrop id this element is a handle for
19594          * @param {String} sHandleId the id of the element that is the drag
19595          * handle
19596          * @static
19597          */
19598         regHandle: function(sDDId, sHandleId) {
19599             if (!this.handleIds[sDDId]) {
19600                 this.handleIds[sDDId] = {};
19601             }
19602             this.handleIds[sDDId][sHandleId] = sHandleId;
19603         },
19604
19605         /**
19606          * Utility function to determine if a given element has been
19607          * registered as a drag drop item.
19608          * @method isDragDrop
19609          * @param {String} id the element id to check
19610          * @return {boolean} true if this element is a DragDrop item,
19611          * false otherwise
19612          * @static
19613          */
19614         isDragDrop: function(id) {
19615             return ( this.getDDById(id) ) ? true : false;
19616         },
19617
19618         /**
19619          * Returns the drag and drop instances that are in all groups the
19620          * passed in instance belongs to.
19621          * @method getRelated
19622          * @param {DragDrop} p_oDD the obj to get related data for
19623          * @param {boolean} bTargetsOnly if true, only return targetable objs
19624          * @return {DragDrop[]} the related instances
19625          * @static
19626          */
19627         getRelated: function(p_oDD, bTargetsOnly) {
19628             var oDDs = [];
19629             for (var i in p_oDD.groups) {
19630                 for (j in this.ids[i]) {
19631                     var dd = this.ids[i][j];
19632                     if (! this.isTypeOfDD(dd)) {
19633                         continue;
19634                     }
19635                     if (!bTargetsOnly || dd.isTarget) {
19636                         oDDs[oDDs.length] = dd;
19637                     }
19638                 }
19639             }
19640
19641             return oDDs;
19642         },
19643
19644         /**
19645          * Returns true if the specified dd target is a legal target for
19646          * the specifice drag obj
19647          * @method isLegalTarget
19648          * @param {DragDrop} the drag obj
19649          * @param {DragDrop} the target
19650          * @return {boolean} true if the target is a legal target for the
19651          * dd obj
19652          * @static
19653          */
19654         isLegalTarget: function (oDD, oTargetDD) {
19655             var targets = this.getRelated(oDD, true);
19656             for (var i=0, len=targets.length;i<len;++i) {
19657                 if (targets[i].id == oTargetDD.id) {
19658                     return true;
19659                 }
19660             }
19661
19662             return false;
19663         },
19664
19665         /**
19666          * My goal is to be able to transparently determine if an object is
19667          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19668          * returns "object", oDD.constructor.toString() always returns
19669          * "DragDrop" and not the name of the subclass.  So for now it just
19670          * evaluates a well-known variable in DragDrop.
19671          * @method isTypeOfDD
19672          * @param {Object} the object to evaluate
19673          * @return {boolean} true if typeof oDD = DragDrop
19674          * @static
19675          */
19676         isTypeOfDD: function (oDD) {
19677             return (oDD && oDD.__ygDragDrop);
19678         },
19679
19680         /**
19681          * Utility function to determine if a given element has been
19682          * registered as a drag drop handle for the given Drag Drop object.
19683          * @method isHandle
19684          * @param {String} id the element id to check
19685          * @return {boolean} true if this element is a DragDrop handle, false
19686          * otherwise
19687          * @static
19688          */
19689         isHandle: function(sDDId, sHandleId) {
19690             return ( this.handleIds[sDDId] &&
19691                             this.handleIds[sDDId][sHandleId] );
19692         },
19693
19694         /**
19695          * Returns the DragDrop instance for a given id
19696          * @method getDDById
19697          * @param {String} id the id of the DragDrop object
19698          * @return {DragDrop} the drag drop object, null if it is not found
19699          * @static
19700          */
19701         getDDById: function(id) {
19702             for (var i in this.ids) {
19703                 if (this.ids[i][id]) {
19704                     return this.ids[i][id];
19705                 }
19706             }
19707             return null;
19708         },
19709
19710         /**
19711          * Fired after a registered DragDrop object gets the mousedown event.
19712          * Sets up the events required to track the object being dragged
19713          * @method handleMouseDown
19714          * @param {Event} e the event
19715          * @param oDD the DragDrop object being dragged
19716          * @private
19717          * @static
19718          */
19719         handleMouseDown: function(e, oDD) {
19720             if(Roo.QuickTips){
19721                 Roo.QuickTips.disable();
19722             }
19723             this.currentTarget = e.getTarget();
19724
19725             this.dragCurrent = oDD;
19726
19727             var el = oDD.getEl();
19728
19729             // track start position
19730             this.startX = e.getPageX();
19731             this.startY = e.getPageY();
19732
19733             this.deltaX = this.startX - el.offsetLeft;
19734             this.deltaY = this.startY - el.offsetTop;
19735
19736             this.dragThreshMet = false;
19737
19738             this.clickTimeout = setTimeout(
19739                     function() {
19740                         var DDM = Roo.dd.DDM;
19741                         DDM.startDrag(DDM.startX, DDM.startY);
19742                     },
19743                     this.clickTimeThresh );
19744         },
19745
19746         /**
19747          * Fired when either the drag pixel threshol or the mousedown hold
19748          * time threshold has been met.
19749          * @method startDrag
19750          * @param x {int} the X position of the original mousedown
19751          * @param y {int} the Y position of the original mousedown
19752          * @static
19753          */
19754         startDrag: function(x, y) {
19755             clearTimeout(this.clickTimeout);
19756             if (this.dragCurrent) {
19757                 this.dragCurrent.b4StartDrag(x, y);
19758                 this.dragCurrent.startDrag(x, y);
19759             }
19760             this.dragThreshMet = true;
19761         },
19762
19763         /**
19764          * Internal function to handle the mouseup event.  Will be invoked
19765          * from the context of the document.
19766          * @method handleMouseUp
19767          * @param {Event} e the event
19768          * @private
19769          * @static
19770          */
19771         handleMouseUp: function(e) {
19772
19773             if(Roo.QuickTips){
19774                 Roo.QuickTips.enable();
19775             }
19776             if (! this.dragCurrent) {
19777                 return;
19778             }
19779
19780             clearTimeout(this.clickTimeout);
19781
19782             if (this.dragThreshMet) {
19783                 this.fireEvents(e, true);
19784             } else {
19785             }
19786
19787             this.stopDrag(e);
19788
19789             this.stopEvent(e);
19790         },
19791
19792         /**
19793          * Utility to stop event propagation and event default, if these
19794          * features are turned on.
19795          * @method stopEvent
19796          * @param {Event} e the event as returned by this.getEvent()
19797          * @static
19798          */
19799         stopEvent: function(e){
19800             if(this.stopPropagation) {
19801                 e.stopPropagation();
19802             }
19803
19804             if (this.preventDefault) {
19805                 e.preventDefault();
19806             }
19807         },
19808
19809         /**
19810          * Internal function to clean up event handlers after the drag
19811          * operation is complete
19812          * @method stopDrag
19813          * @param {Event} e the event
19814          * @private
19815          * @static
19816          */
19817         stopDrag: function(e) {
19818             // Fire the drag end event for the item that was dragged
19819             if (this.dragCurrent) {
19820                 if (this.dragThreshMet) {
19821                     this.dragCurrent.b4EndDrag(e);
19822                     this.dragCurrent.endDrag(e);
19823                 }
19824
19825                 this.dragCurrent.onMouseUp(e);
19826             }
19827
19828             this.dragCurrent = null;
19829             this.dragOvers = {};
19830         },
19831
19832         /**
19833          * Internal function to handle the mousemove event.  Will be invoked
19834          * from the context of the html element.
19835          *
19836          * @TODO figure out what we can do about mouse events lost when the
19837          * user drags objects beyond the window boundary.  Currently we can
19838          * detect this in internet explorer by verifying that the mouse is
19839          * down during the mousemove event.  Firefox doesn't give us the
19840          * button state on the mousemove event.
19841          * @method handleMouseMove
19842          * @param {Event} e the event
19843          * @private
19844          * @static
19845          */
19846         handleMouseMove: function(e) {
19847             if (! this.dragCurrent) {
19848                 return true;
19849             }
19850
19851             // var button = e.which || e.button;
19852
19853             // check for IE mouseup outside of page boundary
19854             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19855                 this.stopEvent(e);
19856                 return this.handleMouseUp(e);
19857             }
19858
19859             if (!this.dragThreshMet) {
19860                 var diffX = Math.abs(this.startX - e.getPageX());
19861                 var diffY = Math.abs(this.startY - e.getPageY());
19862                 if (diffX > this.clickPixelThresh ||
19863                             diffY > this.clickPixelThresh) {
19864                     this.startDrag(this.startX, this.startY);
19865                 }
19866             }
19867
19868             if (this.dragThreshMet) {
19869                 this.dragCurrent.b4Drag(e);
19870                 this.dragCurrent.onDrag(e);
19871                 if(!this.dragCurrent.moveOnly){
19872                     this.fireEvents(e, false);
19873                 }
19874             }
19875
19876             this.stopEvent(e);
19877
19878             return true;
19879         },
19880
19881         /**
19882          * Iterates over all of the DragDrop elements to find ones we are
19883          * hovering over or dropping on
19884          * @method fireEvents
19885          * @param {Event} e the event
19886          * @param {boolean} isDrop is this a drop op or a mouseover op?
19887          * @private
19888          * @static
19889          */
19890         fireEvents: function(e, isDrop) {
19891             var dc = this.dragCurrent;
19892
19893             // If the user did the mouse up outside of the window, we could
19894             // get here even though we have ended the drag.
19895             if (!dc || dc.isLocked()) {
19896                 return;
19897             }
19898
19899             var pt = e.getPoint();
19900
19901             // cache the previous dragOver array
19902             var oldOvers = [];
19903
19904             var outEvts   = [];
19905             var overEvts  = [];
19906             var dropEvts  = [];
19907             var enterEvts = [];
19908
19909             // Check to see if the object(s) we were hovering over is no longer
19910             // being hovered over so we can fire the onDragOut event
19911             for (var i in this.dragOvers) {
19912
19913                 var ddo = this.dragOvers[i];
19914
19915                 if (! this.isTypeOfDD(ddo)) {
19916                     continue;
19917                 }
19918
19919                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19920                     outEvts.push( ddo );
19921                 }
19922
19923                 oldOvers[i] = true;
19924                 delete this.dragOvers[i];
19925             }
19926
19927             for (var sGroup in dc.groups) {
19928
19929                 if ("string" != typeof sGroup) {
19930                     continue;
19931                 }
19932
19933                 for (i in this.ids[sGroup]) {
19934                     var oDD = this.ids[sGroup][i];
19935                     if (! this.isTypeOfDD(oDD)) {
19936                         continue;
19937                     }
19938
19939                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19940                         if (this.isOverTarget(pt, oDD, this.mode)) {
19941                             // look for drop interactions
19942                             if (isDrop) {
19943                                 dropEvts.push( oDD );
19944                             // look for drag enter and drag over interactions
19945                             } else {
19946
19947                                 // initial drag over: dragEnter fires
19948                                 if (!oldOvers[oDD.id]) {
19949                                     enterEvts.push( oDD );
19950                                 // subsequent drag overs: dragOver fires
19951                                 } else {
19952                                     overEvts.push( oDD );
19953                                 }
19954
19955                                 this.dragOvers[oDD.id] = oDD;
19956                             }
19957                         }
19958                     }
19959                 }
19960             }
19961
19962             if (this.mode) {
19963                 if (outEvts.length) {
19964                     dc.b4DragOut(e, outEvts);
19965                     dc.onDragOut(e, outEvts);
19966                 }
19967
19968                 if (enterEvts.length) {
19969                     dc.onDragEnter(e, enterEvts);
19970                 }
19971
19972                 if (overEvts.length) {
19973                     dc.b4DragOver(e, overEvts);
19974                     dc.onDragOver(e, overEvts);
19975                 }
19976
19977                 if (dropEvts.length) {
19978                     dc.b4DragDrop(e, dropEvts);
19979                     dc.onDragDrop(e, dropEvts);
19980                 }
19981
19982             } else {
19983                 // fire dragout events
19984                 var len = 0;
19985                 for (i=0, len=outEvts.length; i<len; ++i) {
19986                     dc.b4DragOut(e, outEvts[i].id);
19987                     dc.onDragOut(e, outEvts[i].id);
19988                 }
19989
19990                 // fire enter events
19991                 for (i=0,len=enterEvts.length; i<len; ++i) {
19992                     // dc.b4DragEnter(e, oDD.id);
19993                     dc.onDragEnter(e, enterEvts[i].id);
19994                 }
19995
19996                 // fire over events
19997                 for (i=0,len=overEvts.length; i<len; ++i) {
19998                     dc.b4DragOver(e, overEvts[i].id);
19999                     dc.onDragOver(e, overEvts[i].id);
20000                 }
20001
20002                 // fire drop events
20003                 for (i=0, len=dropEvts.length; i<len; ++i) {
20004                     dc.b4DragDrop(e, dropEvts[i].id);
20005                     dc.onDragDrop(e, dropEvts[i].id);
20006                 }
20007
20008             }
20009
20010             // notify about a drop that did not find a target
20011             if (isDrop && !dropEvts.length) {
20012                 dc.onInvalidDrop(e);
20013             }
20014
20015         },
20016
20017         /**
20018          * Helper function for getting the best match from the list of drag
20019          * and drop objects returned by the drag and drop events when we are
20020          * in INTERSECT mode.  It returns either the first object that the
20021          * cursor is over, or the object that has the greatest overlap with
20022          * the dragged element.
20023          * @method getBestMatch
20024          * @param  {DragDrop[]} dds The array of drag and drop objects
20025          * targeted
20026          * @return {DragDrop}       The best single match
20027          * @static
20028          */
20029         getBestMatch: function(dds) {
20030             var winner = null;
20031             // Return null if the input is not what we expect
20032             //if (!dds || !dds.length || dds.length == 0) {
20033                // winner = null;
20034             // If there is only one item, it wins
20035             //} else if (dds.length == 1) {
20036
20037             var len = dds.length;
20038
20039             if (len == 1) {
20040                 winner = dds[0];
20041             } else {
20042                 // Loop through the targeted items
20043                 for (var i=0; i<len; ++i) {
20044                     var dd = dds[i];
20045                     // If the cursor is over the object, it wins.  If the
20046                     // cursor is over multiple matches, the first one we come
20047                     // to wins.
20048                     if (dd.cursorIsOver) {
20049                         winner = dd;
20050                         break;
20051                     // Otherwise the object with the most overlap wins
20052                     } else {
20053                         if (!winner ||
20054                             winner.overlap.getArea() < dd.overlap.getArea()) {
20055                             winner = dd;
20056                         }
20057                     }
20058                 }
20059             }
20060
20061             return winner;
20062         },
20063
20064         /**
20065          * Refreshes the cache of the top-left and bottom-right points of the
20066          * drag and drop objects in the specified group(s).  This is in the
20067          * format that is stored in the drag and drop instance, so typical
20068          * usage is:
20069          * <code>
20070          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20071          * </code>
20072          * Alternatively:
20073          * <code>
20074          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20075          * </code>
20076          * @TODO this really should be an indexed array.  Alternatively this
20077          * method could accept both.
20078          * @method refreshCache
20079          * @param {Object} groups an associative array of groups to refresh
20080          * @static
20081          */
20082         refreshCache: function(groups) {
20083             for (var sGroup in groups) {
20084                 if ("string" != typeof sGroup) {
20085                     continue;
20086                 }
20087                 for (var i in this.ids[sGroup]) {
20088                     var oDD = this.ids[sGroup][i];
20089
20090                     if (this.isTypeOfDD(oDD)) {
20091                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20092                         var loc = this.getLocation(oDD);
20093                         if (loc) {
20094                             this.locationCache[oDD.id] = loc;
20095                         } else {
20096                             delete this.locationCache[oDD.id];
20097                             // this will unregister the drag and drop object if
20098                             // the element is not in a usable state
20099                             // oDD.unreg();
20100                         }
20101                     }
20102                 }
20103             }
20104         },
20105
20106         /**
20107          * This checks to make sure an element exists and is in the DOM.  The
20108          * main purpose is to handle cases where innerHTML is used to remove
20109          * drag and drop objects from the DOM.  IE provides an 'unspecified
20110          * error' when trying to access the offsetParent of such an element
20111          * @method verifyEl
20112          * @param {HTMLElement} el the element to check
20113          * @return {boolean} true if the element looks usable
20114          * @static
20115          */
20116         verifyEl: function(el) {
20117             if (el) {
20118                 var parent;
20119                 if(Roo.isIE){
20120                     try{
20121                         parent = el.offsetParent;
20122                     }catch(e){}
20123                 }else{
20124                     parent = el.offsetParent;
20125                 }
20126                 if (parent) {
20127                     return true;
20128                 }
20129             }
20130
20131             return false;
20132         },
20133
20134         /**
20135          * Returns a Region object containing the drag and drop element's position
20136          * and size, including the padding configured for it
20137          * @method getLocation
20138          * @param {DragDrop} oDD the drag and drop object to get the
20139          *                       location for
20140          * @return {Roo.lib.Region} a Region object representing the total area
20141          *                             the element occupies, including any padding
20142          *                             the instance is configured for.
20143          * @static
20144          */
20145         getLocation: function(oDD) {
20146             if (! this.isTypeOfDD(oDD)) {
20147                 return null;
20148             }
20149
20150             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20151
20152             try {
20153                 pos= Roo.lib.Dom.getXY(el);
20154             } catch (e) { }
20155
20156             if (!pos) {
20157                 return null;
20158             }
20159
20160             x1 = pos[0];
20161             x2 = x1 + el.offsetWidth;
20162             y1 = pos[1];
20163             y2 = y1 + el.offsetHeight;
20164
20165             t = y1 - oDD.padding[0];
20166             r = x2 + oDD.padding[1];
20167             b = y2 + oDD.padding[2];
20168             l = x1 - oDD.padding[3];
20169
20170             return new Roo.lib.Region( t, r, b, l );
20171         },
20172
20173         /**
20174          * Checks the cursor location to see if it over the target
20175          * @method isOverTarget
20176          * @param {Roo.lib.Point} pt The point to evaluate
20177          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20178          * @return {boolean} true if the mouse is over the target
20179          * @private
20180          * @static
20181          */
20182         isOverTarget: function(pt, oTarget, intersect) {
20183             // use cache if available
20184             var loc = this.locationCache[oTarget.id];
20185             if (!loc || !this.useCache) {
20186                 loc = this.getLocation(oTarget);
20187                 this.locationCache[oTarget.id] = loc;
20188
20189             }
20190
20191             if (!loc) {
20192                 return false;
20193             }
20194
20195             oTarget.cursorIsOver = loc.contains( pt );
20196
20197             // DragDrop is using this as a sanity check for the initial mousedown
20198             // in this case we are done.  In POINT mode, if the drag obj has no
20199             // contraints, we are also done. Otherwise we need to evaluate the
20200             // location of the target as related to the actual location of the
20201             // dragged element.
20202             var dc = this.dragCurrent;
20203             if (!dc || !dc.getTargetCoord ||
20204                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20205                 return oTarget.cursorIsOver;
20206             }
20207
20208             oTarget.overlap = null;
20209
20210             // Get the current location of the drag element, this is the
20211             // location of the mouse event less the delta that represents
20212             // where the original mousedown happened on the element.  We
20213             // need to consider constraints and ticks as well.
20214             var pos = dc.getTargetCoord(pt.x, pt.y);
20215
20216             var el = dc.getDragEl();
20217             var curRegion = new Roo.lib.Region( pos.y,
20218                                                    pos.x + el.offsetWidth,
20219                                                    pos.y + el.offsetHeight,
20220                                                    pos.x );
20221
20222             var overlap = curRegion.intersect(loc);
20223
20224             if (overlap) {
20225                 oTarget.overlap = overlap;
20226                 return (intersect) ? true : oTarget.cursorIsOver;
20227             } else {
20228                 return false;
20229             }
20230         },
20231
20232         /**
20233          * unload event handler
20234          * @method _onUnload
20235          * @private
20236          * @static
20237          */
20238         _onUnload: function(e, me) {
20239             Roo.dd.DragDropMgr.unregAll();
20240         },
20241
20242         /**
20243          * Cleans up the drag and drop events and objects.
20244          * @method unregAll
20245          * @private
20246          * @static
20247          */
20248         unregAll: function() {
20249
20250             if (this.dragCurrent) {
20251                 this.stopDrag();
20252                 this.dragCurrent = null;
20253             }
20254
20255             this._execOnAll("unreg", []);
20256
20257             for (i in this.elementCache) {
20258                 delete this.elementCache[i];
20259             }
20260
20261             this.elementCache = {};
20262             this.ids = {};
20263         },
20264
20265         /**
20266          * A cache of DOM elements
20267          * @property elementCache
20268          * @private
20269          * @static
20270          */
20271         elementCache: {},
20272
20273         /**
20274          * Get the wrapper for the DOM element specified
20275          * @method getElWrapper
20276          * @param {String} id the id of the element to get
20277          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20278          * @private
20279          * @deprecated This wrapper isn't that useful
20280          * @static
20281          */
20282         getElWrapper: function(id) {
20283             var oWrapper = this.elementCache[id];
20284             if (!oWrapper || !oWrapper.el) {
20285                 oWrapper = this.elementCache[id] =
20286                     new this.ElementWrapper(Roo.getDom(id));
20287             }
20288             return oWrapper;
20289         },
20290
20291         /**
20292          * Returns the actual DOM element
20293          * @method getElement
20294          * @param {String} id the id of the elment to get
20295          * @return {Object} The element
20296          * @deprecated use Roo.getDom instead
20297          * @static
20298          */
20299         getElement: function(id) {
20300             return Roo.getDom(id);
20301         },
20302
20303         /**
20304          * Returns the style property for the DOM element (i.e.,
20305          * document.getElById(id).style)
20306          * @method getCss
20307          * @param {String} id the id of the elment to get
20308          * @return {Object} The style property of the element
20309          * @deprecated use Roo.getDom instead
20310          * @static
20311          */
20312         getCss: function(id) {
20313             var el = Roo.getDom(id);
20314             return (el) ? el.style : null;
20315         },
20316
20317         /**
20318          * Inner class for cached elements
20319          * @class DragDropMgr.ElementWrapper
20320          * @for DragDropMgr
20321          * @private
20322          * @deprecated
20323          */
20324         ElementWrapper: function(el) {
20325                 /**
20326                  * The element
20327                  * @property el
20328                  */
20329                 this.el = el || null;
20330                 /**
20331                  * The element id
20332                  * @property id
20333                  */
20334                 this.id = this.el && el.id;
20335                 /**
20336                  * A reference to the style property
20337                  * @property css
20338                  */
20339                 this.css = this.el && el.style;
20340             },
20341
20342         /**
20343          * Returns the X position of an html element
20344          * @method getPosX
20345          * @param el the element for which to get the position
20346          * @return {int} the X coordinate
20347          * @for DragDropMgr
20348          * @deprecated use Roo.lib.Dom.getX instead
20349          * @static
20350          */
20351         getPosX: function(el) {
20352             return Roo.lib.Dom.getX(el);
20353         },
20354
20355         /**
20356          * Returns the Y position of an html element
20357          * @method getPosY
20358          * @param el the element for which to get the position
20359          * @return {int} the Y coordinate
20360          * @deprecated use Roo.lib.Dom.getY instead
20361          * @static
20362          */
20363         getPosY: function(el) {
20364             return Roo.lib.Dom.getY(el);
20365         },
20366
20367         /**
20368          * Swap two nodes.  In IE, we use the native method, for others we
20369          * emulate the IE behavior
20370          * @method swapNode
20371          * @param n1 the first node to swap
20372          * @param n2 the other node to swap
20373          * @static
20374          */
20375         swapNode: function(n1, n2) {
20376             if (n1.swapNode) {
20377                 n1.swapNode(n2);
20378             } else {
20379                 var p = n2.parentNode;
20380                 var s = n2.nextSibling;
20381
20382                 if (s == n1) {
20383                     p.insertBefore(n1, n2);
20384                 } else if (n2 == n1.nextSibling) {
20385                     p.insertBefore(n2, n1);
20386                 } else {
20387                     n1.parentNode.replaceChild(n2, n1);
20388                     p.insertBefore(n1, s);
20389                 }
20390             }
20391         },
20392
20393         /**
20394          * Returns the current scroll position
20395          * @method getScroll
20396          * @private
20397          * @static
20398          */
20399         getScroll: function () {
20400             var t, l, dde=document.documentElement, db=document.body;
20401             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20402                 t = dde.scrollTop;
20403                 l = dde.scrollLeft;
20404             } else if (db) {
20405                 t = db.scrollTop;
20406                 l = db.scrollLeft;
20407             } else {
20408
20409             }
20410             return { top: t, left: l };
20411         },
20412
20413         /**
20414          * Returns the specified element style property
20415          * @method getStyle
20416          * @param {HTMLElement} el          the element
20417          * @param {string}      styleProp   the style property
20418          * @return {string} The value of the style property
20419          * @deprecated use Roo.lib.Dom.getStyle
20420          * @static
20421          */
20422         getStyle: function(el, styleProp) {
20423             return Roo.fly(el).getStyle(styleProp);
20424         },
20425
20426         /**
20427          * Gets the scrollTop
20428          * @method getScrollTop
20429          * @return {int} the document's scrollTop
20430          * @static
20431          */
20432         getScrollTop: function () { return this.getScroll().top; },
20433
20434         /**
20435          * Gets the scrollLeft
20436          * @method getScrollLeft
20437          * @return {int} the document's scrollTop
20438          * @static
20439          */
20440         getScrollLeft: function () { return this.getScroll().left; },
20441
20442         /**
20443          * Sets the x/y position of an element to the location of the
20444          * target element.
20445          * @method moveToEl
20446          * @param {HTMLElement} moveEl      The element to move
20447          * @param {HTMLElement} targetEl    The position reference element
20448          * @static
20449          */
20450         moveToEl: function (moveEl, targetEl) {
20451             var aCoord = Roo.lib.Dom.getXY(targetEl);
20452             Roo.lib.Dom.setXY(moveEl, aCoord);
20453         },
20454
20455         /**
20456          * Numeric array sort function
20457          * @method numericSort
20458          * @static
20459          */
20460         numericSort: function(a, b) { return (a - b); },
20461
20462         /**
20463          * Internal counter
20464          * @property _timeoutCount
20465          * @private
20466          * @static
20467          */
20468         _timeoutCount: 0,
20469
20470         /**
20471          * Trying to make the load order less important.  Without this we get
20472          * an error if this file is loaded before the Event Utility.
20473          * @method _addListeners
20474          * @private
20475          * @static
20476          */
20477         _addListeners: function() {
20478             var DDM = Roo.dd.DDM;
20479             if ( Roo.lib.Event && document ) {
20480                 DDM._onLoad();
20481             } else {
20482                 if (DDM._timeoutCount > 2000) {
20483                 } else {
20484                     setTimeout(DDM._addListeners, 10);
20485                     if (document && document.body) {
20486                         DDM._timeoutCount += 1;
20487                     }
20488                 }
20489             }
20490         },
20491
20492         /**
20493          * Recursively searches the immediate parent and all child nodes for
20494          * the handle element in order to determine wheter or not it was
20495          * clicked.
20496          * @method handleWasClicked
20497          * @param node the html element to inspect
20498          * @static
20499          */
20500         handleWasClicked: function(node, id) {
20501             if (this.isHandle(id, node.id)) {
20502                 return true;
20503             } else {
20504                 // check to see if this is a text node child of the one we want
20505                 var p = node.parentNode;
20506
20507                 while (p) {
20508                     if (this.isHandle(id, p.id)) {
20509                         return true;
20510                     } else {
20511                         p = p.parentNode;
20512                     }
20513                 }
20514             }
20515
20516             return false;
20517         }
20518
20519     };
20520
20521 }();
20522
20523 // shorter alias, save a few bytes
20524 Roo.dd.DDM = Roo.dd.DragDropMgr;
20525 Roo.dd.DDM._addListeners();
20526
20527 }/*
20528  * Based on:
20529  * Ext JS Library 1.1.1
20530  * Copyright(c) 2006-2007, Ext JS, LLC.
20531  *
20532  * Originally Released Under LGPL - original licence link has changed is not relivant.
20533  *
20534  * Fork - LGPL
20535  * <script type="text/javascript">
20536  */
20537
20538 /**
20539  * @class Roo.dd.DD
20540  * A DragDrop implementation where the linked element follows the
20541  * mouse cursor during a drag.
20542  * @extends Roo.dd.DragDrop
20543  * @constructor
20544  * @param {String} id the id of the linked element
20545  * @param {String} sGroup the group of related DragDrop items
20546  * @param {object} config an object containing configurable attributes
20547  *                Valid properties for DD:
20548  *                    scroll
20549  */
20550 Roo.dd.DD = function(id, sGroup, config) {
20551     if (id) {
20552         this.init(id, sGroup, config);
20553     }
20554 };
20555
20556 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20557
20558     /**
20559      * When set to true, the utility automatically tries to scroll the browser
20560      * window wehn a drag and drop element is dragged near the viewport boundary.
20561      * Defaults to true.
20562      * @property scroll
20563      * @type boolean
20564      */
20565     scroll: true,
20566
20567     /**
20568      * Sets the pointer offset to the distance between the linked element's top
20569      * left corner and the location the element was clicked
20570      * @method autoOffset
20571      * @param {int} iPageX the X coordinate of the click
20572      * @param {int} iPageY the Y coordinate of the click
20573      */
20574     autoOffset: function(iPageX, iPageY) {
20575         var x = iPageX - this.startPageX;
20576         var y = iPageY - this.startPageY;
20577         this.setDelta(x, y);
20578     },
20579
20580     /**
20581      * Sets the pointer offset.  You can call this directly to force the
20582      * offset to be in a particular location (e.g., pass in 0,0 to set it
20583      * to the center of the object)
20584      * @method setDelta
20585      * @param {int} iDeltaX the distance from the left
20586      * @param {int} iDeltaY the distance from the top
20587      */
20588     setDelta: function(iDeltaX, iDeltaY) {
20589         this.deltaX = iDeltaX;
20590         this.deltaY = iDeltaY;
20591     },
20592
20593     /**
20594      * Sets the drag element to the location of the mousedown or click event,
20595      * maintaining the cursor location relative to the location on the element
20596      * that was clicked.  Override this if you want to place the element in a
20597      * location other than where the cursor is.
20598      * @method setDragElPos
20599      * @param {int} iPageX the X coordinate of the mousedown or drag event
20600      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20601      */
20602     setDragElPos: function(iPageX, iPageY) {
20603         // the first time we do this, we are going to check to make sure
20604         // the element has css positioning
20605
20606         var el = this.getDragEl();
20607         this.alignElWithMouse(el, iPageX, iPageY);
20608     },
20609
20610     /**
20611      * Sets the element to the location of the mousedown or click event,
20612      * maintaining the cursor location relative to the location on the element
20613      * that was clicked.  Override this if you want to place the element in a
20614      * location other than where the cursor is.
20615      * @method alignElWithMouse
20616      * @param {HTMLElement} el the element to move
20617      * @param {int} iPageX the X coordinate of the mousedown or drag event
20618      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20619      */
20620     alignElWithMouse: function(el, iPageX, iPageY) {
20621         var oCoord = this.getTargetCoord(iPageX, iPageY);
20622         var fly = el.dom ? el : Roo.fly(el);
20623         if (!this.deltaSetXY) {
20624             var aCoord = [oCoord.x, oCoord.y];
20625             fly.setXY(aCoord);
20626             var newLeft = fly.getLeft(true);
20627             var newTop  = fly.getTop(true);
20628             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20629         } else {
20630             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20631         }
20632
20633         this.cachePosition(oCoord.x, oCoord.y);
20634         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20635         return oCoord;
20636     },
20637
20638     /**
20639      * Saves the most recent position so that we can reset the constraints and
20640      * tick marks on-demand.  We need to know this so that we can calculate the
20641      * number of pixels the element is offset from its original position.
20642      * @method cachePosition
20643      * @param iPageX the current x position (optional, this just makes it so we
20644      * don't have to look it up again)
20645      * @param iPageY the current y position (optional, this just makes it so we
20646      * don't have to look it up again)
20647      */
20648     cachePosition: function(iPageX, iPageY) {
20649         if (iPageX) {
20650             this.lastPageX = iPageX;
20651             this.lastPageY = iPageY;
20652         } else {
20653             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20654             this.lastPageX = aCoord[0];
20655             this.lastPageY = aCoord[1];
20656         }
20657     },
20658
20659     /**
20660      * Auto-scroll the window if the dragged object has been moved beyond the
20661      * visible window boundary.
20662      * @method autoScroll
20663      * @param {int} x the drag element's x position
20664      * @param {int} y the drag element's y position
20665      * @param {int} h the height of the drag element
20666      * @param {int} w the width of the drag element
20667      * @private
20668      */
20669     autoScroll: function(x, y, h, w) {
20670
20671         if (this.scroll) {
20672             // The client height
20673             var clientH = Roo.lib.Dom.getViewWidth();
20674
20675             // The client width
20676             var clientW = Roo.lib.Dom.getViewHeight();
20677
20678             // The amt scrolled down
20679             var st = this.DDM.getScrollTop();
20680
20681             // The amt scrolled right
20682             var sl = this.DDM.getScrollLeft();
20683
20684             // Location of the bottom of the element
20685             var bot = h + y;
20686
20687             // Location of the right of the element
20688             var right = w + x;
20689
20690             // The distance from the cursor to the bottom of the visible area,
20691             // adjusted so that we don't scroll if the cursor is beyond the
20692             // element drag constraints
20693             var toBot = (clientH + st - y - this.deltaY);
20694
20695             // The distance from the cursor to the right of the visible area
20696             var toRight = (clientW + sl - x - this.deltaX);
20697
20698
20699             // How close to the edge the cursor must be before we scroll
20700             // var thresh = (document.all) ? 100 : 40;
20701             var thresh = 40;
20702
20703             // How many pixels to scroll per autoscroll op.  This helps to reduce
20704             // clunky scrolling. IE is more sensitive about this ... it needs this
20705             // value to be higher.
20706             var scrAmt = (document.all) ? 80 : 30;
20707
20708             // Scroll down if we are near the bottom of the visible page and the
20709             // obj extends below the crease
20710             if ( bot > clientH && toBot < thresh ) {
20711                 window.scrollTo(sl, st + scrAmt);
20712             }
20713
20714             // Scroll up if the window is scrolled down and the top of the object
20715             // goes above the top border
20716             if ( y < st && st > 0 && y - st < thresh ) {
20717                 window.scrollTo(sl, st - scrAmt);
20718             }
20719
20720             // Scroll right if the obj is beyond the right border and the cursor is
20721             // near the border.
20722             if ( right > clientW && toRight < thresh ) {
20723                 window.scrollTo(sl + scrAmt, st);
20724             }
20725
20726             // Scroll left if the window has been scrolled to the right and the obj
20727             // extends past the left border
20728             if ( x < sl && sl > 0 && x - sl < thresh ) {
20729                 window.scrollTo(sl - scrAmt, st);
20730             }
20731         }
20732     },
20733
20734     /**
20735      * Finds the location the element should be placed if we want to move
20736      * it to where the mouse location less the click offset would place us.
20737      * @method getTargetCoord
20738      * @param {int} iPageX the X coordinate of the click
20739      * @param {int} iPageY the Y coordinate of the click
20740      * @return an object that contains the coordinates (Object.x and Object.y)
20741      * @private
20742      */
20743     getTargetCoord: function(iPageX, iPageY) {
20744
20745
20746         var x = iPageX - this.deltaX;
20747         var y = iPageY - this.deltaY;
20748
20749         if (this.constrainX) {
20750             if (x < this.minX) { x = this.minX; }
20751             if (x > this.maxX) { x = this.maxX; }
20752         }
20753
20754         if (this.constrainY) {
20755             if (y < this.minY) { y = this.minY; }
20756             if (y > this.maxY) { y = this.maxY; }
20757         }
20758
20759         x = this.getTick(x, this.xTicks);
20760         y = this.getTick(y, this.yTicks);
20761
20762
20763         return {x:x, y:y};
20764     },
20765
20766     /*
20767      * Sets up config options specific to this class. Overrides
20768      * Roo.dd.DragDrop, but all versions of this method through the
20769      * inheritance chain are called
20770      */
20771     applyConfig: function() {
20772         Roo.dd.DD.superclass.applyConfig.call(this);
20773         this.scroll = (this.config.scroll !== false);
20774     },
20775
20776     /*
20777      * Event that fires prior to the onMouseDown event.  Overrides
20778      * Roo.dd.DragDrop.
20779      */
20780     b4MouseDown: function(e) {
20781         // this.resetConstraints();
20782         this.autoOffset(e.getPageX(),
20783                             e.getPageY());
20784     },
20785
20786     /*
20787      * Event that fires prior to the onDrag event.  Overrides
20788      * Roo.dd.DragDrop.
20789      */
20790     b4Drag: function(e) {
20791         this.setDragElPos(e.getPageX(),
20792                             e.getPageY());
20793     },
20794
20795     toString: function() {
20796         return ("DD " + this.id);
20797     }
20798
20799     //////////////////////////////////////////////////////////////////////////
20800     // Debugging ygDragDrop events that can be overridden
20801     //////////////////////////////////////////////////////////////////////////
20802     /*
20803     startDrag: function(x, y) {
20804     },
20805
20806     onDrag: function(e) {
20807     },
20808
20809     onDragEnter: function(e, id) {
20810     },
20811
20812     onDragOver: function(e, id) {
20813     },
20814
20815     onDragOut: function(e, id) {
20816     },
20817
20818     onDragDrop: function(e, id) {
20819     },
20820
20821     endDrag: function(e) {
20822     }
20823
20824     */
20825
20826 });/*
20827  * Based on:
20828  * Ext JS Library 1.1.1
20829  * Copyright(c) 2006-2007, Ext JS, LLC.
20830  *
20831  * Originally Released Under LGPL - original licence link has changed is not relivant.
20832  *
20833  * Fork - LGPL
20834  * <script type="text/javascript">
20835  */
20836
20837 /**
20838  * @class Roo.dd.DDProxy
20839  * A DragDrop implementation that inserts an empty, bordered div into
20840  * the document that follows the cursor during drag operations.  At the time of
20841  * the click, the frame div is resized to the dimensions of the linked html
20842  * element, and moved to the exact location of the linked element.
20843  *
20844  * References to the "frame" element refer to the single proxy element that
20845  * was created to be dragged in place of all DDProxy elements on the
20846  * page.
20847  *
20848  * @extends Roo.dd.DD
20849  * @constructor
20850  * @param {String} id the id of the linked html element
20851  * @param {String} sGroup the group of related DragDrop objects
20852  * @param {object} config an object containing configurable attributes
20853  *                Valid properties for DDProxy in addition to those in DragDrop:
20854  *                   resizeFrame, centerFrame, dragElId
20855  */
20856 Roo.dd.DDProxy = function(id, sGroup, config) {
20857     if (id) {
20858         this.init(id, sGroup, config);
20859         this.initFrame();
20860     }
20861 };
20862
20863 /**
20864  * The default drag frame div id
20865  * @property Roo.dd.DDProxy.dragElId
20866  * @type String
20867  * @static
20868  */
20869 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20870
20871 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20872
20873     /**
20874      * By default we resize the drag frame to be the same size as the element
20875      * we want to drag (this is to get the frame effect).  We can turn it off
20876      * if we want a different behavior.
20877      * @property resizeFrame
20878      * @type boolean
20879      */
20880     resizeFrame: true,
20881
20882     /**
20883      * By default the frame is positioned exactly where the drag element is, so
20884      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20885      * you do not have constraints on the obj is to have the drag frame centered
20886      * around the cursor.  Set centerFrame to true for this effect.
20887      * @property centerFrame
20888      * @type boolean
20889      */
20890     centerFrame: false,
20891
20892     /**
20893      * Creates the proxy element if it does not yet exist
20894      * @method createFrame
20895      */
20896     createFrame: function() {
20897         var self = this;
20898         var body = document.body;
20899
20900         if (!body || !body.firstChild) {
20901             setTimeout( function() { self.createFrame(); }, 50 );
20902             return;
20903         }
20904
20905         var div = this.getDragEl();
20906
20907         if (!div) {
20908             div    = document.createElement("div");
20909             div.id = this.dragElId;
20910             var s  = div.style;
20911
20912             s.position   = "absolute";
20913             s.visibility = "hidden";
20914             s.cursor     = "move";
20915             s.border     = "2px solid #aaa";
20916             s.zIndex     = 999;
20917
20918             // appendChild can blow up IE if invoked prior to the window load event
20919             // while rendering a table.  It is possible there are other scenarios
20920             // that would cause this to happen as well.
20921             body.insertBefore(div, body.firstChild);
20922         }
20923     },
20924
20925     /**
20926      * Initialization for the drag frame element.  Must be called in the
20927      * constructor of all subclasses
20928      * @method initFrame
20929      */
20930     initFrame: function() {
20931         this.createFrame();
20932     },
20933
20934     applyConfig: function() {
20935         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20936
20937         this.resizeFrame = (this.config.resizeFrame !== false);
20938         this.centerFrame = (this.config.centerFrame);
20939         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20940     },
20941
20942     /**
20943      * Resizes the drag frame to the dimensions of the clicked object, positions
20944      * it over the object, and finally displays it
20945      * @method showFrame
20946      * @param {int} iPageX X click position
20947      * @param {int} iPageY Y click position
20948      * @private
20949      */
20950     showFrame: function(iPageX, iPageY) {
20951         var el = this.getEl();
20952         var dragEl = this.getDragEl();
20953         var s = dragEl.style;
20954
20955         this._resizeProxy();
20956
20957         if (this.centerFrame) {
20958             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20959                            Math.round(parseInt(s.height, 10)/2) );
20960         }
20961
20962         this.setDragElPos(iPageX, iPageY);
20963
20964         Roo.fly(dragEl).show();
20965     },
20966
20967     /**
20968      * The proxy is automatically resized to the dimensions of the linked
20969      * element when a drag is initiated, unless resizeFrame is set to false
20970      * @method _resizeProxy
20971      * @private
20972      */
20973     _resizeProxy: function() {
20974         if (this.resizeFrame) {
20975             var el = this.getEl();
20976             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20977         }
20978     },
20979
20980     // overrides Roo.dd.DragDrop
20981     b4MouseDown: function(e) {
20982         var x = e.getPageX();
20983         var y = e.getPageY();
20984         this.autoOffset(x, y);
20985         this.setDragElPos(x, y);
20986     },
20987
20988     // overrides Roo.dd.DragDrop
20989     b4StartDrag: function(x, y) {
20990         // show the drag frame
20991         this.showFrame(x, y);
20992     },
20993
20994     // overrides Roo.dd.DragDrop
20995     b4EndDrag: function(e) {
20996         Roo.fly(this.getDragEl()).hide();
20997     },
20998
20999     // overrides Roo.dd.DragDrop
21000     // By default we try to move the element to the last location of the frame.
21001     // This is so that the default behavior mirrors that of Roo.dd.DD.
21002     endDrag: function(e) {
21003
21004         var lel = this.getEl();
21005         var del = this.getDragEl();
21006
21007         // Show the drag frame briefly so we can get its position
21008         del.style.visibility = "";
21009
21010         this.beforeMove();
21011         // Hide the linked element before the move to get around a Safari
21012         // rendering bug.
21013         lel.style.visibility = "hidden";
21014         Roo.dd.DDM.moveToEl(lel, del);
21015         del.style.visibility = "hidden";
21016         lel.style.visibility = "";
21017
21018         this.afterDrag();
21019     },
21020
21021     beforeMove : function(){
21022
21023     },
21024
21025     afterDrag : function(){
21026
21027     },
21028
21029     toString: function() {
21030         return ("DDProxy " + this.id);
21031     }
21032
21033 });
21034 /*
21035  * Based on:
21036  * Ext JS Library 1.1.1
21037  * Copyright(c) 2006-2007, Ext JS, LLC.
21038  *
21039  * Originally Released Under LGPL - original licence link has changed is not relivant.
21040  *
21041  * Fork - LGPL
21042  * <script type="text/javascript">
21043  */
21044
21045  /**
21046  * @class Roo.dd.DDTarget
21047  * A DragDrop implementation that does not move, but can be a drop
21048  * target.  You would get the same result by simply omitting implementation
21049  * for the event callbacks, but this way we reduce the processing cost of the
21050  * event listener and the callbacks.
21051  * @extends Roo.dd.DragDrop
21052  * @constructor
21053  * @param {String} id the id of the element that is a drop target
21054  * @param {String} sGroup the group of related DragDrop objects
21055  * @param {object} config an object containing configurable attributes
21056  *                 Valid properties for DDTarget in addition to those in
21057  *                 DragDrop:
21058  *                    none
21059  */
21060 Roo.dd.DDTarget = function(id, sGroup, config) {
21061     if (id) {
21062         this.initTarget(id, sGroup, config);
21063     }
21064     if (config.listeners || config.events) { 
21065        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
21066             listeners : config.listeners || {}, 
21067             events : config.events || {} 
21068         });    
21069     }
21070 };
21071
21072 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21073 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21074     toString: function() {
21075         return ("DDTarget " + this.id);
21076     }
21077 });
21078 /*
21079  * Based on:
21080  * Ext JS Library 1.1.1
21081  * Copyright(c) 2006-2007, Ext JS, LLC.
21082  *
21083  * Originally Released Under LGPL - original licence link has changed is not relivant.
21084  *
21085  * Fork - LGPL
21086  * <script type="text/javascript">
21087  */
21088  
21089
21090 /**
21091  * @class Roo.dd.ScrollManager
21092  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21093  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21094  * @singleton
21095  */
21096 Roo.dd.ScrollManager = function(){
21097     var ddm = Roo.dd.DragDropMgr;
21098     var els = {};
21099     var dragEl = null;
21100     var proc = {};
21101     
21102     
21103     
21104     var onStop = function(e){
21105         dragEl = null;
21106         clearProc();
21107     };
21108     
21109     var triggerRefresh = function(){
21110         if(ddm.dragCurrent){
21111              ddm.refreshCache(ddm.dragCurrent.groups);
21112         }
21113     };
21114     
21115     var doScroll = function(){
21116         if(ddm.dragCurrent){
21117             var dds = Roo.dd.ScrollManager;
21118             if(!dds.animate){
21119                 if(proc.el.scroll(proc.dir, dds.increment)){
21120                     triggerRefresh();
21121                 }
21122             }else{
21123                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21124             }
21125         }
21126     };
21127     
21128     var clearProc = function(){
21129         if(proc.id){
21130             clearInterval(proc.id);
21131         }
21132         proc.id = 0;
21133         proc.el = null;
21134         proc.dir = "";
21135     };
21136     
21137     var startProc = function(el, dir){
21138          Roo.log('scroll startproc');
21139         clearProc();
21140         proc.el = el;
21141         proc.dir = dir;
21142         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21143     };
21144     
21145     var onFire = function(e, isDrop){
21146        
21147         if(isDrop || !ddm.dragCurrent){ return; }
21148         var dds = Roo.dd.ScrollManager;
21149         if(!dragEl || dragEl != ddm.dragCurrent){
21150             dragEl = ddm.dragCurrent;
21151             // refresh regions on drag start
21152             dds.refreshCache();
21153         }
21154         
21155         var xy = Roo.lib.Event.getXY(e);
21156         var pt = new Roo.lib.Point(xy[0], xy[1]);
21157         for(var id in els){
21158             var el = els[id], r = el._region;
21159             if(r && r.contains(pt) && el.isScrollable()){
21160                 if(r.bottom - pt.y <= dds.thresh){
21161                     if(proc.el != el){
21162                         startProc(el, "down");
21163                     }
21164                     return;
21165                 }else if(r.right - pt.x <= dds.thresh){
21166                     if(proc.el != el){
21167                         startProc(el, "left");
21168                     }
21169                     return;
21170                 }else if(pt.y - r.top <= dds.thresh){
21171                     if(proc.el != el){
21172                         startProc(el, "up");
21173                     }
21174                     return;
21175                 }else if(pt.x - r.left <= dds.thresh){
21176                     if(proc.el != el){
21177                         startProc(el, "right");
21178                     }
21179                     return;
21180                 }
21181             }
21182         }
21183         clearProc();
21184     };
21185     
21186     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21187     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21188     
21189     return {
21190         /**
21191          * Registers new overflow element(s) to auto scroll
21192          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21193          */
21194         register : function(el){
21195             if(el instanceof Array){
21196                 for(var i = 0, len = el.length; i < len; i++) {
21197                         this.register(el[i]);
21198                 }
21199             }else{
21200                 el = Roo.get(el);
21201                 els[el.id] = el;
21202             }
21203             Roo.dd.ScrollManager.els = els;
21204         },
21205         
21206         /**
21207          * Unregisters overflow element(s) so they are no longer scrolled
21208          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21209          */
21210         unregister : function(el){
21211             if(el instanceof Array){
21212                 for(var i = 0, len = el.length; i < len; i++) {
21213                         this.unregister(el[i]);
21214                 }
21215             }else{
21216                 el = Roo.get(el);
21217                 delete els[el.id];
21218             }
21219         },
21220         
21221         /**
21222          * The number of pixels from the edge of a container the pointer needs to be to 
21223          * trigger scrolling (defaults to 25)
21224          * @type Number
21225          */
21226         thresh : 25,
21227         
21228         /**
21229          * The number of pixels to scroll in each scroll increment (defaults to 50)
21230          * @type Number
21231          */
21232         increment : 100,
21233         
21234         /**
21235          * The frequency of scrolls in milliseconds (defaults to 500)
21236          * @type Number
21237          */
21238         frequency : 500,
21239         
21240         /**
21241          * True to animate the scroll (defaults to true)
21242          * @type Boolean
21243          */
21244         animate: true,
21245         
21246         /**
21247          * The animation duration in seconds - 
21248          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21249          * @type Number
21250          */
21251         animDuration: .4,
21252         
21253         /**
21254          * Manually trigger a cache refresh.
21255          */
21256         refreshCache : function(){
21257             for(var id in els){
21258                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21259                     els[id]._region = els[id].getRegion();
21260                 }
21261             }
21262         }
21263     };
21264 }();/*
21265  * Based on:
21266  * Ext JS Library 1.1.1
21267  * Copyright(c) 2006-2007, Ext JS, LLC.
21268  *
21269  * Originally Released Under LGPL - original licence link has changed is not relivant.
21270  *
21271  * Fork - LGPL
21272  * <script type="text/javascript">
21273  */
21274  
21275
21276 /**
21277  * @class Roo.dd.Registry
21278  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21279  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21280  * @singleton
21281  */
21282 Roo.dd.Registry = function(){
21283     var elements = {}; 
21284     var handles = {}; 
21285     var autoIdSeed = 0;
21286
21287     var getId = function(el, autogen){
21288         if(typeof el == "string"){
21289             return el;
21290         }
21291         var id = el.id;
21292         if(!id && autogen !== false){
21293             id = "roodd-" + (++autoIdSeed);
21294             el.id = id;
21295         }
21296         return id;
21297     };
21298     
21299     return {
21300     /**
21301      * Register a drag drop element
21302      * @param {String|HTMLElement} element The id or DOM node to register
21303      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21304      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21305      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21306      * populated in the data object (if applicable):
21307      * <pre>
21308 Value      Description<br />
21309 ---------  ------------------------------------------<br />
21310 handles    Array of DOM nodes that trigger dragging<br />
21311            for the element being registered<br />
21312 isHandle   True if the element passed in triggers<br />
21313            dragging itself, else false
21314 </pre>
21315      */
21316         register : function(el, data){
21317             data = data || {};
21318             if(typeof el == "string"){
21319                 el = document.getElementById(el);
21320             }
21321             data.ddel = el;
21322             elements[getId(el)] = data;
21323             if(data.isHandle !== false){
21324                 handles[data.ddel.id] = data;
21325             }
21326             if(data.handles){
21327                 var hs = data.handles;
21328                 for(var i = 0, len = hs.length; i < len; i++){
21329                         handles[getId(hs[i])] = data;
21330                 }
21331             }
21332         },
21333
21334     /**
21335      * Unregister a drag drop element
21336      * @param {String|HTMLElement}  element The id or DOM node to unregister
21337      */
21338         unregister : function(el){
21339             var id = getId(el, false);
21340             var data = elements[id];
21341             if(data){
21342                 delete elements[id];
21343                 if(data.handles){
21344                     var hs = data.handles;
21345                     for(var i = 0, len = hs.length; i < len; i++){
21346                         delete handles[getId(hs[i], false)];
21347                     }
21348                 }
21349             }
21350         },
21351
21352     /**
21353      * Returns the handle registered for a DOM Node by id
21354      * @param {String|HTMLElement} id The DOM node or id to look up
21355      * @return {Object} handle The custom handle data
21356      */
21357         getHandle : function(id){
21358             if(typeof id != "string"){ // must be element?
21359                 id = id.id;
21360             }
21361             return handles[id];
21362         },
21363
21364     /**
21365      * Returns the handle that is registered for the DOM node that is the target of the event
21366      * @param {Event} e The event
21367      * @return {Object} handle The custom handle data
21368      */
21369         getHandleFromEvent : function(e){
21370             var t = Roo.lib.Event.getTarget(e);
21371             return t ? handles[t.id] : null;
21372         },
21373
21374     /**
21375      * Returns a custom data object that is registered for a DOM node by id
21376      * @param {String|HTMLElement} id The DOM node or id to look up
21377      * @return {Object} data The custom data
21378      */
21379         getTarget : function(id){
21380             if(typeof id != "string"){ // must be element?
21381                 id = id.id;
21382             }
21383             return elements[id];
21384         },
21385
21386     /**
21387      * Returns a custom data object that is registered for the DOM node that is the target of the event
21388      * @param {Event} e The event
21389      * @return {Object} data The custom data
21390      */
21391         getTargetFromEvent : function(e){
21392             var t = Roo.lib.Event.getTarget(e);
21393             return t ? elements[t.id] || handles[t.id] : null;
21394         }
21395     };
21396 }();/*
21397  * Based on:
21398  * Ext JS Library 1.1.1
21399  * Copyright(c) 2006-2007, Ext JS, LLC.
21400  *
21401  * Originally Released Under LGPL - original licence link has changed is not relivant.
21402  *
21403  * Fork - LGPL
21404  * <script type="text/javascript">
21405  */
21406  
21407
21408 /**
21409  * @class Roo.dd.StatusProxy
21410  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21411  * default drag proxy used by all Roo.dd components.
21412  * @constructor
21413  * @param {Object} config
21414  */
21415 Roo.dd.StatusProxy = function(config){
21416     Roo.apply(this, config);
21417     this.id = this.id || Roo.id();
21418     this.el = new Roo.Layer({
21419         dh: {
21420             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21421                 {tag: "div", cls: "x-dd-drop-icon"},
21422                 {tag: "div", cls: "x-dd-drag-ghost"}
21423             ]
21424         }, 
21425         shadow: !config || config.shadow !== false
21426     });
21427     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21428     this.dropStatus = this.dropNotAllowed;
21429 };
21430
21431 Roo.dd.StatusProxy.prototype = {
21432     /**
21433      * @cfg {String} dropAllowed
21434      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21435      */
21436     dropAllowed : "x-dd-drop-ok",
21437     /**
21438      * @cfg {String} dropNotAllowed
21439      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21440      */
21441     dropNotAllowed : "x-dd-drop-nodrop",
21442
21443     /**
21444      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21445      * over the current target element.
21446      * @param {String} cssClass The css class for the new drop status indicator image
21447      */
21448     setStatus : function(cssClass){
21449         cssClass = cssClass || this.dropNotAllowed;
21450         if(this.dropStatus != cssClass){
21451             this.el.replaceClass(this.dropStatus, cssClass);
21452             this.dropStatus = cssClass;
21453         }
21454     },
21455
21456     /**
21457      * Resets the status indicator to the default dropNotAllowed value
21458      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21459      */
21460     reset : function(clearGhost){
21461         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21462         this.dropStatus = this.dropNotAllowed;
21463         if(clearGhost){
21464             this.ghost.update("");
21465         }
21466     },
21467
21468     /**
21469      * Updates the contents of the ghost element
21470      * @param {String} html The html that will replace the current innerHTML of the ghost element
21471      */
21472     update : function(html){
21473         if(typeof html == "string"){
21474             this.ghost.update(html);
21475         }else{
21476             this.ghost.update("");
21477             html.style.margin = "0";
21478             this.ghost.dom.appendChild(html);
21479         }
21480         // ensure float = none set?? cant remember why though.
21481         var el = this.ghost.dom.firstChild;
21482                 if(el){
21483                         Roo.fly(el).setStyle('float', 'none');
21484                 }
21485     },
21486     
21487     /**
21488      * Returns the underlying proxy {@link Roo.Layer}
21489      * @return {Roo.Layer} el
21490     */
21491     getEl : function(){
21492         return this.el;
21493     },
21494
21495     /**
21496      * Returns the ghost element
21497      * @return {Roo.Element} el
21498      */
21499     getGhost : function(){
21500         return this.ghost;
21501     },
21502
21503     /**
21504      * Hides the proxy
21505      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21506      */
21507     hide : function(clear){
21508         this.el.hide();
21509         if(clear){
21510             this.reset(true);
21511         }
21512     },
21513
21514     /**
21515      * Stops the repair animation if it's currently running
21516      */
21517     stop : function(){
21518         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21519             this.anim.stop();
21520         }
21521     },
21522
21523     /**
21524      * Displays this proxy
21525      */
21526     show : function(){
21527         this.el.show();
21528     },
21529
21530     /**
21531      * Force the Layer to sync its shadow and shim positions to the element
21532      */
21533     sync : function(){
21534         this.el.sync();
21535     },
21536
21537     /**
21538      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21539      * invalid drop operation by the item being dragged.
21540      * @param {Array} xy The XY position of the element ([x, y])
21541      * @param {Function} callback The function to call after the repair is complete
21542      * @param {Object} scope The scope in which to execute the callback
21543      */
21544     repair : function(xy, callback, scope){
21545         this.callback = callback;
21546         this.scope = scope;
21547         if(xy && this.animRepair !== false){
21548             this.el.addClass("x-dd-drag-repair");
21549             this.el.hideUnders(true);
21550             this.anim = this.el.shift({
21551                 duration: this.repairDuration || .5,
21552                 easing: 'easeOut',
21553                 xy: xy,
21554                 stopFx: true,
21555                 callback: this.afterRepair,
21556                 scope: this
21557             });
21558         }else{
21559             this.afterRepair();
21560         }
21561     },
21562
21563     // private
21564     afterRepair : function(){
21565         this.hide(true);
21566         if(typeof this.callback == "function"){
21567             this.callback.call(this.scope || this);
21568         }
21569         this.callback = null;
21570         this.scope = null;
21571     }
21572 };/*
21573  * Based on:
21574  * Ext JS Library 1.1.1
21575  * Copyright(c) 2006-2007, Ext JS, LLC.
21576  *
21577  * Originally Released Under LGPL - original licence link has changed is not relivant.
21578  *
21579  * Fork - LGPL
21580  * <script type="text/javascript">
21581  */
21582
21583 /**
21584  * @class Roo.dd.DragSource
21585  * @extends Roo.dd.DDProxy
21586  * A simple class that provides the basic implementation needed to make any element draggable.
21587  * @constructor
21588  * @param {String/HTMLElement/Element} el The container element
21589  * @param {Object} config
21590  */
21591 Roo.dd.DragSource = function(el, config){
21592     this.el = Roo.get(el);
21593     this.dragData = {};
21594     
21595     Roo.apply(this, config);
21596     
21597     if(!this.proxy){
21598         this.proxy = new Roo.dd.StatusProxy();
21599     }
21600
21601     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21602           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21603     
21604     this.dragging = false;
21605 };
21606
21607 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21608     /**
21609      * @cfg {String} dropAllowed
21610      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21611      */
21612     dropAllowed : "x-dd-drop-ok",
21613     /**
21614      * @cfg {String} dropNotAllowed
21615      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21616      */
21617     dropNotAllowed : "x-dd-drop-nodrop",
21618
21619     /**
21620      * Returns the data object associated with this drag source
21621      * @return {Object} data An object containing arbitrary data
21622      */
21623     getDragData : function(e){
21624         return this.dragData;
21625     },
21626
21627     // private
21628     onDragEnter : function(e, id){
21629         var target = Roo.dd.DragDropMgr.getDDById(id);
21630         this.cachedTarget = target;
21631         if(this.beforeDragEnter(target, e, id) !== false){
21632             if(target.isNotifyTarget){
21633                 var status = target.notifyEnter(this, e, this.dragData);
21634                 this.proxy.setStatus(status);
21635             }else{
21636                 this.proxy.setStatus(this.dropAllowed);
21637             }
21638             
21639             if(this.afterDragEnter){
21640                 /**
21641                  * An empty function by default, but provided so that you can perform a custom action
21642                  * when the dragged item enters the drop target by providing an implementation.
21643                  * @param {Roo.dd.DragDrop} target The drop target
21644                  * @param {Event} e The event object
21645                  * @param {String} id The id of the dragged element
21646                  * @method afterDragEnter
21647                  */
21648                 this.afterDragEnter(target, e, id);
21649             }
21650         }
21651     },
21652
21653     /**
21654      * An empty function by default, but provided so that you can perform a custom action
21655      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21656      * @param {Roo.dd.DragDrop} target The drop target
21657      * @param {Event} e The event object
21658      * @param {String} id The id of the dragged element
21659      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21660      */
21661     beforeDragEnter : function(target, e, id){
21662         return true;
21663     },
21664
21665     // private
21666     alignElWithMouse: function() {
21667         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21668         this.proxy.sync();
21669     },
21670
21671     // private
21672     onDragOver : function(e, id){
21673         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21674         if(this.beforeDragOver(target, e, id) !== false){
21675             if(target.isNotifyTarget){
21676                 var status = target.notifyOver(this, e, this.dragData);
21677                 this.proxy.setStatus(status);
21678             }
21679
21680             if(this.afterDragOver){
21681                 /**
21682                  * An empty function by default, but provided so that you can perform a custom action
21683                  * while the dragged item is over the drop target by providing an implementation.
21684                  * @param {Roo.dd.DragDrop} target The drop target
21685                  * @param {Event} e The event object
21686                  * @param {String} id The id of the dragged element
21687                  * @method afterDragOver
21688                  */
21689                 this.afterDragOver(target, e, id);
21690             }
21691         }
21692     },
21693
21694     /**
21695      * An empty function by default, but provided so that you can perform a custom action
21696      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21697      * @param {Roo.dd.DragDrop} target The drop target
21698      * @param {Event} e The event object
21699      * @param {String} id The id of the dragged element
21700      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21701      */
21702     beforeDragOver : function(target, e, id){
21703         return true;
21704     },
21705
21706     // private
21707     onDragOut : function(e, id){
21708         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21709         if(this.beforeDragOut(target, e, id) !== false){
21710             if(target.isNotifyTarget){
21711                 target.notifyOut(this, e, this.dragData);
21712             }
21713             this.proxy.reset();
21714             if(this.afterDragOut){
21715                 /**
21716                  * An empty function by default, but provided so that you can perform a custom action
21717                  * after the dragged item is dragged out of the target without dropping.
21718                  * @param {Roo.dd.DragDrop} target The drop target
21719                  * @param {Event} e The event object
21720                  * @param {String} id The id of the dragged element
21721                  * @method afterDragOut
21722                  */
21723                 this.afterDragOut(target, e, id);
21724             }
21725         }
21726         this.cachedTarget = null;
21727     },
21728
21729     /**
21730      * An empty function by default, but provided so that you can perform a custom action before the dragged
21731      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21732      * @param {Roo.dd.DragDrop} target The drop target
21733      * @param {Event} e The event object
21734      * @param {String} id The id of the dragged element
21735      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21736      */
21737     beforeDragOut : function(target, e, id){
21738         return true;
21739     },
21740     
21741     // private
21742     onDragDrop : function(e, id){
21743         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21744         if(this.beforeDragDrop(target, e, id) !== false){
21745             if(target.isNotifyTarget){
21746                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21747                     this.onValidDrop(target, e, id);
21748                 }else{
21749                     this.onInvalidDrop(target, e, id);
21750                 }
21751             }else{
21752                 this.onValidDrop(target, e, id);
21753             }
21754             
21755             if(this.afterDragDrop){
21756                 /**
21757                  * An empty function by default, but provided so that you can perform a custom action
21758                  * after a valid drag drop has occurred by providing an implementation.
21759                  * @param {Roo.dd.DragDrop} target The drop target
21760                  * @param {Event} e The event object
21761                  * @param {String} id The id of the dropped element
21762                  * @method afterDragDrop
21763                  */
21764                 this.afterDragDrop(target, e, id);
21765             }
21766         }
21767         delete this.cachedTarget;
21768     },
21769
21770     /**
21771      * An empty function by default, but provided so that you can perform a custom action before the dragged
21772      * item is dropped onto the target and optionally cancel the onDragDrop.
21773      * @param {Roo.dd.DragDrop} target The drop target
21774      * @param {Event} e The event object
21775      * @param {String} id The id of the dragged element
21776      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21777      */
21778     beforeDragDrop : function(target, e, id){
21779         return true;
21780     },
21781
21782     // private
21783     onValidDrop : function(target, e, id){
21784         this.hideProxy();
21785         if(this.afterValidDrop){
21786             /**
21787              * An empty function by default, but provided so that you can perform a custom action
21788              * after a valid drop has occurred by providing an implementation.
21789              * @param {Object} target The target DD 
21790              * @param {Event} e The event object
21791              * @param {String} id The id of the dropped element
21792              * @method afterInvalidDrop
21793              */
21794             this.afterValidDrop(target, e, id);
21795         }
21796     },
21797
21798     // private
21799     getRepairXY : function(e, data){
21800         return this.el.getXY();  
21801     },
21802
21803     // private
21804     onInvalidDrop : function(target, e, id){
21805         this.beforeInvalidDrop(target, e, id);
21806         if(this.cachedTarget){
21807             if(this.cachedTarget.isNotifyTarget){
21808                 this.cachedTarget.notifyOut(this, e, this.dragData);
21809             }
21810             this.cacheTarget = null;
21811         }
21812         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21813
21814         if(this.afterInvalidDrop){
21815             /**
21816              * An empty function by default, but provided so that you can perform a custom action
21817              * after an invalid drop has occurred by providing an implementation.
21818              * @param {Event} e The event object
21819              * @param {String} id The id of the dropped element
21820              * @method afterInvalidDrop
21821              */
21822             this.afterInvalidDrop(e, id);
21823         }
21824     },
21825
21826     // private
21827     afterRepair : function(){
21828         if(Roo.enableFx){
21829             this.el.highlight(this.hlColor || "c3daf9");
21830         }
21831         this.dragging = false;
21832     },
21833
21834     /**
21835      * An empty function by default, but provided so that you can perform a custom action after an invalid
21836      * drop has occurred.
21837      * @param {Roo.dd.DragDrop} target The drop target
21838      * @param {Event} e The event object
21839      * @param {String} id The id of the dragged element
21840      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21841      */
21842     beforeInvalidDrop : function(target, e, id){
21843         return true;
21844     },
21845
21846     // private
21847     handleMouseDown : function(e){
21848         if(this.dragging) {
21849             return;
21850         }
21851         var data = this.getDragData(e);
21852         if(data && this.onBeforeDrag(data, e) !== false){
21853             this.dragData = data;
21854             this.proxy.stop();
21855             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21856         } 
21857     },
21858
21859     /**
21860      * An empty function by default, but provided so that you can perform a custom action before the initial
21861      * drag event begins and optionally cancel it.
21862      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21863      * @param {Event} e The event object
21864      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21865      */
21866     onBeforeDrag : function(data, e){
21867         return true;
21868     },
21869
21870     /**
21871      * An empty function by default, but provided so that you can perform a custom action once the initial
21872      * drag event has begun.  The drag cannot be canceled from this function.
21873      * @param {Number} x The x position of the click on the dragged object
21874      * @param {Number} y The y position of the click on the dragged object
21875      */
21876     onStartDrag : Roo.emptyFn,
21877
21878     // private - YUI override
21879     startDrag : function(x, y){
21880         this.proxy.reset();
21881         this.dragging = true;
21882         this.proxy.update("");
21883         this.onInitDrag(x, y);
21884         this.proxy.show();
21885     },
21886
21887     // private
21888     onInitDrag : function(x, y){
21889         var clone = this.el.dom.cloneNode(true);
21890         clone.id = Roo.id(); // prevent duplicate ids
21891         this.proxy.update(clone);
21892         this.onStartDrag(x, y);
21893         return true;
21894     },
21895
21896     /**
21897      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21898      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21899      */
21900     getProxy : function(){
21901         return this.proxy;  
21902     },
21903
21904     /**
21905      * Hides the drag source's {@link Roo.dd.StatusProxy}
21906      */
21907     hideProxy : function(){
21908         this.proxy.hide();  
21909         this.proxy.reset(true);
21910         this.dragging = false;
21911     },
21912
21913     // private
21914     triggerCacheRefresh : function(){
21915         Roo.dd.DDM.refreshCache(this.groups);
21916     },
21917
21918     // private - override to prevent hiding
21919     b4EndDrag: function(e) {
21920     },
21921
21922     // private - override to prevent moving
21923     endDrag : function(e){
21924         this.onEndDrag(this.dragData, e);
21925     },
21926
21927     // private
21928     onEndDrag : function(data, e){
21929     },
21930     
21931     // private - pin to cursor
21932     autoOffset : function(x, y) {
21933         this.setDelta(-12, -20);
21934     }    
21935 });/*
21936  * Based on:
21937  * Ext JS Library 1.1.1
21938  * Copyright(c) 2006-2007, Ext JS, LLC.
21939  *
21940  * Originally Released Under LGPL - original licence link has changed is not relivant.
21941  *
21942  * Fork - LGPL
21943  * <script type="text/javascript">
21944  */
21945
21946
21947 /**
21948  * @class Roo.dd.DropTarget
21949  * @extends Roo.dd.DDTarget
21950  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21951  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21952  * @constructor
21953  * @param {String/HTMLElement/Element} el The container element
21954  * @param {Object} config
21955  */
21956 Roo.dd.DropTarget = function(el, config){
21957     this.el = Roo.get(el);
21958     
21959     var listeners = false; ;
21960     if (config && config.listeners) {
21961         listeners= config.listeners;
21962         delete config.listeners;
21963     }
21964     Roo.apply(this, config);
21965     
21966     if(this.containerScroll){
21967         Roo.dd.ScrollManager.register(this.el);
21968     }
21969     this.addEvents( {
21970          /**
21971          * @scope Roo.dd.DropTarget
21972          */
21973          
21974          /**
21975          * @event enter
21976          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21977          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21978          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21979          * 
21980          * IMPORTANT : it should set this.overClass and this.dropAllowed
21981          * 
21982          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21983          * @param {Event} e The event
21984          * @param {Object} data An object containing arbitrary data supplied by the drag source
21985          */
21986         "enter" : true,
21987         
21988          /**
21989          * @event over
21990          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21991          * This method will be called on every mouse movement while the drag source is over the drop target.
21992          * This default implementation simply returns the dropAllowed config value.
21993          * 
21994          * IMPORTANT : it should set this.dropAllowed
21995          * 
21996          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21997          * @param {Event} e The event
21998          * @param {Object} data An object containing arbitrary data supplied by the drag source
21999          
22000          */
22001         "over" : true,
22002         /**
22003          * @event out
22004          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22005          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
22006          * overClass (if any) from the drop element.
22007          * 
22008          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22009          * @param {Event} e The event
22010          * @param {Object} data An object containing arbitrary data supplied by the drag source
22011          */
22012          "out" : true,
22013          
22014         /**
22015          * @event drop
22016          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22017          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
22018          * implementation that does something to process the drop event and returns true so that the drag source's
22019          * repair action does not run.
22020          * 
22021          * IMPORTANT : it should set this.success
22022          * 
22023          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22024          * @param {Event} e The event
22025          * @param {Object} data An object containing arbitrary data supplied by the drag source
22026         */
22027          "drop" : true
22028     });
22029             
22030      
22031     Roo.dd.DropTarget.superclass.constructor.call(  this, 
22032         this.el.dom, 
22033         this.ddGroup || this.group,
22034         {
22035             isTarget: true,
22036             listeners : listeners || {} 
22037            
22038         
22039         }
22040     );
22041
22042 };
22043
22044 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22045     /**
22046      * @cfg {String} overClass
22047      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22048      */
22049      /**
22050      * @cfg {String} ddGroup
22051      * The drag drop group to handle drop events for
22052      */
22053      
22054     /**
22055      * @cfg {String} dropAllowed
22056      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22057      */
22058     dropAllowed : "x-dd-drop-ok",
22059     /**
22060      * @cfg {String} dropNotAllowed
22061      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22062      */
22063     dropNotAllowed : "x-dd-drop-nodrop",
22064     /**
22065      * @cfg {boolean} success
22066      * set this after drop listener.. 
22067      */
22068     success : false,
22069     /**
22070      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22071      * if the drop point is valid for over/enter..
22072      */
22073     valid : false,
22074     // private
22075     isTarget : true,
22076
22077     // private
22078     isNotifyTarget : true,
22079     
22080     /**
22081      * @hide
22082      */
22083     notifyEnter : function(dd, e, data)
22084     {
22085         this.valid = true;
22086         this.fireEvent('enter', dd, e, data);
22087         if(this.overClass){
22088             this.el.addClass(this.overClass);
22089         }
22090         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22091             this.valid ? this.dropAllowed : this.dropNotAllowed
22092         );
22093     },
22094
22095     /**
22096      * @hide
22097      */
22098     notifyOver : function(dd, e, data)
22099     {
22100         this.valid = true;
22101         this.fireEvent('over', dd, e, data);
22102         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22103             this.valid ? this.dropAllowed : this.dropNotAllowed
22104         );
22105     },
22106
22107     /**
22108      * @hide
22109      */
22110     notifyOut : function(dd, e, data)
22111     {
22112         this.fireEvent('out', dd, e, data);
22113         if(this.overClass){
22114             this.el.removeClass(this.overClass);
22115         }
22116     },
22117
22118     /**
22119      * @hide
22120      */
22121     notifyDrop : function(dd, e, data)
22122     {
22123         this.success = false;
22124         this.fireEvent('drop', dd, e, data);
22125         return this.success;
22126     }
22127 });/*
22128  * Based on:
22129  * Ext JS Library 1.1.1
22130  * Copyright(c) 2006-2007, Ext JS, LLC.
22131  *
22132  * Originally Released Under LGPL - original licence link has changed is not relivant.
22133  *
22134  * Fork - LGPL
22135  * <script type="text/javascript">
22136  */
22137
22138
22139 /**
22140  * @class Roo.dd.DragZone
22141  * @extends Roo.dd.DragSource
22142  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22143  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22144  * @constructor
22145  * @param {String/HTMLElement/Element} el The container element
22146  * @param {Object} config
22147  */
22148 Roo.dd.DragZone = function(el, config){
22149     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22150     if(this.containerScroll){
22151         Roo.dd.ScrollManager.register(this.el);
22152     }
22153 };
22154
22155 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22156     /**
22157      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22158      * for auto scrolling during drag operations.
22159      */
22160     /**
22161      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22162      * method after a failed drop (defaults to "c3daf9" - light blue)
22163      */
22164
22165     /**
22166      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22167      * for a valid target to drag based on the mouse down. Override this method
22168      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22169      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22170      * @param {EventObject} e The mouse down event
22171      * @return {Object} The dragData
22172      */
22173     getDragData : function(e){
22174         return Roo.dd.Registry.getHandleFromEvent(e);
22175     },
22176     
22177     /**
22178      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22179      * this.dragData.ddel
22180      * @param {Number} x The x position of the click on the dragged object
22181      * @param {Number} y The y position of the click on the dragged object
22182      * @return {Boolean} true to continue the drag, false to cancel
22183      */
22184     onInitDrag : function(x, y){
22185         this.proxy.update(this.dragData.ddel.cloneNode(true));
22186         this.onStartDrag(x, y);
22187         return true;
22188     },
22189     
22190     /**
22191      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22192      */
22193     afterRepair : function(){
22194         if(Roo.enableFx){
22195             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22196         }
22197         this.dragging = false;
22198     },
22199
22200     /**
22201      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22202      * the XY of this.dragData.ddel
22203      * @param {EventObject} e The mouse up event
22204      * @return {Array} The xy location (e.g. [100, 200])
22205      */
22206     getRepairXY : function(e){
22207         return Roo.Element.fly(this.dragData.ddel).getXY();  
22208     }
22209 });/*
22210  * Based on:
22211  * Ext JS Library 1.1.1
22212  * Copyright(c) 2006-2007, Ext JS, LLC.
22213  *
22214  * Originally Released Under LGPL - original licence link has changed is not relivant.
22215  *
22216  * Fork - LGPL
22217  * <script type="text/javascript">
22218  */
22219 /**
22220  * @class Roo.dd.DropZone
22221  * @extends Roo.dd.DropTarget
22222  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22223  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22224  * @constructor
22225  * @param {String/HTMLElement/Element} el The container element
22226  * @param {Object} config
22227  */
22228 Roo.dd.DropZone = function(el, config){
22229     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22230 };
22231
22232 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22233     /**
22234      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22235      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22236      * provide your own custom lookup.
22237      * @param {Event} e The event
22238      * @return {Object} data The custom data
22239      */
22240     getTargetFromEvent : function(e){
22241         return Roo.dd.Registry.getTargetFromEvent(e);
22242     },
22243
22244     /**
22245      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22246      * that it has registered.  This method has no default implementation and should be overridden to provide
22247      * node-specific processing if necessary.
22248      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22249      * {@link #getTargetFromEvent} for this node)
22250      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22251      * @param {Event} e The event
22252      * @param {Object} data An object containing arbitrary data supplied by the drag source
22253      */
22254     onNodeEnter : function(n, dd, e, data){
22255         
22256     },
22257
22258     /**
22259      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22260      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22261      * overridden to provide the proper feedback.
22262      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22263      * {@link #getTargetFromEvent} for this node)
22264      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22265      * @param {Event} e The event
22266      * @param {Object} data An object containing arbitrary data supplied by the drag source
22267      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22268      * underlying {@link Roo.dd.StatusProxy} can be updated
22269      */
22270     onNodeOver : function(n, dd, e, data){
22271         return this.dropAllowed;
22272     },
22273
22274     /**
22275      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22276      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22277      * node-specific processing if necessary.
22278      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22279      * {@link #getTargetFromEvent} for this node)
22280      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22281      * @param {Event} e The event
22282      * @param {Object} data An object containing arbitrary data supplied by the drag source
22283      */
22284     onNodeOut : function(n, dd, e, data){
22285         
22286     },
22287
22288     /**
22289      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22290      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22291      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22292      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22293      * {@link #getTargetFromEvent} for this node)
22294      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22295      * @param {Event} e The event
22296      * @param {Object} data An object containing arbitrary data supplied by the drag source
22297      * @return {Boolean} True if the drop was valid, else false
22298      */
22299     onNodeDrop : function(n, dd, e, data){
22300         return false;
22301     },
22302
22303     /**
22304      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22305      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22306      * it should be overridden to provide the proper feedback if necessary.
22307      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22308      * @param {Event} e The event
22309      * @param {Object} data An object containing arbitrary data supplied by the drag source
22310      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22311      * underlying {@link Roo.dd.StatusProxy} can be updated
22312      */
22313     onContainerOver : function(dd, e, data){
22314         return this.dropNotAllowed;
22315     },
22316
22317     /**
22318      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22319      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22320      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22321      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22322      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22323      * @param {Event} e The event
22324      * @param {Object} data An object containing arbitrary data supplied by the drag source
22325      * @return {Boolean} True if the drop was valid, else false
22326      */
22327     onContainerDrop : function(dd, e, data){
22328         return false;
22329     },
22330
22331     /**
22332      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22333      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22334      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22335      * you should override this method and provide a custom implementation.
22336      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22337      * @param {Event} e The event
22338      * @param {Object} data An object containing arbitrary data supplied by the drag source
22339      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22340      * underlying {@link Roo.dd.StatusProxy} can be updated
22341      */
22342     notifyEnter : function(dd, e, data){
22343         return this.dropNotAllowed;
22344     },
22345
22346     /**
22347      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22348      * This method will be called on every mouse movement while the drag source is over the drop zone.
22349      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22350      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22351      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22352      * registered node, it will call {@link #onContainerOver}.
22353      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22354      * @param {Event} e The event
22355      * @param {Object} data An object containing arbitrary data supplied by the drag source
22356      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22357      * underlying {@link Roo.dd.StatusProxy} can be updated
22358      */
22359     notifyOver : function(dd, e, data){
22360         var n = this.getTargetFromEvent(e);
22361         if(!n){ // not over valid drop target
22362             if(this.lastOverNode){
22363                 this.onNodeOut(this.lastOverNode, dd, e, data);
22364                 this.lastOverNode = null;
22365             }
22366             return this.onContainerOver(dd, e, data);
22367         }
22368         if(this.lastOverNode != n){
22369             if(this.lastOverNode){
22370                 this.onNodeOut(this.lastOverNode, dd, e, data);
22371             }
22372             this.onNodeEnter(n, dd, e, data);
22373             this.lastOverNode = n;
22374         }
22375         return this.onNodeOver(n, dd, e, data);
22376     },
22377
22378     /**
22379      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22380      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22381      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22382      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22383      * @param {Event} e The event
22384      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22385      */
22386     notifyOut : function(dd, e, data){
22387         if(this.lastOverNode){
22388             this.onNodeOut(this.lastOverNode, dd, e, data);
22389             this.lastOverNode = null;
22390         }
22391     },
22392
22393     /**
22394      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22395      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22396      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22397      * otherwise it will call {@link #onContainerDrop}.
22398      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22399      * @param {Event} e The event
22400      * @param {Object} data An object containing arbitrary data supplied by the drag source
22401      * @return {Boolean} True if the drop was valid, else false
22402      */
22403     notifyDrop : function(dd, e, data){
22404         if(this.lastOverNode){
22405             this.onNodeOut(this.lastOverNode, dd, e, data);
22406             this.lastOverNode = null;
22407         }
22408         var n = this.getTargetFromEvent(e);
22409         return n ?
22410             this.onNodeDrop(n, dd, e, data) :
22411             this.onContainerDrop(dd, e, data);
22412     },
22413
22414     // private
22415     triggerCacheRefresh : function(){
22416         Roo.dd.DDM.refreshCache(this.groups);
22417     }  
22418 });