roojs-ui.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             console.log(s);
347         },
348         /**
349          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
350          * @param {Object} o
351          * @return {String}
352          */
353         urlEncode : function(o){
354             if(!o){
355                 return "";
356             }
357             var buf = [];
358             for(var key in o){
359                 var ov = o[key], k = Roo.encodeURIComponent(key);
360                 var type = typeof ov;
361                 if(type == 'undefined'){
362                     buf.push(k, "=&");
363                 }else if(type != "function" && type != "object"){
364                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365                 }else if(ov instanceof Array){
366                     if (ov.length) {
367                             for(var i = 0, len = ov.length; i < len; i++) {
368                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369                             }
370                         } else {
371                             buf.push(k, "=&");
372                         }
373                 }
374             }
375             buf.pop();
376             return buf.join("");
377         },
378          /**
379          * Safe version of encodeURIComponent
380          * @param {String} data 
381          * @return {String} 
382          */
383         
384         encodeURIComponent : function (data)
385         {
386             try {
387                 return encodeURIComponent(data);
388             } catch(e) {} // should be an uri encode error.
389             
390             if (data == '' || data == null){
391                return '';
392             }
393             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394             function nibble_to_hex(nibble){
395                 var chars = '0123456789ABCDEF';
396                 return chars.charAt(nibble);
397             }
398             data = data.toString();
399             var buffer = '';
400             for(var i=0; i<data.length; i++){
401                 var c = data.charCodeAt(i);
402                 var bs = new Array();
403                 if (c > 0x10000){
404                         // 4 bytes
405                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408                     bs[3] = 0x80 | (c & 0x3F);
409                 }else if (c > 0x800){
410                          // 3 bytes
411                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413                     bs[2] = 0x80 | (c & 0x3F);
414                 }else if (c > 0x80){
415                        // 2 bytes
416                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417                     bs[1] = 0x80 | (c & 0x3F);
418                 }else{
419                         // 1 byte
420                     bs[0] = c;
421                 }
422                 for(var j=0; j<bs.length; j++){
423                     var b = bs[j];
424                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
425                             + nibble_to_hex(b &0x0F);
426                     buffer += '%'+hex;
427                }
428             }
429             return buffer;    
430              
431         },
432
433         /**
434          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435          * @param {String} string
436          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437          * @return {Object} A literal with members
438          */
439         urlDecode : function(string, overwrite){
440             if(!string || !string.length){
441                 return {};
442             }
443             var obj = {};
444             var pairs = string.split('&');
445             var pair, name, value;
446             for(var i = 0, len = pairs.length; i < len; i++){
447                 pair = pairs[i].split('=');
448                 name = decodeURIComponent(pair[0]);
449                 value = decodeURIComponent(pair[1]);
450                 if(overwrite !== true){
451                     if(typeof obj[name] == "undefined"){
452                         obj[name] = value;
453                     }else if(typeof obj[name] == "string"){
454                         obj[name] = [obj[name]];
455                         obj[name].push(value);
456                     }else{
457                         obj[name].push(value);
458                     }
459                 }else{
460                     obj[name] = value;
461                 }
462             }
463             return obj;
464         },
465
466         /**
467          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468          * passed array is not really an array, your function is called once with it.
469          * The supplied function is called with (Object item, Number index, Array allItems).
470          * @param {Array/NodeList/Mixed} array
471          * @param {Function} fn
472          * @param {Object} scope
473          */
474         each : function(array, fn, scope){
475             if(typeof array.length == "undefined" || typeof array == "string"){
476                 array = [array];
477             }
478             for(var i = 0, len = array.length; i < len; i++){
479                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
480             }
481         },
482
483         // deprecated
484         combine : function(){
485             var as = arguments, l = as.length, r = [];
486             for(var i = 0; i < l; i++){
487                 var a = as[i];
488                 if(a instanceof Array){
489                     r = r.concat(a);
490                 }else if(a.length !== undefined && !a.substr){
491                     r = r.concat(Array.prototype.slice.call(a, 0));
492                 }else{
493                     r.push(a);
494                 }
495             }
496             return r;
497         },
498
499         /**
500          * Escapes the passed string for use in a regular expression
501          * @param {String} str
502          * @return {String}
503          */
504         escapeRe : function(s) {
505             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
506         },
507
508         // internal
509         callback : function(cb, scope, args, delay){
510             if(typeof cb == "function"){
511                 if(delay){
512                     cb.defer(delay, scope, args || []);
513                 }else{
514                     cb.apply(scope, args || []);
515                 }
516             }
517         },
518
519         /**
520          * Return the dom node for the passed string (id), dom node, or Roo.Element
521          * @param {String/HTMLElement/Roo.Element} el
522          * @return HTMLElement
523          */
524         getDom : function(el){
525             if(!el){
526                 return null;
527             }
528             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
529         },
530
531         /**
532         * Shorthand for {@link Roo.ComponentMgr#get}
533         * @param {String} id
534         * @return Roo.Component
535         */
536         getCmp : function(id){
537             return Roo.ComponentMgr.get(id);
538         },
539          
540         num : function(v, defaultValue){
541             if(typeof v != 'number'){
542                 return defaultValue;
543             }
544             return v;
545         },
546
547         destroy : function(){
548             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
549                 var as = a[i];
550                 if(as){
551                     if(as.dom){
552                         as.removeAllListeners();
553                         as.remove();
554                         continue;
555                     }
556                     if(typeof as.purgeListeners == 'function'){
557                         as.purgeListeners();
558                     }
559                     if(typeof as.destroy == 'function'){
560                         as.destroy();
561                     }
562                 }
563             }
564         },
565
566         // inpired by a similar function in mootools library
567         /**
568          * Returns the type of object that is passed in. If the object passed in is null or undefined it
569          * return false otherwise it returns one of the following values:<ul>
570          * <li><b>string</b>: If the object passed is a string</li>
571          * <li><b>number</b>: If the object passed is a number</li>
572          * <li><b>boolean</b>: If the object passed is a boolean value</li>
573          * <li><b>function</b>: If the object passed is a function reference</li>
574          * <li><b>object</b>: If the object passed is an object</li>
575          * <li><b>array</b>: If the object passed is an array</li>
576          * <li><b>regexp</b>: If the object passed is a regular expression</li>
577          * <li><b>element</b>: If the object passed is a DOM Element</li>
578          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581          * @param {Mixed} object
582          * @return {String}
583          */
584         type : function(o){
585             if(o === undefined || o === null){
586                 return false;
587             }
588             if(o.htmlElement){
589                 return 'element';
590             }
591             var t = typeof o;
592             if(t == 'object' && o.nodeName) {
593                 switch(o.nodeType) {
594                     case 1: return 'element';
595                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
596                 }
597             }
598             if(t == 'object' || t == 'function') {
599                 switch(o.constructor) {
600                     case Array: return 'array';
601                     case RegExp: return 'regexp';
602                 }
603                 if(typeof o.length == 'number' && typeof o.item == 'function') {
604                     return 'nodelist';
605                 }
606             }
607             return t;
608         },
609
610         /**
611          * Returns true if the passed value is null, undefined or an empty string (optional).
612          * @param {Mixed} value The value to test
613          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
614          * @return {Boolean}
615          */
616         isEmpty : function(v, allowBlank){
617             return v === null || v === undefined || (!allowBlank ? v === '' : false);
618         },
619         
620         /** @type Boolean */
621         isOpera : isOpera,
622         /** @type Boolean */
623         isSafari : isSafari,
624         /** @type Boolean */
625         isFirefox : isFirefox,
626         /** @type Boolean */
627         isIE : isIE,
628         /** @type Boolean */
629         isIE7 : isIE7,
630         /** @type Boolean */
631         isIE11 : isIE11,
632         /** @type Boolean */
633         isEdge : isEdge,
634         /** @type Boolean */
635         isGecko : isGecko,
636         /** @type Boolean */
637         isBorderBox : isBorderBox,
638         /** @type Boolean */
639         isWindows : isWindows,
640         /** @type Boolean */
641         isLinux : isLinux,
642         /** @type Boolean */
643         isMac : isMac,
644         /** @type Boolean */
645         isIOS : isIOS,
646         /** @type Boolean */
647         isAndroid : isAndroid,
648         /** @type Boolean */
649         isTouch : isTouch,
650
651         /**
652          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653          * you may want to set this to true.
654          * @type Boolean
655          */
656         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
657         
658         
659                 
660         /**
661          * Selects a single element as a Roo Element
662          * This is about as close as you can get to jQuery's $('do crazy stuff')
663          * @param {String} selector The selector/xpath query
664          * @param {Node} root (optional) The start of the query (defaults to document).
665          * @return {Roo.Element}
666          */
667         selectNode : function(selector, root) 
668         {
669             var node = Roo.DomQuery.selectNode(selector,root);
670             return node ? Roo.get(node) : new Roo.Element(false);
671         }
672         
673     });
674
675
676 })();
677
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
680                 "Roo.app", "Roo.ux",
681                 "Roo.bootstrap",
682                 "Roo.bootstrap.dash");
683 /*
684  * Based on:
685  * Ext JS Library 1.1.1
686  * Copyright(c) 2006-2007, Ext JS, LLC.
687  *
688  * Originally Released Under LGPL - original licence link has changed is not relivant.
689  *
690  * Fork - LGPL
691  * <script type="text/javascript">
692  */
693
694 (function() {    
695     // wrappedn so fnCleanup is not in global scope...
696     if(Roo.isIE) {
697         function fnCleanUp() {
698             var p = Function.prototype;
699             delete p.createSequence;
700             delete p.defer;
701             delete p.createDelegate;
702             delete p.createCallback;
703             delete p.createInterceptor;
704
705             window.detachEvent("onunload", fnCleanUp);
706         }
707         window.attachEvent("onunload", fnCleanUp);
708     }
709 })();
710
711
712 /**
713  * @class Function
714  * These functions are available on every Function object (any JavaScript function).
715  */
716 Roo.apply(Function.prototype, {
717      /**
718      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720      * Will create a function that is bound to those 2 args.
721      * @return {Function} The new function
722     */
723     createCallback : function(/*args...*/){
724         // make args available, in function below
725         var args = arguments;
726         var method = this;
727         return function() {
728             return method.apply(window, args);
729         };
730     },
731
732     /**
733      * Creates a delegate (callback) that sets the scope to obj.
734      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735      * Will create a function that is automatically scoped to this.
736      * @param {Object} obj (optional) The object for which the scope is set
737      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739      *                                             if a number the args are inserted at the specified position
740      * @return {Function} The new function
741      */
742     createDelegate : function(obj, args, appendArgs){
743         var method = this;
744         return function() {
745             var callArgs = args || arguments;
746             if(appendArgs === true){
747                 callArgs = Array.prototype.slice.call(arguments, 0);
748                 callArgs = callArgs.concat(args);
749             }else if(typeof appendArgs == "number"){
750                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
753             }
754             return method.apply(obj || window, callArgs);
755         };
756     },
757
758     /**
759      * Calls this function after the number of millseconds specified.
760      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761      * @param {Object} obj (optional) The object for which the scope is set
762      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764      *                                             if a number the args are inserted at the specified position
765      * @return {Number} The timeout id that can be used with clearTimeout
766      */
767     defer : function(millis, obj, args, appendArgs){
768         var fn = this.createDelegate(obj, args, appendArgs);
769         if(millis){
770             return setTimeout(fn, millis);
771         }
772         fn();
773         return 0;
774     },
775     /**
776      * Create a combined function call sequence of the original function + the passed function.
777      * The resulting function returns the results of the original function.
778      * The passed fcn is called with the parameters of the original function
779      * @param {Function} fcn The function to sequence
780      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781      * @return {Function} The new function
782      */
783     createSequence : function(fcn, scope){
784         if(typeof fcn != "function"){
785             return this;
786         }
787         var method = this;
788         return function() {
789             var retval = method.apply(this || window, arguments);
790             fcn.apply(scope || this || window, arguments);
791             return retval;
792         };
793     },
794
795     /**
796      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797      * The resulting function returns the results of the original function.
798      * The passed fcn is called with the parameters of the original function.
799      * @addon
800      * @param {Function} fcn The function to call before the original
801      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802      * @return {Function} The new function
803      */
804     createInterceptor : function(fcn, scope){
805         if(typeof fcn != "function"){
806             return this;
807         }
808         var method = this;
809         return function() {
810             fcn.target = this;
811             fcn.method = method;
812             if(fcn.apply(scope || this || window, arguments) === false){
813                 return;
814             }
815             return method.apply(this || window, arguments);
816         };
817     }
818 });
819 /*
820  * Based on:
821  * Ext JS Library 1.1.1
822  * Copyright(c) 2006-2007, Ext JS, LLC.
823  *
824  * Originally Released Under LGPL - original licence link has changed is not relivant.
825  *
826  * Fork - LGPL
827  * <script type="text/javascript">
828  */
829
830 Roo.applyIf(String, {
831     
832     /** @scope String */
833     
834     /**
835      * Escapes the passed string for ' and \
836      * @param {String} string The string to escape
837      * @return {String} The escaped string
838      * @static
839      */
840     escape : function(string) {
841         return string.replace(/('|\\)/g, "\\$1");
842     },
843
844     /**
845      * Pads the left side of a string with a specified character.  This is especially useful
846      * for normalizing number and date strings.  Example usage:
847      * <pre><code>
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
850 </code></pre>
851      * @param {String} string The original string
852      * @param {Number} size The total length of the output string
853      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854      * @return {String} The padded string
855      * @static
856      */
857     leftPad : function (val, size, ch) {
858         var result = new String(val);
859         if(ch === null || ch === undefined || ch === '') {
860             ch = " ";
861         }
862         while (result.length < size) {
863             result = ch + result;
864         }
865         return result;
866     },
867
868     /**
869      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
870      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
871      * <pre><code>
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
875 </code></pre>
876      * @param {String} string The tokenized string to be formatted
877      * @param {String} value1 The value to replace token {0}
878      * @param {String} value2 Etc...
879      * @return {String} The formatted string
880      * @static
881      */
882     format : function(format){
883         var args = Array.prototype.slice.call(arguments, 1);
884         return format.replace(/\{(\d+)\}/g, function(m, i){
885             return Roo.util.Format.htmlEncode(args[i]);
886         });
887     }
888   
889     
890 });
891
892 /**
893  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
894  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
895  * they are already different, the first value passed in is returned.  Note that this method returns the new value
896  * but does not change the current string.
897  * <pre><code>
898 // alternate sort directions
899 sort = sort.toggle('ASC', 'DESC');
900
901 // instead of conditional logic:
902 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
903 </code></pre>
904  * @param {String} value The value to compare to the current string
905  * @param {String} other The new value to use if the string already equals the first value passed in
906  * @return {String} The new value
907  */
908  
909 String.prototype.toggle = function(value, other){
910     return this == value ? other : value;
911 };
912
913
914 /**
915   * Remove invalid unicode characters from a string 
916   *
917   * @return {String} The clean string
918   */
919 String.prototype.unicodeClean = function () {
920     return this.replace(/[\s\S]/g,
921         function(character) {
922             if (character.charCodeAt()< 256) {
923               return character;
924            }
925            try {
926                 encodeURIComponent(character);
927            } catch(e) { 
928               return '';
929            }
930            return character;
931         }
932     );
933 };
934   
935 /*
936  * Based on:
937  * Ext JS Library 1.1.1
938  * Copyright(c) 2006-2007, Ext JS, LLC.
939  *
940  * Originally Released Under LGPL - original licence link has changed is not relivant.
941  *
942  * Fork - LGPL
943  * <script type="text/javascript">
944  */
945
946  /**
947  * @class Number
948  */
949 Roo.applyIf(Number.prototype, {
950     /**
951      * Checks whether or not the current number is within a desired range.  If the number is already within the
952      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
953      * exceeded.  Note that this method returns the constrained value but does not change the current number.
954      * @param {Number} min The minimum number in the range
955      * @param {Number} max The maximum number in the range
956      * @return {Number} The constrained value if outside the range, otherwise the current value
957      */
958     constrain : function(min, max){
959         return Math.min(Math.max(this, min), max);
960     }
961 });/*
962  * Based on:
963  * Ext JS Library 1.1.1
964  * Copyright(c) 2006-2007, Ext JS, LLC.
965  *
966  * Originally Released Under LGPL - original licence link has changed is not relivant.
967  *
968  * Fork - LGPL
969  * <script type="text/javascript">
970  */
971  /**
972  * @class Array
973  */
974 Roo.applyIf(Array.prototype, {
975     /**
976      * 
977      * Checks whether or not the specified object exists in the array.
978      * @param {Object} o The object to check for
979      * @return {Number} The index of o in the array (or -1 if it is not found)
980      */
981     indexOf : function(o){
982        for (var i = 0, len = this.length; i < len; i++){
983               if(this[i] == o) { return i; }
984        }
985            return -1;
986     },
987
988     /**
989      * Removes the specified object from the array.  If the object is not found nothing happens.
990      * @param {Object} o The object to remove
991      */
992     remove : function(o){
993        var index = this.indexOf(o);
994        if(index != -1){
995            this.splice(index, 1);
996        }
997     },
998     /**
999      * Map (JS 1.6 compatibility)
1000      * @param {Function} function  to call
1001      */
1002     map : function(fun )
1003     {
1004         var len = this.length >>> 0;
1005         if (typeof fun != "function") {
1006             throw new TypeError();
1007         }
1008         var res = new Array(len);
1009         var thisp = arguments[1];
1010         for (var i = 0; i < len; i++)
1011         {
1012             if (i in this) {
1013                 res[i] = fun.call(thisp, this[i], i, this);
1014             }
1015         }
1016
1017         return res;
1018     }
1019     
1020 });
1021
1022
1023  
1024 /*
1025  * Based on:
1026  * Ext JS Library 1.1.1
1027  * Copyright(c) 2006-2007, Ext JS, LLC.
1028  *
1029  * Originally Released Under LGPL - original licence link has changed is not relivant.
1030  *
1031  * Fork - LGPL
1032  * <script type="text/javascript">
1033  */
1034
1035 /**
1036  * @class Date
1037  *
1038  * The date parsing and format syntax is a subset of
1039  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1040  * supported will provide results equivalent to their PHP versions.
1041  *
1042  * Following is the list of all currently supported formats:
1043  *<pre>
1044 Sample date:
1045 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1046
1047 Format  Output      Description
1048 ------  ----------  --------------------------------------------------------------
1049   d      10         Day of the month, 2 digits with leading zeros
1050   D      Wed        A textual representation of a day, three letters
1051   j      10         Day of the month without leading zeros
1052   l      Wednesday  A full textual representation of the day of the week
1053   S      th         English ordinal day of month suffix, 2 chars (use with j)
1054   w      3          Numeric representation of the day of the week
1055   z      9          The julian date, or day of the year (0-365)
1056   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1057   F      January    A full textual representation of the month
1058   m      01         Numeric representation of a month, with leading zeros
1059   M      Jan        Month name abbreviation, three letters
1060   n      1          Numeric representation of a month, without leading zeros
1061   t      31         Number of days in the given month
1062   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1063   Y      2007       A full numeric representation of a year, 4 digits
1064   y      07         A two digit representation of a year
1065   a      pm         Lowercase Ante meridiem and Post meridiem
1066   A      PM         Uppercase Ante meridiem and Post meridiem
1067   g      3          12-hour format of an hour without leading zeros
1068   G      15         24-hour format of an hour without leading zeros
1069   h      03         12-hour format of an hour with leading zeros
1070   H      15         24-hour format of an hour with leading zeros
1071   i      05         Minutes with leading zeros
1072   s      01         Seconds, with leading zeros
1073   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1074   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1075   T      CST        Timezone setting of the machine running the code
1076   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1077 </pre>
1078  *
1079  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1080  * <pre><code>
1081 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1082 document.write(dt.format('Y-m-d'));                         //2007-01-10
1083 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1084 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
1085  </code></pre>
1086  *
1087  * Here are some standard date/time patterns that you might find helpful.  They
1088  * are not part of the source of Date.js, but to use them you can simply copy this
1089  * block of code into any script that is included after Date.js and they will also become
1090  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1091  * <pre><code>
1092 Date.patterns = {
1093     ISO8601Long:"Y-m-d H:i:s",
1094     ISO8601Short:"Y-m-d",
1095     ShortDate: "n/j/Y",
1096     LongDate: "l, F d, Y",
1097     FullDateTime: "l, F d, Y g:i:s A",
1098     MonthDay: "F d",
1099     ShortTime: "g:i A",
1100     LongTime: "g:i:s A",
1101     SortableDateTime: "Y-m-d\\TH:i:s",
1102     UniversalSortableDateTime: "Y-m-d H:i:sO",
1103     YearMonth: "F, Y"
1104 };
1105 </code></pre>
1106  *
1107  * Example usage:
1108  * <pre><code>
1109 var dt = new Date();
1110 document.write(dt.format(Date.patterns.ShortDate));
1111  </code></pre>
1112  */
1113
1114 /*
1115  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1116  * They generate precompiled functions from date formats instead of parsing and
1117  * processing the pattern every time you format a date.  These functions are available
1118  * on every Date object (any javascript function).
1119  *
1120  * The original article and download are here:
1121  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1122  *
1123  */
1124  
1125  
1126  // was in core
1127 /**
1128  Returns the number of milliseconds between this date and date
1129  @param {Date} date (optional) Defaults to now
1130  @return {Number} The diff in milliseconds
1131  @member Date getElapsed
1132  */
1133 Date.prototype.getElapsed = function(date) {
1134         return Math.abs((date || new Date()).getTime()-this.getTime());
1135 };
1136 // was in date file..
1137
1138
1139 // private
1140 Date.parseFunctions = {count:0};
1141 // private
1142 Date.parseRegexes = [];
1143 // private
1144 Date.formatFunctions = {count:0};
1145
1146 // private
1147 Date.prototype.dateFormat = function(format) {
1148     if (Date.formatFunctions[format] == null) {
1149         Date.createNewFormat(format);
1150     }
1151     var func = Date.formatFunctions[format];
1152     return this[func]();
1153 };
1154
1155
1156 /**
1157  * Formats a date given the supplied format string
1158  * @param {String} format The format string
1159  * @return {String} The formatted date
1160  * @method
1161  */
1162 Date.prototype.format = Date.prototype.dateFormat;
1163
1164 // private
1165 Date.createNewFormat = function(format) {
1166     var funcName = "format" + Date.formatFunctions.count++;
1167     Date.formatFunctions[format] = funcName;
1168     var code = "Date.prototype." + funcName + " = function(){return ";
1169     var special = false;
1170     var ch = '';
1171     for (var i = 0; i < format.length; ++i) {
1172         ch = format.charAt(i);
1173         if (!special && ch == "\\") {
1174             special = true;
1175         }
1176         else if (special) {
1177             special = false;
1178             code += "'" + String.escape(ch) + "' + ";
1179         }
1180         else {
1181             code += Date.getFormatCode(ch);
1182         }
1183     }
1184     /** eval:var:zzzzzzzzzzzzz */
1185     eval(code.substring(0, code.length - 3) + ";}");
1186 };
1187
1188 // private
1189 Date.getFormatCode = function(character) {
1190     switch (character) {
1191     case "d":
1192         return "String.leftPad(this.getDate(), 2, '0') + ";
1193     case "D":
1194         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1195     case "j":
1196         return "this.getDate() + ";
1197     case "l":
1198         return "Date.dayNames[this.getDay()] + ";
1199     case "S":
1200         return "this.getSuffix() + ";
1201     case "w":
1202         return "this.getDay() + ";
1203     case "z":
1204         return "this.getDayOfYear() + ";
1205     case "W":
1206         return "this.getWeekOfYear() + ";
1207     case "F":
1208         return "Date.monthNames[this.getMonth()] + ";
1209     case "m":
1210         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1211     case "M":
1212         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1213     case "n":
1214         return "(this.getMonth() + 1) + ";
1215     case "t":
1216         return "this.getDaysInMonth() + ";
1217     case "L":
1218         return "(this.isLeapYear() ? 1 : 0) + ";
1219     case "Y":
1220         return "this.getFullYear() + ";
1221     case "y":
1222         return "('' + this.getFullYear()).substring(2, 4) + ";
1223     case "a":
1224         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1225     case "A":
1226         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1227     case "g":
1228         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1229     case "G":
1230         return "this.getHours() + ";
1231     case "h":
1232         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1233     case "H":
1234         return "String.leftPad(this.getHours(), 2, '0') + ";
1235     case "i":
1236         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1237     case "s":
1238         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1239     case "O":
1240         return "this.getGMTOffset() + ";
1241     case "P":
1242         return "this.getGMTColonOffset() + ";
1243     case "T":
1244         return "this.getTimezone() + ";
1245     case "Z":
1246         return "(this.getTimezoneOffset() * -60) + ";
1247     default:
1248         return "'" + String.escape(character) + "' + ";
1249     }
1250 };
1251
1252 /**
1253  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1254  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1255  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1256  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1257  * string or the parse operation will fail.
1258  * Example Usage:
1259 <pre><code>
1260 //dt = Fri May 25 2007 (current date)
1261 var dt = new Date();
1262
1263 //dt = Thu May 25 2006 (today's month/day in 2006)
1264 dt = Date.parseDate("2006", "Y");
1265
1266 //dt = Sun Jan 15 2006 (all date parts specified)
1267 dt = Date.parseDate("2006-1-15", "Y-m-d");
1268
1269 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1270 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1271 </code></pre>
1272  * @param {String} input The unparsed date as a string
1273  * @param {String} format The format the date is in
1274  * @return {Date} The parsed date
1275  * @static
1276  */
1277 Date.parseDate = function(input, format) {
1278     if (Date.parseFunctions[format] == null) {
1279         Date.createParser(format);
1280     }
1281     var func = Date.parseFunctions[format];
1282     return Date[func](input);
1283 };
1284 /**
1285  * @private
1286  */
1287
1288 Date.createParser = function(format) {
1289     var funcName = "parse" + Date.parseFunctions.count++;
1290     var regexNum = Date.parseRegexes.length;
1291     var currentGroup = 1;
1292     Date.parseFunctions[format] = funcName;
1293
1294     var code = "Date." + funcName + " = function(input){\n"
1295         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1296         + "var d = new Date();\n"
1297         + "y = d.getFullYear();\n"
1298         + "m = d.getMonth();\n"
1299         + "d = d.getDate();\n"
1300         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1301         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1302         + "if (results && results.length > 0) {";
1303     var regex = "";
1304
1305     var special = false;
1306     var ch = '';
1307     for (var i = 0; i < format.length; ++i) {
1308         ch = format.charAt(i);
1309         if (!special && ch == "\\") {
1310             special = true;
1311         }
1312         else if (special) {
1313             special = false;
1314             regex += String.escape(ch);
1315         }
1316         else {
1317             var obj = Date.formatCodeToRegex(ch, currentGroup);
1318             currentGroup += obj.g;
1319             regex += obj.s;
1320             if (obj.g && obj.c) {
1321                 code += obj.c;
1322             }
1323         }
1324     }
1325
1326     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1327         + "{v = new Date(y, m, d, h, i, s);}\n"
1328         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1329         + "{v = new Date(y, m, d, h, i);}\n"
1330         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1331         + "{v = new Date(y, m, d, h);}\n"
1332         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1333         + "{v = new Date(y, m, d);}\n"
1334         + "else if (y >= 0 && m >= 0)\n"
1335         + "{v = new Date(y, m);}\n"
1336         + "else if (y >= 0)\n"
1337         + "{v = new Date(y);}\n"
1338         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1339         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1340         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1341         + ";}";
1342
1343     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1344     /** eval:var:zzzzzzzzzzzzz */
1345     eval(code);
1346 };
1347
1348 // private
1349 Date.formatCodeToRegex = function(character, currentGroup) {
1350     switch (character) {
1351     case "D":
1352         return {g:0,
1353         c:null,
1354         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1355     case "j":
1356         return {g:1,
1357             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1358             s:"(\\d{1,2})"}; // day of month without leading zeroes
1359     case "d":
1360         return {g:1,
1361             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1362             s:"(\\d{2})"}; // day of month with leading zeroes
1363     case "l":
1364         return {g:0,
1365             c:null,
1366             s:"(?:" + Date.dayNames.join("|") + ")"};
1367     case "S":
1368         return {g:0,
1369             c:null,
1370             s:"(?:st|nd|rd|th)"};
1371     case "w":
1372         return {g:0,
1373             c:null,
1374             s:"\\d"};
1375     case "z":
1376         return {g:0,
1377             c:null,
1378             s:"(?:\\d{1,3})"};
1379     case "W":
1380         return {g:0,
1381             c:null,
1382             s:"(?:\\d{2})"};
1383     case "F":
1384         return {g:1,
1385             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1386             s:"(" + Date.monthNames.join("|") + ")"};
1387     case "M":
1388         return {g:1,
1389             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1390             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1391     case "n":
1392         return {g:1,
1393             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1394             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1395     case "m":
1396         return {g:1,
1397             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1398             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1399     case "t":
1400         return {g:0,
1401             c:null,
1402             s:"\\d{1,2}"};
1403     case "L":
1404         return {g:0,
1405             c:null,
1406             s:"(?:1|0)"};
1407     case "Y":
1408         return {g:1,
1409             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1410             s:"(\\d{4})"};
1411     case "y":
1412         return {g:1,
1413             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1414                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1415             s:"(\\d{1,2})"};
1416     case "a":
1417         return {g:1,
1418             c:"if (results[" + currentGroup + "] == 'am') {\n"
1419                 + "if (h == 12) { h = 0; }\n"
1420                 + "} else { if (h < 12) { h += 12; }}",
1421             s:"(am|pm)"};
1422     case "A":
1423         return {g:1,
1424             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1425                 + "if (h == 12) { h = 0; }\n"
1426                 + "} else { if (h < 12) { h += 12; }}",
1427             s:"(AM|PM)"};
1428     case "g":
1429     case "G":
1430         return {g:1,
1431             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1432             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1433     case "h":
1434     case "H":
1435         return {g:1,
1436             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1437             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1438     case "i":
1439         return {g:1,
1440             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1441             s:"(\\d{2})"};
1442     case "s":
1443         return {g:1,
1444             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1445             s:"(\\d{2})"};
1446     case "O":
1447         return {g:1,
1448             c:[
1449                 "o = results[", currentGroup, "];\n",
1450                 "var sn = o.substring(0,1);\n", // get + / - sign
1451                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1452                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1453                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1454                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1455             ].join(""),
1456             s:"([+\-]\\d{2,4})"};
1457     
1458     
1459     case "P":
1460         return {g:1,
1461                 c:[
1462                    "o = results[", currentGroup, "];\n",
1463                    "var sn = o.substring(0,1);\n",
1464                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1465                    "var mn = o.substring(4,6) % 60;\n",
1466                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1467                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1468             ].join(""),
1469             s:"([+\-]\\d{4})"};
1470     case "T":
1471         return {g:0,
1472             c:null,
1473             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1474     case "Z":
1475         return {g:1,
1476             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1477                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1478             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1479     default:
1480         return {g:0,
1481             c:null,
1482             s:String.escape(character)};
1483     }
1484 };
1485
1486 /**
1487  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1488  * @return {String} The abbreviated timezone name (e.g. 'CST')
1489  */
1490 Date.prototype.getTimezone = function() {
1491     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1492 };
1493
1494 /**
1495  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1496  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1497  */
1498 Date.prototype.getGMTOffset = function() {
1499     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1500         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1501         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1502 };
1503
1504 /**
1505  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1506  * @return {String} 2-characters representing hours and 2-characters representing minutes
1507  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1508  */
1509 Date.prototype.getGMTColonOffset = function() {
1510         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1511                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1512                 + ":"
1513                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1514 }
1515
1516 /**
1517  * Get the numeric day number of the year, adjusted for leap year.
1518  * @return {Number} 0 through 364 (365 in leap years)
1519  */
1520 Date.prototype.getDayOfYear = function() {
1521     var num = 0;
1522     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1523     for (var i = 0; i < this.getMonth(); ++i) {
1524         num += Date.daysInMonth[i];
1525     }
1526     return num + this.getDate() - 1;
1527 };
1528
1529 /**
1530  * Get the string representation of the numeric week number of the year
1531  * (equivalent to the format specifier 'W').
1532  * @return {String} '00' through '52'
1533  */
1534 Date.prototype.getWeekOfYear = function() {
1535     // Skip to Thursday of this week
1536     var now = this.getDayOfYear() + (4 - this.getDay());
1537     // Find the first Thursday of the year
1538     var jan1 = new Date(this.getFullYear(), 0, 1);
1539     var then = (7 - jan1.getDay() + 4);
1540     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1541 };
1542
1543 /**
1544  * Whether or not the current date is in a leap year.
1545  * @return {Boolean} True if the current date is in a leap year, else false
1546  */
1547 Date.prototype.isLeapYear = function() {
1548     var year = this.getFullYear();
1549     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1550 };
1551
1552 /**
1553  * Get the first day of the current month, adjusted for leap year.  The returned value
1554  * is the numeric day index within the week (0-6) which can be used in conjunction with
1555  * the {@link #monthNames} array to retrieve the textual day name.
1556  * Example:
1557  *<pre><code>
1558 var dt = new Date('1/10/2007');
1559 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1560 </code></pre>
1561  * @return {Number} The day number (0-6)
1562  */
1563 Date.prototype.getFirstDayOfMonth = function() {
1564     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1565     return (day < 0) ? (day + 7) : day;
1566 };
1567
1568 /**
1569  * Get the last day of the current month, adjusted for leap year.  The returned value
1570  * is the numeric day index within the week (0-6) which can be used in conjunction with
1571  * the {@link #monthNames} array to retrieve the textual day name.
1572  * Example:
1573  *<pre><code>
1574 var dt = new Date('1/10/2007');
1575 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1576 </code></pre>
1577  * @return {Number} The day number (0-6)
1578  */
1579 Date.prototype.getLastDayOfMonth = function() {
1580     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1581     return (day < 0) ? (day + 7) : day;
1582 };
1583
1584
1585 /**
1586  * Get the first date of this date's month
1587  * @return {Date}
1588  */
1589 Date.prototype.getFirstDateOfMonth = function() {
1590     return new Date(this.getFullYear(), this.getMonth(), 1);
1591 };
1592
1593 /**
1594  * Get the last date of this date's month
1595  * @return {Date}
1596  */
1597 Date.prototype.getLastDateOfMonth = function() {
1598     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1599 };
1600 /**
1601  * Get the number of days in the current month, adjusted for leap year.
1602  * @return {Number} The number of days in the month
1603  */
1604 Date.prototype.getDaysInMonth = function() {
1605     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1606     return Date.daysInMonth[this.getMonth()];
1607 };
1608
1609 /**
1610  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1611  * @return {String} 'st, 'nd', 'rd' or 'th'
1612  */
1613 Date.prototype.getSuffix = function() {
1614     switch (this.getDate()) {
1615         case 1:
1616         case 21:
1617         case 31:
1618             return "st";
1619         case 2:
1620         case 22:
1621             return "nd";
1622         case 3:
1623         case 23:
1624             return "rd";
1625         default:
1626             return "th";
1627     }
1628 };
1629
1630 // private
1631 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1632
1633 /**
1634  * An array of textual month names.
1635  * Override these values for international dates, for example...
1636  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1637  * @type Array
1638  * @static
1639  */
1640 Date.monthNames =
1641    ["January",
1642     "February",
1643     "March",
1644     "April",
1645     "May",
1646     "June",
1647     "July",
1648     "August",
1649     "September",
1650     "October",
1651     "November",
1652     "December"];
1653
1654 /**
1655  * An array of textual day names.
1656  * Override these values for international dates, for example...
1657  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1658  * @type Array
1659  * @static
1660  */
1661 Date.dayNames =
1662    ["Sunday",
1663     "Monday",
1664     "Tuesday",
1665     "Wednesday",
1666     "Thursday",
1667     "Friday",
1668     "Saturday"];
1669
1670 // private
1671 Date.y2kYear = 50;
1672 // private
1673 Date.monthNumbers = {
1674     Jan:0,
1675     Feb:1,
1676     Mar:2,
1677     Apr:3,
1678     May:4,
1679     Jun:5,
1680     Jul:6,
1681     Aug:7,
1682     Sep:8,
1683     Oct:9,
1684     Nov:10,
1685     Dec:11};
1686
1687 /**
1688  * Creates and returns a new Date instance with the exact same date value as the called instance.
1689  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1690  * variable will also be changed.  When the intention is to create a new variable that will not
1691  * modify the original instance, you should create a clone.
1692  *
1693  * Example of correctly cloning a date:
1694  * <pre><code>
1695 //wrong way:
1696 var orig = new Date('10/1/2006');
1697 var copy = orig;
1698 copy.setDate(5);
1699 document.write(orig);  //returns 'Thu Oct 05 2006'!
1700
1701 //correct way:
1702 var orig = new Date('10/1/2006');
1703 var copy = orig.clone();
1704 copy.setDate(5);
1705 document.write(orig);  //returns 'Thu Oct 01 2006'
1706 </code></pre>
1707  * @return {Date} The new Date instance
1708  */
1709 Date.prototype.clone = function() {
1710         return new Date(this.getTime());
1711 };
1712
1713 /**
1714  * Clears any time information from this date
1715  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1716  @return {Date} this or the clone
1717  */
1718 Date.prototype.clearTime = function(clone){
1719     if(clone){
1720         return this.clone().clearTime();
1721     }
1722     this.setHours(0);
1723     this.setMinutes(0);
1724     this.setSeconds(0);
1725     this.setMilliseconds(0);
1726     return this;
1727 };
1728
1729 // private
1730 // safari setMonth is broken -- check that this is only donw once...
1731 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1732     Date.brokenSetMonth = Date.prototype.setMonth;
1733         Date.prototype.setMonth = function(num){
1734                 if(num <= -1){
1735                         var n = Math.ceil(-num);
1736                         var back_year = Math.ceil(n/12);
1737                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1738                         this.setFullYear(this.getFullYear() - back_year);
1739                         return Date.brokenSetMonth.call(this, month);
1740                 } else {
1741                         return Date.brokenSetMonth.apply(this, arguments);
1742                 }
1743         };
1744 }
1745
1746 /** Date interval constant 
1747 * @static 
1748 * @type String */
1749 Date.MILLI = "ms";
1750 /** Date interval constant 
1751 * @static 
1752 * @type String */
1753 Date.SECOND = "s";
1754 /** Date interval constant 
1755 * @static 
1756 * @type String */
1757 Date.MINUTE = "mi";
1758 /** Date interval constant 
1759 * @static 
1760 * @type String */
1761 Date.HOUR = "h";
1762 /** Date interval constant 
1763 * @static 
1764 * @type String */
1765 Date.DAY = "d";
1766 /** Date interval constant 
1767 * @static 
1768 * @type String */
1769 Date.MONTH = "mo";
1770 /** Date interval constant 
1771 * @static 
1772 * @type String */
1773 Date.YEAR = "y";
1774
1775 /**
1776  * Provides a convenient method of performing basic date arithmetic.  This method
1777  * does not modify the Date instance being called - it creates and returns
1778  * a new Date instance containing the resulting date value.
1779  *
1780  * Examples:
1781  * <pre><code>
1782 //Basic usage:
1783 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1784 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1785
1786 //Negative values will subtract correctly:
1787 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1788 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1789
1790 //You can even chain several calls together in one line!
1791 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1792 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1793  </code></pre>
1794  *
1795  * @param {String} interval   A valid date interval enum value
1796  * @param {Number} value      The amount to add to the current date
1797  * @return {Date} The new Date instance
1798  */
1799 Date.prototype.add = function(interval, value){
1800   var d = this.clone();
1801   if (!interval || value === 0) { return d; }
1802   switch(interval.toLowerCase()){
1803     case Date.MILLI:
1804       d.setMilliseconds(this.getMilliseconds() + value);
1805       break;
1806     case Date.SECOND:
1807       d.setSeconds(this.getSeconds() + value);
1808       break;
1809     case Date.MINUTE:
1810       d.setMinutes(this.getMinutes() + value);
1811       break;
1812     case Date.HOUR:
1813       d.setHours(this.getHours() + value);
1814       break;
1815     case Date.DAY:
1816       d.setDate(this.getDate() + value);
1817       break;
1818     case Date.MONTH:
1819       var day = this.getDate();
1820       if(day > 28){
1821           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1822       }
1823       d.setDate(day);
1824       d.setMonth(this.getMonth() + value);
1825       break;
1826     case Date.YEAR:
1827       d.setFullYear(this.getFullYear() + value);
1828       break;
1829   }
1830   return d;
1831 };
1832 /*
1833  * Based on:
1834  * Ext JS Library 1.1.1
1835  * Copyright(c) 2006-2007, Ext JS, LLC.
1836  *
1837  * Originally Released Under LGPL - original licence link has changed is not relivant.
1838  *
1839  * Fork - LGPL
1840  * <script type="text/javascript">
1841  */
1842
1843 /**
1844  * @class Roo.lib.Dom
1845  * @static
1846  * 
1847  * Dom utils (from YIU afaik)
1848  * 
1849  **/
1850 Roo.lib.Dom = {
1851     /**
1852      * Get the view width
1853      * @param {Boolean} full True will get the full document, otherwise it's the view width
1854      * @return {Number} The width
1855      */
1856      
1857     getViewWidth : function(full) {
1858         return full ? this.getDocumentWidth() : this.getViewportWidth();
1859     },
1860     /**
1861      * Get the view height
1862      * @param {Boolean} full True will get the full document, otherwise it's the view height
1863      * @return {Number} The height
1864      */
1865     getViewHeight : function(full) {
1866         return full ? this.getDocumentHeight() : this.getViewportHeight();
1867     },
1868
1869     getDocumentHeight: function() {
1870         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1871         return Math.max(scrollHeight, this.getViewportHeight());
1872     },
1873
1874     getDocumentWidth: function() {
1875         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1876         return Math.max(scrollWidth, this.getViewportWidth());
1877     },
1878
1879     getViewportHeight: function() {
1880         var height = self.innerHeight;
1881         var mode = document.compatMode;
1882
1883         if ((mode || Roo.isIE) && !Roo.isOpera) {
1884             height = (mode == "CSS1Compat") ?
1885                      document.documentElement.clientHeight :
1886                      document.body.clientHeight;
1887         }
1888
1889         return height;
1890     },
1891
1892     getViewportWidth: function() {
1893         var width = self.innerWidth;
1894         var mode = document.compatMode;
1895
1896         if (mode || Roo.isIE) {
1897             width = (mode == "CSS1Compat") ?
1898                     document.documentElement.clientWidth :
1899                     document.body.clientWidth;
1900         }
1901         return width;
1902     },
1903
1904     isAncestor : function(p, c) {
1905         p = Roo.getDom(p);
1906         c = Roo.getDom(c);
1907         if (!p || !c) {
1908             return false;
1909         }
1910
1911         if (p.contains && !Roo.isSafari) {
1912             return p.contains(c);
1913         } else if (p.compareDocumentPosition) {
1914             return !!(p.compareDocumentPosition(c) & 16);
1915         } else {
1916             var parent = c.parentNode;
1917             while (parent) {
1918                 if (parent == p) {
1919                     return true;
1920                 }
1921                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1922                     return false;
1923                 }
1924                 parent = parent.parentNode;
1925             }
1926             return false;
1927         }
1928     },
1929
1930     getRegion : function(el) {
1931         return Roo.lib.Region.getRegion(el);
1932     },
1933
1934     getY : function(el) {
1935         return this.getXY(el)[1];
1936     },
1937
1938     getX : function(el) {
1939         return this.getXY(el)[0];
1940     },
1941
1942     getXY : function(el) {
1943         var p, pe, b, scroll, bd = document.body;
1944         el = Roo.getDom(el);
1945         var fly = Roo.lib.AnimBase.fly;
1946         if (el.getBoundingClientRect) {
1947             b = el.getBoundingClientRect();
1948             scroll = fly(document).getScroll();
1949             return [b.left + scroll.left, b.top + scroll.top];
1950         }
1951         var x = 0, y = 0;
1952
1953         p = el;
1954
1955         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1956
1957         while (p) {
1958
1959             x += p.offsetLeft;
1960             y += p.offsetTop;
1961
1962             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1963                 hasAbsolute = true;
1964             }
1965
1966             if (Roo.isGecko) {
1967                 pe = fly(p);
1968
1969                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1970                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1971
1972
1973                 x += bl;
1974                 y += bt;
1975
1976
1977                 if (p != el && pe.getStyle('overflow') != 'visible') {
1978                     x += bl;
1979                     y += bt;
1980                 }
1981             }
1982             p = p.offsetParent;
1983         }
1984
1985         if (Roo.isSafari && hasAbsolute) {
1986             x -= bd.offsetLeft;
1987             y -= bd.offsetTop;
1988         }
1989
1990         if (Roo.isGecko && !hasAbsolute) {
1991             var dbd = fly(bd);
1992             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1993             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1994         }
1995
1996         p = el.parentNode;
1997         while (p && p != bd) {
1998             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1999                 x -= p.scrollLeft;
2000                 y -= p.scrollTop;
2001             }
2002             p = p.parentNode;
2003         }
2004         return [x, y];
2005     },
2006  
2007   
2008
2009
2010     setXY : function(el, xy) {
2011         el = Roo.fly(el, '_setXY');
2012         el.position();
2013         var pts = el.translatePoints(xy);
2014         if (xy[0] !== false) {
2015             el.dom.style.left = pts.left + "px";
2016         }
2017         if (xy[1] !== false) {
2018             el.dom.style.top = pts.top + "px";
2019         }
2020     },
2021
2022     setX : function(el, x) {
2023         this.setXY(el, [x, false]);
2024     },
2025
2026     setY : function(el, y) {
2027         this.setXY(el, [false, y]);
2028     }
2029 };
2030 /*
2031  * Portions of this file are based on pieces of Yahoo User Interface Library
2032  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2033  * YUI licensed under the BSD License:
2034  * http://developer.yahoo.net/yui/license.txt
2035  * <script type="text/javascript">
2036  *
2037  */
2038
2039 Roo.lib.Event = function() {
2040     var loadComplete = false;
2041     var listeners = [];
2042     var unloadListeners = [];
2043     var retryCount = 0;
2044     var onAvailStack = [];
2045     var counter = 0;
2046     var lastError = null;
2047
2048     return {
2049         POLL_RETRYS: 200,
2050         POLL_INTERVAL: 20,
2051         EL: 0,
2052         TYPE: 1,
2053         FN: 2,
2054         WFN: 3,
2055         OBJ: 3,
2056         ADJ_SCOPE: 4,
2057         _interval: null,
2058
2059         startInterval: function() {
2060             if (!this._interval) {
2061                 var self = this;
2062                 var callback = function() {
2063                     self._tryPreloadAttach();
2064                 };
2065                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2066
2067             }
2068         },
2069
2070         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2071             onAvailStack.push({ id:         p_id,
2072                 fn:         p_fn,
2073                 obj:        p_obj,
2074                 override:   p_override,
2075                 checkReady: false    });
2076
2077             retryCount = this.POLL_RETRYS;
2078             this.startInterval();
2079         },
2080
2081
2082         addListener: function(el, eventName, fn) {
2083             el = Roo.getDom(el);
2084             if (!el || !fn) {
2085                 return false;
2086             }
2087
2088             if ("unload" == eventName) {
2089                 unloadListeners[unloadListeners.length] =
2090                 [el, eventName, fn];
2091                 return true;
2092             }
2093
2094             var wrappedFn = function(e) {
2095                 return fn(Roo.lib.Event.getEvent(e));
2096             };
2097
2098             var li = [el, eventName, fn, wrappedFn];
2099
2100             var index = listeners.length;
2101             listeners[index] = li;
2102
2103             this.doAdd(el, eventName, wrappedFn, false);
2104             return true;
2105
2106         },
2107
2108
2109         removeListener: function(el, eventName, fn) {
2110             var i, len;
2111
2112             el = Roo.getDom(el);
2113
2114             if(!fn) {
2115                 return this.purgeElement(el, false, eventName);
2116             }
2117
2118
2119             if ("unload" == eventName) {
2120
2121                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2122                     var li = unloadListeners[i];
2123                     if (li &&
2124                         li[0] == el &&
2125                         li[1] == eventName &&
2126                         li[2] == fn) {
2127                         unloadListeners.splice(i, 1);
2128                         return true;
2129                     }
2130                 }
2131
2132                 return false;
2133             }
2134
2135             var cacheItem = null;
2136
2137
2138             var index = arguments[3];
2139
2140             if ("undefined" == typeof index) {
2141                 index = this._getCacheIndex(el, eventName, fn);
2142             }
2143
2144             if (index >= 0) {
2145                 cacheItem = listeners[index];
2146             }
2147
2148             if (!el || !cacheItem) {
2149                 return false;
2150             }
2151
2152             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2153
2154             delete listeners[index][this.WFN];
2155             delete listeners[index][this.FN];
2156             listeners.splice(index, 1);
2157
2158             return true;
2159
2160         },
2161
2162
2163         getTarget: function(ev, resolveTextNode) {
2164             ev = ev.browserEvent || ev;
2165             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2166             var t = ev.target || ev.srcElement;
2167             return this.resolveTextNode(t);
2168         },
2169
2170
2171         resolveTextNode: function(node) {
2172             if (Roo.isSafari && node && 3 == node.nodeType) {
2173                 return node.parentNode;
2174             } else {
2175                 return node;
2176             }
2177         },
2178
2179
2180         getPageX: function(ev) {
2181             ev = ev.browserEvent || ev;
2182             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2183             var x = ev.pageX;
2184             if (!x && 0 !== x) {
2185                 x = ev.clientX || 0;
2186
2187                 if (Roo.isIE) {
2188                     x += this.getScroll()[1];
2189                 }
2190             }
2191
2192             return x;
2193         },
2194
2195
2196         getPageY: function(ev) {
2197             ev = ev.browserEvent || ev;
2198             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2199             var y = ev.pageY;
2200             if (!y && 0 !== y) {
2201                 y = ev.clientY || 0;
2202
2203                 if (Roo.isIE) {
2204                     y += this.getScroll()[0];
2205                 }
2206             }
2207
2208
2209             return y;
2210         },
2211
2212
2213         getXY: function(ev) {
2214             ev = ev.browserEvent || ev;
2215             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2216             return [this.getPageX(ev), this.getPageY(ev)];
2217         },
2218
2219
2220         getRelatedTarget: function(ev) {
2221             ev = ev.browserEvent || ev;
2222             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2223             var t = ev.relatedTarget;
2224             if (!t) {
2225                 if (ev.type == "mouseout") {
2226                     t = ev.toElement;
2227                 } else if (ev.type == "mouseover") {
2228                     t = ev.fromElement;
2229                 }
2230             }
2231
2232             return this.resolveTextNode(t);
2233         },
2234
2235
2236         getTime: function(ev) {
2237             ev = ev.browserEvent || ev;
2238             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2239             if (!ev.time) {
2240                 var t = new Date().getTime();
2241                 try {
2242                     ev.time = t;
2243                 } catch(ex) {
2244                     this.lastError = ex;
2245                     return t;
2246                 }
2247             }
2248
2249             return ev.time;
2250         },
2251
2252
2253         stopEvent: function(ev) {
2254             this.stopPropagation(ev);
2255             this.preventDefault(ev);
2256         },
2257
2258
2259         stopPropagation: function(ev) {
2260             ev = ev.browserEvent || ev;
2261             if (ev.stopPropagation) {
2262                 ev.stopPropagation();
2263             } else {
2264                 ev.cancelBubble = true;
2265             }
2266         },
2267
2268
2269         preventDefault: function(ev) {
2270             ev = ev.browserEvent || ev;
2271             if(ev.preventDefault) {
2272                 ev.preventDefault();
2273             } else {
2274                 ev.returnValue = false;
2275             }
2276         },
2277
2278
2279         getEvent: function(e) {
2280             var ev = e || window.event;
2281             if (!ev) {
2282                 var c = this.getEvent.caller;
2283                 while (c) {
2284                     ev = c.arguments[0];
2285                     if (ev && Event == ev.constructor) {
2286                         break;
2287                     }
2288                     c = c.caller;
2289                 }
2290             }
2291             return ev;
2292         },
2293
2294
2295         getCharCode: function(ev) {
2296             ev = ev.browserEvent || ev;
2297             return ev.charCode || ev.keyCode || 0;
2298         },
2299
2300
2301         _getCacheIndex: function(el, eventName, fn) {
2302             for (var i = 0,len = listeners.length; i < len; ++i) {
2303                 var li = listeners[i];
2304                 if (li &&
2305                     li[this.FN] == fn &&
2306                     li[this.EL] == el &&
2307                     li[this.TYPE] == eventName) {
2308                     return i;
2309                 }
2310             }
2311
2312             return -1;
2313         },
2314
2315
2316         elCache: {},
2317
2318
2319         getEl: function(id) {
2320             return document.getElementById(id);
2321         },
2322
2323
2324         clearCache: function() {
2325         },
2326
2327
2328         _load: function(e) {
2329             loadComplete = true;
2330             var EU = Roo.lib.Event;
2331
2332
2333             if (Roo.isIE) {
2334                 EU.doRemove(window, "load", EU._load);
2335             }
2336         },
2337
2338
2339         _tryPreloadAttach: function() {
2340
2341             if (this.locked) {
2342                 return false;
2343             }
2344
2345             this.locked = true;
2346
2347
2348             var tryAgain = !loadComplete;
2349             if (!tryAgain) {
2350                 tryAgain = (retryCount > 0);
2351             }
2352
2353
2354             var notAvail = [];
2355             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2356                 var item = onAvailStack[i];
2357                 if (item) {
2358                     var el = this.getEl(item.id);
2359
2360                     if (el) {
2361                         if (!item.checkReady ||
2362                             loadComplete ||
2363                             el.nextSibling ||
2364                             (document && document.body)) {
2365
2366                             var scope = el;
2367                             if (item.override) {
2368                                 if (item.override === true) {
2369                                     scope = item.obj;
2370                                 } else {
2371                                     scope = item.override;
2372                                 }
2373                             }
2374                             item.fn.call(scope, item.obj);
2375                             onAvailStack[i] = null;
2376                         }
2377                     } else {
2378                         notAvail.push(item);
2379                     }
2380                 }
2381             }
2382
2383             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2384
2385             if (tryAgain) {
2386
2387                 this.startInterval();
2388             } else {
2389                 clearInterval(this._interval);
2390                 this._interval = null;
2391             }
2392
2393             this.locked = false;
2394
2395             return true;
2396
2397         },
2398
2399
2400         purgeElement: function(el, recurse, eventName) {
2401             var elListeners = this.getListeners(el, eventName);
2402             if (elListeners) {
2403                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2404                     var l = elListeners[i];
2405                     this.removeListener(el, l.type, l.fn);
2406                 }
2407             }
2408
2409             if (recurse && el && el.childNodes) {
2410                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2411                     this.purgeElement(el.childNodes[i], recurse, eventName);
2412                 }
2413             }
2414         },
2415
2416
2417         getListeners: function(el, eventName) {
2418             var results = [], searchLists;
2419             if (!eventName) {
2420                 searchLists = [listeners, unloadListeners];
2421             } else if (eventName == "unload") {
2422                 searchLists = [unloadListeners];
2423             } else {
2424                 searchLists = [listeners];
2425             }
2426
2427             for (var j = 0; j < searchLists.length; ++j) {
2428                 var searchList = searchLists[j];
2429                 if (searchList && searchList.length > 0) {
2430                     for (var i = 0,len = searchList.length; i < len; ++i) {
2431                         var l = searchList[i];
2432                         if (l && l[this.EL] === el &&
2433                             (!eventName || eventName === l[this.TYPE])) {
2434                             results.push({
2435                                 type:   l[this.TYPE],
2436                                 fn:     l[this.FN],
2437                                 obj:    l[this.OBJ],
2438                                 adjust: l[this.ADJ_SCOPE],
2439                                 index:  i
2440                             });
2441                         }
2442                     }
2443                 }
2444             }
2445
2446             return (results.length) ? results : null;
2447         },
2448
2449
2450         _unload: function(e) {
2451
2452             var EU = Roo.lib.Event, i, j, l, len, index;
2453
2454             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2455                 l = unloadListeners[i];
2456                 if (l) {
2457                     var scope = window;
2458                     if (l[EU.ADJ_SCOPE]) {
2459                         if (l[EU.ADJ_SCOPE] === true) {
2460                             scope = l[EU.OBJ];
2461                         } else {
2462                             scope = l[EU.ADJ_SCOPE];
2463                         }
2464                     }
2465                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2466                     unloadListeners[i] = null;
2467                     l = null;
2468                     scope = null;
2469                 }
2470             }
2471
2472             unloadListeners = null;
2473
2474             if (listeners && listeners.length > 0) {
2475                 j = listeners.length;
2476                 while (j) {
2477                     index = j - 1;
2478                     l = listeners[index];
2479                     if (l) {
2480                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2481                                 l[EU.FN], index);
2482                     }
2483                     j = j - 1;
2484                 }
2485                 l = null;
2486
2487                 EU.clearCache();
2488             }
2489
2490             EU.doRemove(window, "unload", EU._unload);
2491
2492         },
2493
2494
2495         getScroll: function() {
2496             var dd = document.documentElement, db = document.body;
2497             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2498                 return [dd.scrollTop, dd.scrollLeft];
2499             } else if (db) {
2500                 return [db.scrollTop, db.scrollLeft];
2501             } else {
2502                 return [0, 0];
2503             }
2504         },
2505
2506
2507         doAdd: function () {
2508             if (window.addEventListener) {
2509                 return function(el, eventName, fn, capture) {
2510                     el.addEventListener(eventName, fn, (capture));
2511                 };
2512             } else if (window.attachEvent) {
2513                 return function(el, eventName, fn, capture) {
2514                     el.attachEvent("on" + eventName, fn);
2515                 };
2516             } else {
2517                 return function() {
2518                 };
2519             }
2520         }(),
2521
2522
2523         doRemove: function() {
2524             if (window.removeEventListener) {
2525                 return function (el, eventName, fn, capture) {
2526                     el.removeEventListener(eventName, fn, (capture));
2527                 };
2528             } else if (window.detachEvent) {
2529                 return function (el, eventName, fn) {
2530                     el.detachEvent("on" + eventName, fn);
2531                 };
2532             } else {
2533                 return function() {
2534                 };
2535             }
2536         }()
2537     };
2538     
2539 }();
2540 (function() {     
2541    
2542     var E = Roo.lib.Event;
2543     E.on = E.addListener;
2544     E.un = E.removeListener;
2545
2546     if (document && document.body) {
2547         E._load();
2548     } else {
2549         E.doAdd(window, "load", E._load);
2550     }
2551     E.doAdd(window, "unload", E._unload);
2552     E._tryPreloadAttach();
2553 })();
2554
2555 /*
2556  * Portions of this file are based on pieces of Yahoo User Interface Library
2557  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2558  * YUI licensed under the BSD License:
2559  * http://developer.yahoo.net/yui/license.txt
2560  * <script type="text/javascript">
2561  *
2562  */
2563
2564 (function() {
2565     /**
2566      * @class Roo.lib.Ajax
2567      *
2568      */
2569     Roo.lib.Ajax = {
2570         /**
2571          * @static 
2572          */
2573         request : function(method, uri, cb, data, options) {
2574             if(options){
2575                 var hs = options.headers;
2576                 if(hs){
2577                     for(var h in hs){
2578                         if(hs.hasOwnProperty(h)){
2579                             this.initHeader(h, hs[h], false);
2580                         }
2581                     }
2582                 }
2583                 if(options.xmlData){
2584                     this.initHeader('Content-Type', 'text/xml', false);
2585                     method = 'POST';
2586                     data = options.xmlData;
2587                 }
2588             }
2589
2590             return this.asyncRequest(method, uri, cb, data);
2591         },
2592
2593         serializeForm : function(form) {
2594             if(typeof form == 'string') {
2595                 form = (document.getElementById(form) || document.forms[form]);
2596             }
2597
2598             var el, name, val, disabled, data = '', hasSubmit = false;
2599             for (var i = 0; i < form.elements.length; i++) {
2600                 el = form.elements[i];
2601                 disabled = form.elements[i].disabled;
2602                 name = form.elements[i].name;
2603                 val = form.elements[i].value;
2604
2605                 if (!disabled && name){
2606                     switch (el.type)
2607                             {
2608                         case 'select-one':
2609                         case 'select-multiple':
2610                             for (var j = 0; j < el.options.length; j++) {
2611                                 if (el.options[j].selected) {
2612                                     if (Roo.isIE) {
2613                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2614                                     }
2615                                     else {
2616                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2617                                     }
2618                                 }
2619                             }
2620                             break;
2621                         case 'radio':
2622                         case 'checkbox':
2623                             if (el.checked) {
2624                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2625                             }
2626                             break;
2627                         case 'file':
2628
2629                         case undefined:
2630
2631                         case 'reset':
2632
2633                         case 'button':
2634
2635                             break;
2636                         case 'submit':
2637                             if(hasSubmit == false) {
2638                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2639                                 hasSubmit = true;
2640                             }
2641                             break;
2642                         default:
2643                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2644                             break;
2645                     }
2646                 }
2647             }
2648             data = data.substr(0, data.length - 1);
2649             return data;
2650         },
2651
2652         headers:{},
2653
2654         hasHeaders:false,
2655
2656         useDefaultHeader:true,
2657
2658         defaultPostHeader:'application/x-www-form-urlencoded',
2659
2660         useDefaultXhrHeader:true,
2661
2662         defaultXhrHeader:'XMLHttpRequest',
2663
2664         hasDefaultHeaders:true,
2665
2666         defaultHeaders:{},
2667
2668         poll:{},
2669
2670         timeout:{},
2671
2672         pollInterval:50,
2673
2674         transactionId:0,
2675
2676         setProgId:function(id)
2677         {
2678             this.activeX.unshift(id);
2679         },
2680
2681         setDefaultPostHeader:function(b)
2682         {
2683             this.useDefaultHeader = b;
2684         },
2685
2686         setDefaultXhrHeader:function(b)
2687         {
2688             this.useDefaultXhrHeader = b;
2689         },
2690
2691         setPollingInterval:function(i)
2692         {
2693             if (typeof i == 'number' && isFinite(i)) {
2694                 this.pollInterval = i;
2695             }
2696         },
2697
2698         createXhrObject:function(transactionId)
2699         {
2700             var obj,http;
2701             try
2702             {
2703
2704                 http = new XMLHttpRequest();
2705
2706                 obj = { conn:http, tId:transactionId };
2707             }
2708             catch(e)
2709             {
2710                 for (var i = 0; i < this.activeX.length; ++i) {
2711                     try
2712                     {
2713
2714                         http = new ActiveXObject(this.activeX[i]);
2715
2716                         obj = { conn:http, tId:transactionId };
2717                         break;
2718                     }
2719                     catch(e) {
2720                     }
2721                 }
2722             }
2723             finally
2724             {
2725                 return obj;
2726             }
2727         },
2728
2729         getConnectionObject:function()
2730         {
2731             var o;
2732             var tId = this.transactionId;
2733
2734             try
2735             {
2736                 o = this.createXhrObject(tId);
2737                 if (o) {
2738                     this.transactionId++;
2739                 }
2740             }
2741             catch(e) {
2742             }
2743             finally
2744             {
2745                 return o;
2746             }
2747         },
2748
2749         asyncRequest:function(method, uri, callback, postData)
2750         {
2751             var o = this.getConnectionObject();
2752
2753             if (!o) {
2754                 return null;
2755             }
2756             else {
2757                 o.conn.open(method, uri, true);
2758
2759                 if (this.useDefaultXhrHeader) {
2760                     if (!this.defaultHeaders['X-Requested-With']) {
2761                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2762                     }
2763                 }
2764
2765                 if(postData && this.useDefaultHeader){
2766                     this.initHeader('Content-Type', this.defaultPostHeader);
2767                 }
2768
2769                  if (this.hasDefaultHeaders || this.hasHeaders) {
2770                     this.setHeader(o);
2771                 }
2772
2773                 this.handleReadyState(o, callback);
2774                 o.conn.send(postData || null);
2775
2776                 return o;
2777             }
2778         },
2779
2780         handleReadyState:function(o, callback)
2781         {
2782             var oConn = this;
2783
2784             if (callback && callback.timeout) {
2785                 
2786                 this.timeout[o.tId] = window.setTimeout(function() {
2787                     oConn.abort(o, callback, true);
2788                 }, callback.timeout);
2789             }
2790
2791             this.poll[o.tId] = window.setInterval(
2792                     function() {
2793                         if (o.conn && o.conn.readyState == 4) {
2794                             window.clearInterval(oConn.poll[o.tId]);
2795                             delete oConn.poll[o.tId];
2796
2797                             if(callback && callback.timeout) {
2798                                 window.clearTimeout(oConn.timeout[o.tId]);
2799                                 delete oConn.timeout[o.tId];
2800                             }
2801
2802                             oConn.handleTransactionResponse(o, callback);
2803                         }
2804                     }
2805                     , this.pollInterval);
2806         },
2807
2808         handleTransactionResponse:function(o, callback, isAbort)
2809         {
2810
2811             if (!callback) {
2812                 this.releaseObject(o);
2813                 return;
2814             }
2815
2816             var httpStatus, responseObject;
2817
2818             try
2819             {
2820                 if (o.conn.status !== undefined && o.conn.status != 0) {
2821                     httpStatus = o.conn.status;
2822                 }
2823                 else {
2824                     httpStatus = 13030;
2825                 }
2826             }
2827             catch(e) {
2828
2829
2830                 httpStatus = 13030;
2831             }
2832
2833             if (httpStatus >= 200 && httpStatus < 300) {
2834                 responseObject = this.createResponseObject(o, callback.argument);
2835                 if (callback.success) {
2836                     if (!callback.scope) {
2837                         callback.success(responseObject);
2838                     }
2839                     else {
2840
2841
2842                         callback.success.apply(callback.scope, [responseObject]);
2843                     }
2844                 }
2845             }
2846             else {
2847                 switch (httpStatus) {
2848
2849                     case 12002:
2850                     case 12029:
2851                     case 12030:
2852                     case 12031:
2853                     case 12152:
2854                     case 13030:
2855                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2856                         if (callback.failure) {
2857                             if (!callback.scope) {
2858                                 callback.failure(responseObject);
2859                             }
2860                             else {
2861                                 callback.failure.apply(callback.scope, [responseObject]);
2862                             }
2863                         }
2864                         break;
2865                     default:
2866                         responseObject = this.createResponseObject(o, callback.argument);
2867                         if (callback.failure) {
2868                             if (!callback.scope) {
2869                                 callback.failure(responseObject);
2870                             }
2871                             else {
2872                                 callback.failure.apply(callback.scope, [responseObject]);
2873                             }
2874                         }
2875                 }
2876             }
2877
2878             this.releaseObject(o);
2879             responseObject = null;
2880         },
2881
2882         createResponseObject:function(o, callbackArg)
2883         {
2884             var obj = {};
2885             var headerObj = {};
2886
2887             try
2888             {
2889                 var headerStr = o.conn.getAllResponseHeaders();
2890                 var header = headerStr.split('\n');
2891                 for (var i = 0; i < header.length; i++) {
2892                     var delimitPos = header[i].indexOf(':');
2893                     if (delimitPos != -1) {
2894                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2895                     }
2896                 }
2897             }
2898             catch(e) {
2899             }
2900
2901             obj.tId = o.tId;
2902             obj.status = o.conn.status;
2903             obj.statusText = o.conn.statusText;
2904             obj.getResponseHeader = headerObj;
2905             obj.getAllResponseHeaders = headerStr;
2906             obj.responseText = o.conn.responseText;
2907             obj.responseXML = o.conn.responseXML;
2908
2909             if (typeof callbackArg !== undefined) {
2910                 obj.argument = callbackArg;
2911             }
2912
2913             return obj;
2914         },
2915
2916         createExceptionObject:function(tId, callbackArg, isAbort)
2917         {
2918             var COMM_CODE = 0;
2919             var COMM_ERROR = 'communication failure';
2920             var ABORT_CODE = -1;
2921             var ABORT_ERROR = 'transaction aborted';
2922
2923             var obj = {};
2924
2925             obj.tId = tId;
2926             if (isAbort) {
2927                 obj.status = ABORT_CODE;
2928                 obj.statusText = ABORT_ERROR;
2929             }
2930             else {
2931                 obj.status = COMM_CODE;
2932                 obj.statusText = COMM_ERROR;
2933             }
2934
2935             if (callbackArg) {
2936                 obj.argument = callbackArg;
2937             }
2938
2939             return obj;
2940         },
2941
2942         initHeader:function(label, value, isDefault)
2943         {
2944             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2945
2946             if (headerObj[label] === undefined) {
2947                 headerObj[label] = value;
2948             }
2949             else {
2950
2951
2952                 headerObj[label] = value + "," + headerObj[label];
2953             }
2954
2955             if (isDefault) {
2956                 this.hasDefaultHeaders = true;
2957             }
2958             else {
2959                 this.hasHeaders = true;
2960             }
2961         },
2962
2963
2964         setHeader:function(o)
2965         {
2966             if (this.hasDefaultHeaders) {
2967                 for (var prop in this.defaultHeaders) {
2968                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2969                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2970                     }
2971                 }
2972             }
2973
2974             if (this.hasHeaders) {
2975                 for (var prop in this.headers) {
2976                     if (this.headers.hasOwnProperty(prop)) {
2977                         o.conn.setRequestHeader(prop, this.headers[prop]);
2978                     }
2979                 }
2980                 this.headers = {};
2981                 this.hasHeaders = false;
2982             }
2983         },
2984
2985         resetDefaultHeaders:function() {
2986             delete this.defaultHeaders;
2987             this.defaultHeaders = {};
2988             this.hasDefaultHeaders = false;
2989         },
2990
2991         abort:function(o, callback, isTimeout)
2992         {
2993             if(this.isCallInProgress(o)) {
2994                 o.conn.abort();
2995                 window.clearInterval(this.poll[o.tId]);
2996                 delete this.poll[o.tId];
2997                 if (isTimeout) {
2998                     delete this.timeout[o.tId];
2999                 }
3000
3001                 this.handleTransactionResponse(o, callback, true);
3002
3003                 return true;
3004             }
3005             else {
3006                 return false;
3007             }
3008         },
3009
3010
3011         isCallInProgress:function(o)
3012         {
3013             if (o && o.conn) {
3014                 return o.conn.readyState != 4 && o.conn.readyState != 0;
3015             }
3016             else {
3017
3018                 return false;
3019             }
3020         },
3021
3022
3023         releaseObject:function(o)
3024         {
3025
3026             o.conn = null;
3027
3028             o = null;
3029         },
3030
3031         activeX:[
3032         'MSXML2.XMLHTTP.3.0',
3033         'MSXML2.XMLHTTP',
3034         'Microsoft.XMLHTTP'
3035         ]
3036
3037
3038     };
3039 })();/*
3040  * Portions of this file are based on pieces of Yahoo User Interface Library
3041  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3042  * YUI licensed under the BSD License:
3043  * http://developer.yahoo.net/yui/license.txt
3044  * <script type="text/javascript">
3045  *
3046  */
3047
3048 Roo.lib.Region = function(t, r, b, l) {
3049     this.top = t;
3050     this[1] = t;
3051     this.right = r;
3052     this.bottom = b;
3053     this.left = l;
3054     this[0] = l;
3055 };
3056
3057
3058 Roo.lib.Region.prototype = {
3059     contains : function(region) {
3060         return ( region.left >= this.left &&
3061                  region.right <= this.right &&
3062                  region.top >= this.top &&
3063                  region.bottom <= this.bottom    );
3064
3065     },
3066
3067     getArea : function() {
3068         return ( (this.bottom - this.top) * (this.right - this.left) );
3069     },
3070
3071     intersect : function(region) {
3072         var t = Math.max(this.top, region.top);
3073         var r = Math.min(this.right, region.right);
3074         var b = Math.min(this.bottom, region.bottom);
3075         var l = Math.max(this.left, region.left);
3076
3077         if (b >= t && r >= l) {
3078             return new Roo.lib.Region(t, r, b, l);
3079         } else {
3080             return null;
3081         }
3082     },
3083     union : function(region) {
3084         var t = Math.min(this.top, region.top);
3085         var r = Math.max(this.right, region.right);
3086         var b = Math.max(this.bottom, region.bottom);
3087         var l = Math.min(this.left, region.left);
3088
3089         return new Roo.lib.Region(t, r, b, l);
3090     },
3091
3092     adjust : function(t, l, b, r) {
3093         this.top += t;
3094         this.left += l;
3095         this.right += r;
3096         this.bottom += b;
3097         return this;
3098     }
3099 };
3100
3101 Roo.lib.Region.getRegion = function(el) {
3102     var p = Roo.lib.Dom.getXY(el);
3103
3104     var t = p[1];
3105     var r = p[0] + el.offsetWidth;
3106     var b = p[1] + el.offsetHeight;
3107     var l = p[0];
3108
3109     return new Roo.lib.Region(t, r, b, l);
3110 };
3111 /*
3112  * Portions of this file are based on pieces of Yahoo User Interface Library
3113  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3114  * YUI licensed under the BSD License:
3115  * http://developer.yahoo.net/yui/license.txt
3116  * <script type="text/javascript">
3117  *
3118  */
3119 //@@dep Roo.lib.Region
3120
3121
3122 Roo.lib.Point = function(x, y) {
3123     if (x instanceof Array) {
3124         y = x[1];
3125         x = x[0];
3126     }
3127     this.x = this.right = this.left = this[0] = x;
3128     this.y = this.top = this.bottom = this[1] = y;
3129 };
3130
3131 Roo.lib.Point.prototype = new Roo.lib.Region();
3132 /*
3133  * Portions of this file are based on pieces of Yahoo User Interface Library
3134  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3135  * YUI licensed under the BSD License:
3136  * http://developer.yahoo.net/yui/license.txt
3137  * <script type="text/javascript">
3138  *
3139  */
3140  
3141 (function() {   
3142
3143     Roo.lib.Anim = {
3144         scroll : function(el, args, duration, easing, cb, scope) {
3145             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3146         },
3147
3148         motion : function(el, args, duration, easing, cb, scope) {
3149             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3150         },
3151
3152         color : function(el, args, duration, easing, cb, scope) {
3153             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3154         },
3155
3156         run : function(el, args, duration, easing, cb, scope, type) {
3157             type = type || Roo.lib.AnimBase;
3158             if (typeof easing == "string") {
3159                 easing = Roo.lib.Easing[easing];
3160             }
3161             var anim = new type(el, args, duration, easing);
3162             anim.animateX(function() {
3163                 Roo.callback(cb, scope);
3164             });
3165             return anim;
3166         }
3167     };
3168 })();/*
3169  * Portions of this file are based on pieces of Yahoo User Interface Library
3170  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3171  * YUI licensed under the BSD License:
3172  * http://developer.yahoo.net/yui/license.txt
3173  * <script type="text/javascript">
3174  *
3175  */
3176
3177 (function() {    
3178     var libFlyweight;
3179     
3180     function fly(el) {
3181         if (!libFlyweight) {
3182             libFlyweight = new Roo.Element.Flyweight();
3183         }
3184         libFlyweight.dom = el;
3185         return libFlyweight;
3186     }
3187
3188     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3189     
3190    
3191     
3192     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3193         if (el) {
3194             this.init(el, attributes, duration, method);
3195         }
3196     };
3197
3198     Roo.lib.AnimBase.fly = fly;
3199     
3200     
3201     
3202     Roo.lib.AnimBase.prototype = {
3203
3204         toString: function() {
3205             var el = this.getEl();
3206             var id = el.id || el.tagName;
3207             return ("Anim " + id);
3208         },
3209
3210         patterns: {
3211             noNegatives:        /width|height|opacity|padding/i,
3212             offsetAttribute:  /^((width|height)|(top|left))$/,
3213             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3214             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3215         },
3216
3217
3218         doMethod: function(attr, start, end) {
3219             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3220         },
3221
3222
3223         setAttribute: function(attr, val, unit) {
3224             if (this.patterns.noNegatives.test(attr)) {
3225                 val = (val > 0) ? val : 0;
3226             }
3227
3228             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3229         },
3230
3231
3232         getAttribute: function(attr) {
3233             var el = this.getEl();
3234             var val = fly(el).getStyle(attr);
3235
3236             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3237                 return parseFloat(val);
3238             }
3239
3240             var a = this.patterns.offsetAttribute.exec(attr) || [];
3241             var pos = !!( a[3] );
3242             var box = !!( a[2] );
3243
3244
3245             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3246                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3247             } else {
3248                 val = 0;
3249             }
3250
3251             return val;
3252         },
3253
3254
3255         getDefaultUnit: function(attr) {
3256             if (this.patterns.defaultUnit.test(attr)) {
3257                 return 'px';
3258             }
3259
3260             return '';
3261         },
3262
3263         animateX : function(callback, scope) {
3264             var f = function() {
3265                 this.onComplete.removeListener(f);
3266                 if (typeof callback == "function") {
3267                     callback.call(scope || this, this);
3268                 }
3269             };
3270             this.onComplete.addListener(f, this);
3271             this.animate();
3272         },
3273
3274
3275         setRuntimeAttribute: function(attr) {
3276             var start;
3277             var end;
3278             var attributes = this.attributes;
3279
3280             this.runtimeAttributes[attr] = {};
3281
3282             var isset = function(prop) {
3283                 return (typeof prop !== 'undefined');
3284             };
3285
3286             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3287                 return false;
3288             }
3289
3290             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3291
3292
3293             if (isset(attributes[attr]['to'])) {
3294                 end = attributes[attr]['to'];
3295             } else if (isset(attributes[attr]['by'])) {
3296                 if (start.constructor == Array) {
3297                     end = [];
3298                     for (var i = 0, len = start.length; i < len; ++i) {
3299                         end[i] = start[i] + attributes[attr]['by'][i];
3300                     }
3301                 } else {
3302                     end = start + attributes[attr]['by'];
3303                 }
3304             }
3305
3306             this.runtimeAttributes[attr].start = start;
3307             this.runtimeAttributes[attr].end = end;
3308
3309
3310             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3311         },
3312
3313
3314         init: function(el, attributes, duration, method) {
3315
3316             var isAnimated = false;
3317
3318
3319             var startTime = null;
3320
3321
3322             var actualFrames = 0;
3323
3324
3325             el = Roo.getDom(el);
3326
3327
3328             this.attributes = attributes || {};
3329
3330
3331             this.duration = duration || 1;
3332
3333
3334             this.method = method || Roo.lib.Easing.easeNone;
3335
3336
3337             this.useSeconds = true;
3338
3339
3340             this.currentFrame = 0;
3341
3342
3343             this.totalFrames = Roo.lib.AnimMgr.fps;
3344
3345
3346             this.getEl = function() {
3347                 return el;
3348             };
3349
3350
3351             this.isAnimated = function() {
3352                 return isAnimated;
3353             };
3354
3355
3356             this.getStartTime = function() {
3357                 return startTime;
3358             };
3359
3360             this.runtimeAttributes = {};
3361
3362
3363             this.animate = function() {
3364                 if (this.isAnimated()) {
3365                     return false;
3366                 }
3367
3368                 this.currentFrame = 0;
3369
3370                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3371
3372                 Roo.lib.AnimMgr.registerElement(this);
3373             };
3374
3375
3376             this.stop = function(finish) {
3377                 if (finish) {
3378                     this.currentFrame = this.totalFrames;
3379                     this._onTween.fire();
3380                 }
3381                 Roo.lib.AnimMgr.stop(this);
3382             };
3383
3384             var onStart = function() {
3385                 this.onStart.fire();
3386
3387                 this.runtimeAttributes = {};
3388                 for (var attr in this.attributes) {
3389                     this.setRuntimeAttribute(attr);
3390                 }
3391
3392                 isAnimated = true;
3393                 actualFrames = 0;
3394                 startTime = new Date();
3395             };
3396
3397
3398             var onTween = function() {
3399                 var data = {
3400                     duration: new Date() - this.getStartTime(),
3401                     currentFrame: this.currentFrame
3402                 };
3403
3404                 data.toString = function() {
3405                     return (
3406                             'duration: ' + data.duration +
3407                             ', currentFrame: ' + data.currentFrame
3408                             );
3409                 };
3410
3411                 this.onTween.fire(data);
3412
3413                 var runtimeAttributes = this.runtimeAttributes;
3414
3415                 for (var attr in runtimeAttributes) {
3416                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3417                 }
3418
3419                 actualFrames += 1;
3420             };
3421
3422             var onComplete = function() {
3423                 var actual_duration = (new Date() - startTime) / 1000 ;
3424
3425                 var data = {
3426                     duration: actual_duration,
3427                     frames: actualFrames,
3428                     fps: actualFrames / actual_duration
3429                 };
3430
3431                 data.toString = function() {
3432                     return (
3433                             'duration: ' + data.duration +
3434                             ', frames: ' + data.frames +
3435                             ', fps: ' + data.fps
3436                             );
3437                 };
3438
3439                 isAnimated = false;
3440                 actualFrames = 0;
3441                 this.onComplete.fire(data);
3442             };
3443
3444
3445             this._onStart = new Roo.util.Event(this);
3446             this.onStart = new Roo.util.Event(this);
3447             this.onTween = new Roo.util.Event(this);
3448             this._onTween = new Roo.util.Event(this);
3449             this.onComplete = new Roo.util.Event(this);
3450             this._onComplete = new Roo.util.Event(this);
3451             this._onStart.addListener(onStart);
3452             this._onTween.addListener(onTween);
3453             this._onComplete.addListener(onComplete);
3454         }
3455     };
3456 })();
3457 /*
3458  * Portions of this file are based on pieces of Yahoo User Interface Library
3459  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3460  * YUI licensed under the BSD License:
3461  * http://developer.yahoo.net/yui/license.txt
3462  * <script type="text/javascript">
3463  *
3464  */
3465
3466 Roo.lib.AnimMgr = new function() {
3467
3468     var thread = null;
3469
3470
3471     var queue = [];
3472
3473
3474     var tweenCount = 0;
3475
3476
3477     this.fps = 1000;
3478
3479
3480     this.delay = 1;
3481
3482
3483     this.registerElement = function(tween) {
3484         queue[queue.length] = tween;
3485         tweenCount += 1;
3486         tween._onStart.fire();
3487         this.start();
3488     };
3489
3490
3491     this.unRegister = function(tween, index) {
3492         tween._onComplete.fire();
3493         index = index || getIndex(tween);
3494         if (index != -1) {
3495             queue.splice(index, 1);
3496         }
3497
3498         tweenCount -= 1;
3499         if (tweenCount <= 0) {
3500             this.stop();
3501         }
3502     };
3503
3504
3505     this.start = function() {
3506         if (thread === null) {
3507             thread = setInterval(this.run, this.delay);
3508         }
3509     };
3510
3511
3512     this.stop = function(tween) {
3513         if (!tween) {
3514             clearInterval(thread);
3515
3516             for (var i = 0, len = queue.length; i < len; ++i) {
3517                 if (queue[0].isAnimated()) {
3518                     this.unRegister(queue[0], 0);
3519                 }
3520             }
3521
3522             queue = [];
3523             thread = null;
3524             tweenCount = 0;
3525         }
3526         else {
3527             this.unRegister(tween);
3528         }
3529     };
3530
3531
3532     this.run = function() {
3533         for (var i = 0, len = queue.length; i < len; ++i) {
3534             var tween = queue[i];
3535             if (!tween || !tween.isAnimated()) {
3536                 continue;
3537             }
3538
3539             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3540             {
3541                 tween.currentFrame += 1;
3542
3543                 if (tween.useSeconds) {
3544                     correctFrame(tween);
3545                 }
3546                 tween._onTween.fire();
3547             }
3548             else {
3549                 Roo.lib.AnimMgr.stop(tween, i);
3550             }
3551         }
3552     };
3553
3554     var getIndex = function(anim) {
3555         for (var i = 0, len = queue.length; i < len; ++i) {
3556             if (queue[i] == anim) {
3557                 return i;
3558             }
3559         }
3560         return -1;
3561     };
3562
3563
3564     var correctFrame = function(tween) {
3565         var frames = tween.totalFrames;
3566         var frame = tween.currentFrame;
3567         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3568         var elapsed = (new Date() - tween.getStartTime());
3569         var tweak = 0;
3570
3571         if (elapsed < tween.duration * 1000) {
3572             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3573         } else {
3574             tweak = frames - (frame + 1);
3575         }
3576         if (tweak > 0 && isFinite(tweak)) {
3577             if (tween.currentFrame + tweak >= frames) {
3578                 tweak = frames - (frame + 1);
3579             }
3580
3581             tween.currentFrame += tweak;
3582         }
3583     };
3584 };
3585
3586     /*
3587  * Portions of this file are based on pieces of Yahoo User Interface Library
3588  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3589  * YUI licensed under the BSD License:
3590  * http://developer.yahoo.net/yui/license.txt
3591  * <script type="text/javascript">
3592  *
3593  */
3594 Roo.lib.Bezier = new function() {
3595
3596         this.getPosition = function(points, t) {
3597             var n = points.length;
3598             var tmp = [];
3599
3600             for (var i = 0; i < n; ++i) {
3601                 tmp[i] = [points[i][0], points[i][1]];
3602             }
3603
3604             for (var j = 1; j < n; ++j) {
3605                 for (i = 0; i < n - j; ++i) {
3606                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3607                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3608                 }
3609             }
3610
3611             return [ tmp[0][0], tmp[0][1] ];
3612
3613         };
3614     };/*
3615  * Portions of this file are based on pieces of Yahoo User Interface Library
3616  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3617  * YUI licensed under the BSD License:
3618  * http://developer.yahoo.net/yui/license.txt
3619  * <script type="text/javascript">
3620  *
3621  */
3622 (function() {
3623
3624     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3625         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3626     };
3627
3628     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3629
3630     var fly = Roo.lib.AnimBase.fly;
3631     var Y = Roo.lib;
3632     var superclass = Y.ColorAnim.superclass;
3633     var proto = Y.ColorAnim.prototype;
3634
3635     proto.toString = function() {
3636         var el = this.getEl();
3637         var id = el.id || el.tagName;
3638         return ("ColorAnim " + id);
3639     };
3640
3641     proto.patterns.color = /color$/i;
3642     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3643     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3644     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3645     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3646
3647
3648     proto.parseColor = function(s) {
3649         if (s.length == 3) {
3650             return s;
3651         }
3652
3653         var c = this.patterns.hex.exec(s);
3654         if (c && c.length == 4) {
3655             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3656         }
3657
3658         c = this.patterns.rgb.exec(s);
3659         if (c && c.length == 4) {
3660             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3661         }
3662
3663         c = this.patterns.hex3.exec(s);
3664         if (c && c.length == 4) {
3665             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3666         }
3667
3668         return null;
3669     };
3670     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3671     proto.getAttribute = function(attr) {
3672         var el = this.getEl();
3673         if (this.patterns.color.test(attr)) {
3674             var val = fly(el).getStyle(attr);
3675
3676             if (this.patterns.transparent.test(val)) {
3677                 var parent = el.parentNode;
3678                 val = fly(parent).getStyle(attr);
3679
3680                 while (parent && this.patterns.transparent.test(val)) {
3681                     parent = parent.parentNode;
3682                     val = fly(parent).getStyle(attr);
3683                     if (parent.tagName.toUpperCase() == 'HTML') {
3684                         val = '#fff';
3685                     }
3686                 }
3687             }
3688         } else {
3689             val = superclass.getAttribute.call(this, attr);
3690         }
3691
3692         return val;
3693     };
3694     proto.getAttribute = function(attr) {
3695         var el = this.getEl();
3696         if (this.patterns.color.test(attr)) {
3697             var val = fly(el).getStyle(attr);
3698
3699             if (this.patterns.transparent.test(val)) {
3700                 var parent = el.parentNode;
3701                 val = fly(parent).getStyle(attr);
3702
3703                 while (parent && this.patterns.transparent.test(val)) {
3704                     parent = parent.parentNode;
3705                     val = fly(parent).getStyle(attr);
3706                     if (parent.tagName.toUpperCase() == 'HTML') {
3707                         val = '#fff';
3708                     }
3709                 }
3710             }
3711         } else {
3712             val = superclass.getAttribute.call(this, attr);
3713         }
3714
3715         return val;
3716     };
3717
3718     proto.doMethod = function(attr, start, end) {
3719         var val;
3720
3721         if (this.patterns.color.test(attr)) {
3722             val = [];
3723             for (var i = 0, len = start.length; i < len; ++i) {
3724                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3725             }
3726
3727             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3728         }
3729         else {
3730             val = superclass.doMethod.call(this, attr, start, end);
3731         }
3732
3733         return val;
3734     };
3735
3736     proto.setRuntimeAttribute = function(attr) {
3737         superclass.setRuntimeAttribute.call(this, attr);
3738
3739         if (this.patterns.color.test(attr)) {
3740             var attributes = this.attributes;
3741             var start = this.parseColor(this.runtimeAttributes[attr].start);
3742             var end = this.parseColor(this.runtimeAttributes[attr].end);
3743
3744             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3745                 end = this.parseColor(attributes[attr].by);
3746
3747                 for (var i = 0, len = start.length; i < len; ++i) {
3748                     end[i] = start[i] + end[i];
3749                 }
3750             }
3751
3752             this.runtimeAttributes[attr].start = start;
3753             this.runtimeAttributes[attr].end = end;
3754         }
3755     };
3756 })();
3757
3758 /*
3759  * Portions of this file are based on pieces of Yahoo User Interface Library
3760  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3761  * YUI licensed under the BSD License:
3762  * http://developer.yahoo.net/yui/license.txt
3763  * <script type="text/javascript">
3764  *
3765  */
3766 Roo.lib.Easing = {
3767
3768
3769     easeNone: function (t, b, c, d) {
3770         return c * t / d + b;
3771     },
3772
3773
3774     easeIn: function (t, b, c, d) {
3775         return c * (t /= d) * t + b;
3776     },
3777
3778
3779     easeOut: function (t, b, c, d) {
3780         return -c * (t /= d) * (t - 2) + b;
3781     },
3782
3783
3784     easeBoth: function (t, b, c, d) {
3785         if ((t /= d / 2) < 1) {
3786             return c / 2 * t * t + b;
3787         }
3788
3789         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3790     },
3791
3792
3793     easeInStrong: function (t, b, c, d) {
3794         return c * (t /= d) * t * t * t + b;
3795     },
3796
3797
3798     easeOutStrong: function (t, b, c, d) {
3799         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3800     },
3801
3802
3803     easeBothStrong: function (t, b, c, d) {
3804         if ((t /= d / 2) < 1) {
3805             return c / 2 * t * t * t * t + b;
3806         }
3807
3808         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3809     },
3810
3811
3812
3813     elasticIn: function (t, b, c, d, a, p) {
3814         if (t == 0) {
3815             return b;
3816         }
3817         if ((t /= d) == 1) {
3818             return b + c;
3819         }
3820         if (!p) {
3821             p = d * .3;
3822         }
3823
3824         if (!a || a < Math.abs(c)) {
3825             a = c;
3826             var s = p / 4;
3827         }
3828         else {
3829             var s = p / (2 * Math.PI) * Math.asin(c / a);
3830         }
3831
3832         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3833     },
3834
3835
3836     elasticOut: function (t, b, c, d, a, p) {
3837         if (t == 0) {
3838             return b;
3839         }
3840         if ((t /= d) == 1) {
3841             return b + c;
3842         }
3843         if (!p) {
3844             p = d * .3;
3845         }
3846
3847         if (!a || a < Math.abs(c)) {
3848             a = c;
3849             var s = p / 4;
3850         }
3851         else {
3852             var s = p / (2 * Math.PI) * Math.asin(c / a);
3853         }
3854
3855         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3856     },
3857
3858
3859     elasticBoth: function (t, b, c, d, a, p) {
3860         if (t == 0) {
3861             return b;
3862         }
3863
3864         if ((t /= d / 2) == 2) {
3865             return b + c;
3866         }
3867
3868         if (!p) {
3869             p = d * (.3 * 1.5);
3870         }
3871
3872         if (!a || a < Math.abs(c)) {
3873             a = c;
3874             var s = p / 4;
3875         }
3876         else {
3877             var s = p / (2 * Math.PI) * Math.asin(c / a);
3878         }
3879
3880         if (t < 1) {
3881             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3882                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3883         }
3884         return a * Math.pow(2, -10 * (t -= 1)) *
3885                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3886     },
3887
3888
3889
3890     backIn: function (t, b, c, d, s) {
3891         if (typeof s == 'undefined') {
3892             s = 1.70158;
3893         }
3894         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3895     },
3896
3897
3898     backOut: function (t, b, c, d, s) {
3899         if (typeof s == 'undefined') {
3900             s = 1.70158;
3901         }
3902         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3903     },
3904
3905
3906     backBoth: function (t, b, c, d, s) {
3907         if (typeof s == 'undefined') {
3908             s = 1.70158;
3909         }
3910
3911         if ((t /= d / 2 ) < 1) {
3912             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3913         }
3914         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3915     },
3916
3917
3918     bounceIn: function (t, b, c, d) {
3919         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3920     },
3921
3922
3923     bounceOut: function (t, b, c, d) {
3924         if ((t /= d) < (1 / 2.75)) {
3925             return c * (7.5625 * t * t) + b;
3926         } else if (t < (2 / 2.75)) {
3927             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3928         } else if (t < (2.5 / 2.75)) {
3929             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3930         }
3931         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3932     },
3933
3934
3935     bounceBoth: function (t, b, c, d) {
3936         if (t < d / 2) {
3937             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3938         }
3939         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3940     }
3941 };/*
3942  * Portions of this file are based on pieces of Yahoo User Interface Library
3943  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3944  * YUI licensed under the BSD License:
3945  * http://developer.yahoo.net/yui/license.txt
3946  * <script type="text/javascript">
3947  *
3948  */
3949     (function() {
3950         Roo.lib.Motion = function(el, attributes, duration, method) {
3951             if (el) {
3952                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3953             }
3954         };
3955
3956         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3957
3958
3959         var Y = Roo.lib;
3960         var superclass = Y.Motion.superclass;
3961         var proto = Y.Motion.prototype;
3962
3963         proto.toString = function() {
3964             var el = this.getEl();
3965             var id = el.id || el.tagName;
3966             return ("Motion " + id);
3967         };
3968
3969         proto.patterns.points = /^points$/i;
3970
3971         proto.setAttribute = function(attr, val, unit) {
3972             if (this.patterns.points.test(attr)) {
3973                 unit = unit || 'px';
3974                 superclass.setAttribute.call(this, 'left', val[0], unit);
3975                 superclass.setAttribute.call(this, 'top', val[1], unit);
3976             } else {
3977                 superclass.setAttribute.call(this, attr, val, unit);
3978             }
3979         };
3980
3981         proto.getAttribute = function(attr) {
3982             if (this.patterns.points.test(attr)) {
3983                 var val = [
3984                         superclass.getAttribute.call(this, 'left'),
3985                         superclass.getAttribute.call(this, 'top')
3986                         ];
3987             } else {
3988                 val = superclass.getAttribute.call(this, attr);
3989             }
3990
3991             return val;
3992         };
3993
3994         proto.doMethod = function(attr, start, end) {
3995             var val = null;
3996
3997             if (this.patterns.points.test(attr)) {
3998                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3999                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4000             } else {
4001                 val = superclass.doMethod.call(this, attr, start, end);
4002             }
4003             return val;
4004         };
4005
4006         proto.setRuntimeAttribute = function(attr) {
4007             if (this.patterns.points.test(attr)) {
4008                 var el = this.getEl();
4009                 var attributes = this.attributes;
4010                 var start;
4011                 var control = attributes['points']['control'] || [];
4012                 var end;
4013                 var i, len;
4014
4015                 if (control.length > 0 && !(control[0] instanceof Array)) {
4016                     control = [control];
4017                 } else {
4018                     var tmp = [];
4019                     for (i = 0,len = control.length; i < len; ++i) {
4020                         tmp[i] = control[i];
4021                     }
4022                     control = tmp;
4023                 }
4024
4025                 Roo.fly(el).position();
4026
4027                 if (isset(attributes['points']['from'])) {
4028                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4029                 }
4030                 else {
4031                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4032                 }
4033
4034                 start = this.getAttribute('points');
4035
4036
4037                 if (isset(attributes['points']['to'])) {
4038                     end = translateValues.call(this, attributes['points']['to'], start);
4039
4040                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4041                     for (i = 0,len = control.length; i < len; ++i) {
4042                         control[i] = translateValues.call(this, control[i], start);
4043                     }
4044
4045
4046                 } else if (isset(attributes['points']['by'])) {
4047                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4048
4049                     for (i = 0,len = control.length; i < len; ++i) {
4050                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4051                     }
4052                 }
4053
4054                 this.runtimeAttributes[attr] = [start];
4055
4056                 if (control.length > 0) {
4057                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4058                 }
4059
4060                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4061             }
4062             else {
4063                 superclass.setRuntimeAttribute.call(this, attr);
4064             }
4065         };
4066
4067         var translateValues = function(val, start) {
4068             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4069             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4070
4071             return val;
4072         };
4073
4074         var isset = function(prop) {
4075             return (typeof prop !== 'undefined');
4076         };
4077     })();
4078 /*
4079  * Portions of this file are based on pieces of Yahoo User Interface Library
4080  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4081  * YUI licensed under the BSD License:
4082  * http://developer.yahoo.net/yui/license.txt
4083  * <script type="text/javascript">
4084  *
4085  */
4086     (function() {
4087         Roo.lib.Scroll = function(el, attributes, duration, method) {
4088             if (el) {
4089                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4090             }
4091         };
4092
4093         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4094
4095
4096         var Y = Roo.lib;
4097         var superclass = Y.Scroll.superclass;
4098         var proto = Y.Scroll.prototype;
4099
4100         proto.toString = function() {
4101             var el = this.getEl();
4102             var id = el.id || el.tagName;
4103             return ("Scroll " + id);
4104         };
4105
4106         proto.doMethod = function(attr, start, end) {
4107             var val = null;
4108
4109             if (attr == 'scroll') {
4110                 val = [
4111                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4112                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4113                         ];
4114
4115             } else {
4116                 val = superclass.doMethod.call(this, attr, start, end);
4117             }
4118             return val;
4119         };
4120
4121         proto.getAttribute = function(attr) {
4122             var val = null;
4123             var el = this.getEl();
4124
4125             if (attr == 'scroll') {
4126                 val = [ el.scrollLeft, el.scrollTop ];
4127             } else {
4128                 val = superclass.getAttribute.call(this, attr);
4129             }
4130
4131             return val;
4132         };
4133
4134         proto.setAttribute = function(attr, val, unit) {
4135             var el = this.getEl();
4136
4137             if (attr == 'scroll') {
4138                 el.scrollLeft = val[0];
4139                 el.scrollTop = val[1];
4140             } else {
4141                 superclass.setAttribute.call(this, attr, val, unit);
4142             }
4143         };
4144     })();
4145 /*
4146  * Based on:
4147  * Ext JS Library 1.1.1
4148  * Copyright(c) 2006-2007, Ext JS, LLC.
4149  *
4150  * Originally Released Under LGPL - original licence link has changed is not relivant.
4151  *
4152  * Fork - LGPL
4153  * <script type="text/javascript">
4154  */
4155
4156
4157 // nasty IE9 hack - what a pile of crap that is..
4158
4159  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4160     Range.prototype.createContextualFragment = function (html) {
4161         var doc = window.document;
4162         var container = doc.createElement("div");
4163         container.innerHTML = html;
4164         var frag = doc.createDocumentFragment(), n;
4165         while ((n = container.firstChild)) {
4166             frag.appendChild(n);
4167         }
4168         return frag;
4169     };
4170 }
4171
4172 /**
4173  * @class Roo.DomHelper
4174  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4175  * 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>.
4176  * @singleton
4177  */
4178 Roo.DomHelper = function(){
4179     var tempTableEl = null;
4180     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4181     var tableRe = /^table|tbody|tr|td$/i;
4182     var xmlns = {};
4183     // build as innerHTML where available
4184     /** @ignore */
4185     var createHtml = function(o){
4186         if(typeof o == 'string'){
4187             return o;
4188         }
4189         var b = "";
4190         if(!o.tag){
4191             o.tag = "div";
4192         }
4193         b += "<" + o.tag;
4194         for(var attr in o){
4195             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4196             if(attr == "style"){
4197                 var s = o["style"];
4198                 if(typeof s == "function"){
4199                     s = s.call();
4200                 }
4201                 if(typeof s == "string"){
4202                     b += ' style="' + s + '"';
4203                 }else if(typeof s == "object"){
4204                     b += ' style="';
4205                     for(var key in s){
4206                         if(typeof s[key] != "function"){
4207                             b += key + ":" + s[key] + ";";
4208                         }
4209                     }
4210                     b += '"';
4211                 }
4212             }else{
4213                 if(attr == "cls"){
4214                     b += ' class="' + o["cls"] + '"';
4215                 }else if(attr == "htmlFor"){
4216                     b += ' for="' + o["htmlFor"] + '"';
4217                 }else{
4218                     b += " " + attr + '="' + o[attr] + '"';
4219                 }
4220             }
4221         }
4222         if(emptyTags.test(o.tag)){
4223             b += "/>";
4224         }else{
4225             b += ">";
4226             var cn = o.children || o.cn;
4227             if(cn){
4228                 //http://bugs.kde.org/show_bug.cgi?id=71506
4229                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4230                     for(var i = 0, len = cn.length; i < len; i++) {
4231                         b += createHtml(cn[i], b);
4232                     }
4233                 }else{
4234                     b += createHtml(cn, b);
4235                 }
4236             }
4237             if(o.html){
4238                 b += o.html;
4239             }
4240             b += "</" + o.tag + ">";
4241         }
4242         return b;
4243     };
4244
4245     // build as dom
4246     /** @ignore */
4247     var createDom = function(o, parentNode){
4248          
4249         // defininition craeted..
4250         var ns = false;
4251         if (o.ns && o.ns != 'html') {
4252                
4253             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4254                 xmlns[o.ns] = o.xmlns;
4255                 ns = o.xmlns;
4256             }
4257             if (typeof(xmlns[o.ns]) == 'undefined') {
4258                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4259             }
4260             ns = xmlns[o.ns];
4261         }
4262         
4263         
4264         if (typeof(o) == 'string') {
4265             return parentNode.appendChild(document.createTextNode(o));
4266         }
4267         o.tag = o.tag || div;
4268         if (o.ns && Roo.isIE) {
4269             ns = false;
4270             o.tag = o.ns + ':' + o.tag;
4271             
4272         }
4273         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4274         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4275         for(var attr in o){
4276             
4277             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4278                     attr == "style" || typeof o[attr] == "function") { continue; }
4279                     
4280             if(attr=="cls" && Roo.isIE){
4281                 el.className = o["cls"];
4282             }else{
4283                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4284                 else { 
4285                     el[attr] = o[attr];
4286                 }
4287             }
4288         }
4289         Roo.DomHelper.applyStyles(el, o.style);
4290         var cn = o.children || o.cn;
4291         if(cn){
4292             //http://bugs.kde.org/show_bug.cgi?id=71506
4293              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4294                 for(var i = 0, len = cn.length; i < len; i++) {
4295                     createDom(cn[i], el);
4296                 }
4297             }else{
4298                 createDom(cn, el);
4299             }
4300         }
4301         if(o.html){
4302             el.innerHTML = o.html;
4303         }
4304         if(parentNode){
4305            parentNode.appendChild(el);
4306         }
4307         return el;
4308     };
4309
4310     var ieTable = function(depth, s, h, e){
4311         tempTableEl.innerHTML = [s, h, e].join('');
4312         var i = -1, el = tempTableEl;
4313         while(++i < depth){
4314             el = el.firstChild;
4315         }
4316         return el;
4317     };
4318
4319     // kill repeat to save bytes
4320     var ts = '<table>',
4321         te = '</table>',
4322         tbs = ts+'<tbody>',
4323         tbe = '</tbody>'+te,
4324         trs = tbs + '<tr>',
4325         tre = '</tr>'+tbe;
4326
4327     /**
4328      * @ignore
4329      * Nasty code for IE's broken table implementation
4330      */
4331     var insertIntoTable = function(tag, where, el, html){
4332         if(!tempTableEl){
4333             tempTableEl = document.createElement('div');
4334         }
4335         var node;
4336         var before = null;
4337         if(tag == 'td'){
4338             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4339                 return;
4340             }
4341             if(where == 'beforebegin'){
4342                 before = el;
4343                 el = el.parentNode;
4344             } else{
4345                 before = el.nextSibling;
4346                 el = el.parentNode;
4347             }
4348             node = ieTable(4, trs, html, tre);
4349         }
4350         else if(tag == 'tr'){
4351             if(where == 'beforebegin'){
4352                 before = el;
4353                 el = el.parentNode;
4354                 node = ieTable(3, tbs, html, tbe);
4355             } else if(where == 'afterend'){
4356                 before = el.nextSibling;
4357                 el = el.parentNode;
4358                 node = ieTable(3, tbs, html, tbe);
4359             } else{ // INTO a TR
4360                 if(where == 'afterbegin'){
4361                     before = el.firstChild;
4362                 }
4363                 node = ieTable(4, trs, html, tre);
4364             }
4365         } else if(tag == 'tbody'){
4366             if(where == 'beforebegin'){
4367                 before = el;
4368                 el = el.parentNode;
4369                 node = ieTable(2, ts, html, te);
4370             } else if(where == 'afterend'){
4371                 before = el.nextSibling;
4372                 el = el.parentNode;
4373                 node = ieTable(2, ts, html, te);
4374             } else{
4375                 if(where == 'afterbegin'){
4376                     before = el.firstChild;
4377                 }
4378                 node = ieTable(3, tbs, html, tbe);
4379             }
4380         } else{ // TABLE
4381             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4382                 return;
4383             }
4384             if(where == 'afterbegin'){
4385                 before = el.firstChild;
4386             }
4387             node = ieTable(2, ts, html, te);
4388         }
4389         el.insertBefore(node, before);
4390         return node;
4391     };
4392
4393     return {
4394     /** True to force the use of DOM instead of html fragments @type Boolean */
4395     useDom : false,
4396
4397     /**
4398      * Returns the markup for the passed Element(s) config
4399      * @param {Object} o The Dom object spec (and children)
4400      * @return {String}
4401      */
4402     markup : function(o){
4403         return createHtml(o);
4404     },
4405
4406     /**
4407      * Applies a style specification to an element
4408      * @param {String/HTMLElement} el The element to apply styles to
4409      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4410      * a function which returns such a specification.
4411      */
4412     applyStyles : function(el, styles){
4413         if(styles){
4414            el = Roo.fly(el);
4415            if(typeof styles == "string"){
4416                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4417                var matches;
4418                while ((matches = re.exec(styles)) != null){
4419                    el.setStyle(matches[1], matches[2]);
4420                }
4421            }else if (typeof styles == "object"){
4422                for (var style in styles){
4423                   el.setStyle(style, styles[style]);
4424                }
4425            }else if (typeof styles == "function"){
4426                 Roo.DomHelper.applyStyles(el, styles.call());
4427            }
4428         }
4429     },
4430
4431     /**
4432      * Inserts an HTML fragment into the Dom
4433      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4434      * @param {HTMLElement} el The context element
4435      * @param {String} html The HTML fragmenet
4436      * @return {HTMLElement} The new node
4437      */
4438     insertHtml : function(where, el, html){
4439         where = where.toLowerCase();
4440         if(el.insertAdjacentHTML){
4441             if(tableRe.test(el.tagName)){
4442                 var rs;
4443                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4444                     return rs;
4445                 }
4446             }
4447             switch(where){
4448                 case "beforebegin":
4449                     el.insertAdjacentHTML('BeforeBegin', html);
4450                     return el.previousSibling;
4451                 case "afterbegin":
4452                     el.insertAdjacentHTML('AfterBegin', html);
4453                     return el.firstChild;
4454                 case "beforeend":
4455                     el.insertAdjacentHTML('BeforeEnd', html);
4456                     return el.lastChild;
4457                 case "afterend":
4458                     el.insertAdjacentHTML('AfterEnd', html);
4459                     return el.nextSibling;
4460             }
4461             throw 'Illegal insertion point -> "' + where + '"';
4462         }
4463         var range = el.ownerDocument.createRange();
4464         var frag;
4465         switch(where){
4466              case "beforebegin":
4467                 range.setStartBefore(el);
4468                 frag = range.createContextualFragment(html);
4469                 el.parentNode.insertBefore(frag, el);
4470                 return el.previousSibling;
4471              case "afterbegin":
4472                 if(el.firstChild){
4473                     range.setStartBefore(el.firstChild);
4474                     frag = range.createContextualFragment(html);
4475                     el.insertBefore(frag, el.firstChild);
4476                     return el.firstChild;
4477                 }else{
4478                     el.innerHTML = html;
4479                     return el.firstChild;
4480                 }
4481             case "beforeend":
4482                 if(el.lastChild){
4483                     range.setStartAfter(el.lastChild);
4484                     frag = range.createContextualFragment(html);
4485                     el.appendChild(frag);
4486                     return el.lastChild;
4487                 }else{
4488                     el.innerHTML = html;
4489                     return el.lastChild;
4490                 }
4491             case "afterend":
4492                 range.setStartAfter(el);
4493                 frag = range.createContextualFragment(html);
4494                 el.parentNode.insertBefore(frag, el.nextSibling);
4495                 return el.nextSibling;
4496             }
4497             throw 'Illegal insertion point -> "' + where + '"';
4498     },
4499
4500     /**
4501      * Creates new Dom element(s) and inserts them before el
4502      * @param {String/HTMLElement/Element} el The context element
4503      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4504      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4505      * @return {HTMLElement/Roo.Element} The new node
4506      */
4507     insertBefore : function(el, o, returnElement){
4508         return this.doInsert(el, o, returnElement, "beforeBegin");
4509     },
4510
4511     /**
4512      * Creates new Dom element(s) and inserts them after el
4513      * @param {String/HTMLElement/Element} el The context element
4514      * @param {Object} o The Dom object spec (and children)
4515      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4516      * @return {HTMLElement/Roo.Element} The new node
4517      */
4518     insertAfter : function(el, o, returnElement){
4519         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4520     },
4521
4522     /**
4523      * Creates new Dom element(s) and inserts them as the first child of el
4524      * @param {String/HTMLElement/Element} el The context element
4525      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4526      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4527      * @return {HTMLElement/Roo.Element} The new node
4528      */
4529     insertFirst : function(el, o, returnElement){
4530         return this.doInsert(el, o, returnElement, "afterBegin");
4531     },
4532
4533     // private
4534     doInsert : function(el, o, returnElement, pos, sibling){
4535         el = Roo.getDom(el);
4536         var newNode;
4537         if(this.useDom || o.ns){
4538             newNode = createDom(o, null);
4539             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4540         }else{
4541             var html = createHtml(o);
4542             newNode = this.insertHtml(pos, el, html);
4543         }
4544         return returnElement ? Roo.get(newNode, true) : newNode;
4545     },
4546
4547     /**
4548      * Creates new Dom element(s) and appends them to el
4549      * @param {String/HTMLElement/Element} el The context element
4550      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4551      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4552      * @return {HTMLElement/Roo.Element} The new node
4553      */
4554     append : function(el, o, returnElement){
4555         el = Roo.getDom(el);
4556         var newNode;
4557         if(this.useDom || o.ns){
4558             newNode = createDom(o, null);
4559             el.appendChild(newNode);
4560         }else{
4561             var html = createHtml(o);
4562             newNode = this.insertHtml("beforeEnd", el, html);
4563         }
4564         return returnElement ? Roo.get(newNode, true) : newNode;
4565     },
4566
4567     /**
4568      * Creates new Dom element(s) and overwrites the contents of el with them
4569      * @param {String/HTMLElement/Element} el The context element
4570      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4571      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4572      * @return {HTMLElement/Roo.Element} The new node
4573      */
4574     overwrite : function(el, o, returnElement){
4575         el = Roo.getDom(el);
4576         if (o.ns) {
4577           
4578             while (el.childNodes.length) {
4579                 el.removeChild(el.firstChild);
4580             }
4581             createDom(o, el);
4582         } else {
4583             el.innerHTML = createHtml(o);   
4584         }
4585         
4586         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4587     },
4588
4589     /**
4590      * Creates a new Roo.DomHelper.Template from the Dom object spec
4591      * @param {Object} o The Dom object spec (and children)
4592      * @return {Roo.DomHelper.Template} The new template
4593      */
4594     createTemplate : function(o){
4595         var html = createHtml(o);
4596         return new Roo.Template(html);
4597     }
4598     };
4599 }();
4600 /*
4601  * Based on:
4602  * Ext JS Library 1.1.1
4603  * Copyright(c) 2006-2007, Ext JS, LLC.
4604  *
4605  * Originally Released Under LGPL - original licence link has changed is not relivant.
4606  *
4607  * Fork - LGPL
4608  * <script type="text/javascript">
4609  */
4610  
4611 /**
4612 * @class Roo.Template
4613 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4614 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4615 * Usage:
4616 <pre><code>
4617 var t = new Roo.Template({
4618     html :  '&lt;div name="{id}"&gt;' + 
4619         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4620         '&lt;/div&gt;',
4621     myformat: function (value, allValues) {
4622         return 'XX' + value;
4623     }
4624 });
4625 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4626 </code></pre>
4627 * For more information see this blog post with examples:
4628 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4629      - Create Elements using DOM, HTML fragments and Templates</a>. 
4630 * @constructor
4631 * @param {Object} cfg - Configuration object.
4632 */
4633 Roo.Template = function(cfg){
4634     // BC!
4635     if(cfg instanceof Array){
4636         cfg = cfg.join("");
4637     }else if(arguments.length > 1){
4638         cfg = Array.prototype.join.call(arguments, "");
4639     }
4640     
4641     
4642     if (typeof(cfg) == 'object') {
4643         Roo.apply(this,cfg)
4644     } else {
4645         // bc
4646         this.html = cfg;
4647     }
4648     if (this.url) {
4649         this.load();
4650     }
4651     
4652 };
4653 Roo.Template.prototype = {
4654     
4655     /**
4656      * @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..
4657      *                    it should be fixed so that template is observable...
4658      */
4659     url : false,
4660     /**
4661      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4662      */
4663     html : '',
4664     /**
4665      * Returns an HTML fragment of this template with the specified values applied.
4666      * @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'})
4667      * @return {String} The HTML fragment
4668      */
4669     applyTemplate : function(values){
4670         try {
4671            
4672             if(this.compiled){
4673                 return this.compiled(values);
4674             }
4675             var useF = this.disableFormats !== true;
4676             var fm = Roo.util.Format, tpl = this;
4677             var fn = function(m, name, format, args){
4678                 if(format && useF){
4679                     if(format.substr(0, 5) == "this."){
4680                         return tpl.call(format.substr(5), values[name], values);
4681                     }else{
4682                         if(args){
4683                             // quoted values are required for strings in compiled templates, 
4684                             // but for non compiled we need to strip them
4685                             // quoted reversed for jsmin
4686                             var re = /^\s*['"](.*)["']\s*$/;
4687                             args = args.split(',');
4688                             for(var i = 0, len = args.length; i < len; i++){
4689                                 args[i] = args[i].replace(re, "$1");
4690                             }
4691                             args = [values[name]].concat(args);
4692                         }else{
4693                             args = [values[name]];
4694                         }
4695                         return fm[format].apply(fm, args);
4696                     }
4697                 }else{
4698                     return values[name] !== undefined ? values[name] : "";
4699                 }
4700             };
4701             return this.html.replace(this.re, fn);
4702         } catch (e) {
4703             Roo.log(e);
4704             throw e;
4705         }
4706          
4707     },
4708     
4709     loading : false,
4710       
4711     load : function ()
4712     {
4713          
4714         if (this.loading) {
4715             return;
4716         }
4717         var _t = this;
4718         
4719         this.loading = true;
4720         this.compiled = false;
4721         
4722         var cx = new Roo.data.Connection();
4723         cx.request({
4724             url : this.url,
4725             method : 'GET',
4726             success : function (response) {
4727                 _t.loading = false;
4728                 _t.html = response.responseText;
4729                 _t.url = false;
4730                 _t.compile();
4731              },
4732             failure : function(response) {
4733                 Roo.log("Template failed to load from " + _t.url);
4734                 _t.loading = false;
4735             }
4736         });
4737     },
4738
4739     /**
4740      * Sets the HTML used as the template and optionally compiles it.
4741      * @param {String} html
4742      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4743      * @return {Roo.Template} this
4744      */
4745     set : function(html, compile){
4746         this.html = html;
4747         this.compiled = null;
4748         if(compile){
4749             this.compile();
4750         }
4751         return this;
4752     },
4753     
4754     /**
4755      * True to disable format functions (defaults to false)
4756      * @type Boolean
4757      */
4758     disableFormats : false,
4759     
4760     /**
4761     * The regular expression used to match template variables 
4762     * @type RegExp
4763     * @property 
4764     */
4765     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4766     
4767     /**
4768      * Compiles the template into an internal function, eliminating the RegEx overhead.
4769      * @return {Roo.Template} this
4770      */
4771     compile : function(){
4772         var fm = Roo.util.Format;
4773         var useF = this.disableFormats !== true;
4774         var sep = Roo.isGecko ? "+" : ",";
4775         var fn = function(m, name, format, args){
4776             if(format && useF){
4777                 args = args ? ',' + args : "";
4778                 if(format.substr(0, 5) != "this."){
4779                     format = "fm." + format + '(';
4780                 }else{
4781                     format = 'this.call("'+ format.substr(5) + '", ';
4782                     args = ", values";
4783                 }
4784             }else{
4785                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4786             }
4787             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4788         };
4789         var body;
4790         // branched to use + in gecko and [].join() in others
4791         if(Roo.isGecko){
4792             body = "this.compiled = function(values){ return '" +
4793                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4794                     "';};";
4795         }else{
4796             body = ["this.compiled = function(values){ return ['"];
4797             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4798             body.push("'].join('');};");
4799             body = body.join('');
4800         }
4801         /**
4802          * eval:var:values
4803          * eval:var:fm
4804          */
4805         eval(body);
4806         return this;
4807     },
4808     
4809     // private function used to call members
4810     call : function(fnName, value, allValues){
4811         return this[fnName](value, allValues);
4812     },
4813     
4814     /**
4815      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4816      * @param {String/HTMLElement/Roo.Element} el The context element
4817      * @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'})
4818      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4819      * @return {HTMLElement/Roo.Element} The new node or Element
4820      */
4821     insertFirst: function(el, values, returnElement){
4822         return this.doInsert('afterBegin', el, values, returnElement);
4823     },
4824
4825     /**
4826      * Applies the supplied values to the template and inserts the new node(s) before el.
4827      * @param {String/HTMLElement/Roo.Element} el The context element
4828      * @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'})
4829      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4830      * @return {HTMLElement/Roo.Element} The new node or Element
4831      */
4832     insertBefore: function(el, values, returnElement){
4833         return this.doInsert('beforeBegin', el, values, returnElement);
4834     },
4835
4836     /**
4837      * Applies the supplied values to the template and inserts the new node(s) after el.
4838      * @param {String/HTMLElement/Roo.Element} el The context element
4839      * @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'})
4840      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4841      * @return {HTMLElement/Roo.Element} The new node or Element
4842      */
4843     insertAfter : function(el, values, returnElement){
4844         return this.doInsert('afterEnd', el, values, returnElement);
4845     },
4846     
4847     /**
4848      * Applies the supplied values to the template and appends the new node(s) to el.
4849      * @param {String/HTMLElement/Roo.Element} el The context element
4850      * @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'})
4851      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4852      * @return {HTMLElement/Roo.Element} The new node or Element
4853      */
4854     append : function(el, values, returnElement){
4855         return this.doInsert('beforeEnd', el, values, returnElement);
4856     },
4857
4858     doInsert : function(where, el, values, returnEl){
4859         el = Roo.getDom(el);
4860         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4861         return returnEl ? Roo.get(newNode, true) : newNode;
4862     },
4863
4864     /**
4865      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4866      * @param {String/HTMLElement/Roo.Element} el The context element
4867      * @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'})
4868      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4869      * @return {HTMLElement/Roo.Element} The new node or Element
4870      */
4871     overwrite : function(el, values, returnElement){
4872         el = Roo.getDom(el);
4873         el.innerHTML = this.applyTemplate(values);
4874         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4875     }
4876 };
4877 /**
4878  * Alias for {@link #applyTemplate}
4879  * @method
4880  */
4881 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4882
4883 // backwards compat
4884 Roo.DomHelper.Template = Roo.Template;
4885
4886 /**
4887  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4888  * @param {String/HTMLElement} el A DOM element or its id
4889  * @returns {Roo.Template} The created template
4890  * @static
4891  */
4892 Roo.Template.from = function(el){
4893     el = Roo.getDom(el);
4894     return new Roo.Template(el.value || el.innerHTML);
4895 };/*
4896  * Based on:
4897  * Ext JS Library 1.1.1
4898  * Copyright(c) 2006-2007, Ext JS, LLC.
4899  *
4900  * Originally Released Under LGPL - original licence link has changed is not relivant.
4901  *
4902  * Fork - LGPL
4903  * <script type="text/javascript">
4904  */
4905  
4906
4907 /*
4908  * This is code is also distributed under MIT license for use
4909  * with jQuery and prototype JavaScript libraries.
4910  */
4911 /**
4912  * @class Roo.DomQuery
4913 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).
4914 <p>
4915 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>
4916
4917 <p>
4918 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.
4919 </p>
4920 <h4>Element Selectors:</h4>
4921 <ul class="list">
4922     <li> <b>*</b> any element</li>
4923     <li> <b>E</b> an element with the tag E</li>
4924     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4925     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4926     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4927     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4928 </ul>
4929 <h4>Attribute Selectors:</h4>
4930 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4931 <ul class="list">
4932     <li> <b>E[foo]</b> has an attribute "foo"</li>
4933     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4934     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4935     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4936     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4937     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4938     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4939 </ul>
4940 <h4>Pseudo Classes:</h4>
4941 <ul class="list">
4942     <li> <b>E:first-child</b> E is the first child of its parent</li>
4943     <li> <b>E:last-child</b> E is the last child of its parent</li>
4944     <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>
4945     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4946     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4947     <li> <b>E:only-child</b> E is the only child of its parent</li>
4948     <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>
4949     <li> <b>E:first</b> the first E in the resultset</li>
4950     <li> <b>E:last</b> the last E in the resultset</li>
4951     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4952     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4953     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4954     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4955     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4956     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4957     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4958     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4959     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4960 </ul>
4961 <h4>CSS Value Selectors:</h4>
4962 <ul class="list">
4963     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4964     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4965     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4966     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4967     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4968     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4969 </ul>
4970  * @singleton
4971  */
4972 Roo.DomQuery = function(){
4973     var cache = {}, simpleCache = {}, valueCache = {};
4974     var nonSpace = /\S/;
4975     var trimRe = /^\s+|\s+$/g;
4976     var tplRe = /\{(\d+)\}/g;
4977     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4978     var tagTokenRe = /^(#)?([\w-\*]+)/;
4979     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4980
4981     function child(p, index){
4982         var i = 0;
4983         var n = p.firstChild;
4984         while(n){
4985             if(n.nodeType == 1){
4986                if(++i == index){
4987                    return n;
4988                }
4989             }
4990             n = n.nextSibling;
4991         }
4992         return null;
4993     };
4994
4995     function next(n){
4996         while((n = n.nextSibling) && n.nodeType != 1);
4997         return n;
4998     };
4999
5000     function prev(n){
5001         while((n = n.previousSibling) && n.nodeType != 1);
5002         return n;
5003     };
5004
5005     function children(d){
5006         var n = d.firstChild, ni = -1;
5007             while(n){
5008                 var nx = n.nextSibling;
5009                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5010                     d.removeChild(n);
5011                 }else{
5012                     n.nodeIndex = ++ni;
5013                 }
5014                 n = nx;
5015             }
5016             return this;
5017         };
5018
5019     function byClassName(c, a, v){
5020         if(!v){
5021             return c;
5022         }
5023         var r = [], ri = -1, cn;
5024         for(var i = 0, ci; ci = c[i]; i++){
5025             if((' '+ci.className+' ').indexOf(v) != -1){
5026                 r[++ri] = ci;
5027             }
5028         }
5029         return r;
5030     };
5031
5032     function attrValue(n, attr){
5033         if(!n.tagName && typeof n.length != "undefined"){
5034             n = n[0];
5035         }
5036         if(!n){
5037             return null;
5038         }
5039         if(attr == "for"){
5040             return n.htmlFor;
5041         }
5042         if(attr == "class" || attr == "className"){
5043             return n.className;
5044         }
5045         return n.getAttribute(attr) || n[attr];
5046
5047     };
5048
5049     function getNodes(ns, mode, tagName){
5050         var result = [], ri = -1, cs;
5051         if(!ns){
5052             return result;
5053         }
5054         tagName = tagName || "*";
5055         if(typeof ns.getElementsByTagName != "undefined"){
5056             ns = [ns];
5057         }
5058         if(!mode){
5059             for(var i = 0, ni; ni = ns[i]; i++){
5060                 cs = ni.getElementsByTagName(tagName);
5061                 for(var j = 0, ci; ci = cs[j]; j++){
5062                     result[++ri] = ci;
5063                 }
5064             }
5065         }else if(mode == "/" || mode == ">"){
5066             var utag = tagName.toUpperCase();
5067             for(var i = 0, ni, cn; ni = ns[i]; i++){
5068                 cn = ni.children || ni.childNodes;
5069                 for(var j = 0, cj; cj = cn[j]; j++){
5070                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5071                         result[++ri] = cj;
5072                     }
5073                 }
5074             }
5075         }else if(mode == "+"){
5076             var utag = tagName.toUpperCase();
5077             for(var i = 0, n; n = ns[i]; i++){
5078                 while((n = n.nextSibling) && n.nodeType != 1);
5079                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5080                     result[++ri] = n;
5081                 }
5082             }
5083         }else if(mode == "~"){
5084             for(var i = 0, n; n = ns[i]; i++){
5085                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5086                 if(n){
5087                     result[++ri] = n;
5088                 }
5089             }
5090         }
5091         return result;
5092     };
5093
5094     function concat(a, b){
5095         if(b.slice){
5096             return a.concat(b);
5097         }
5098         for(var i = 0, l = b.length; i < l; i++){
5099             a[a.length] = b[i];
5100         }
5101         return a;
5102     }
5103
5104     function byTag(cs, tagName){
5105         if(cs.tagName || cs == document){
5106             cs = [cs];
5107         }
5108         if(!tagName){
5109             return cs;
5110         }
5111         var r = [], ri = -1;
5112         tagName = tagName.toLowerCase();
5113         for(var i = 0, ci; ci = cs[i]; i++){
5114             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5115                 r[++ri] = ci;
5116             }
5117         }
5118         return r;
5119     };
5120
5121     function byId(cs, attr, id){
5122         if(cs.tagName || cs == document){
5123             cs = [cs];
5124         }
5125         if(!id){
5126             return cs;
5127         }
5128         var r = [], ri = -1;
5129         for(var i = 0,ci; ci = cs[i]; i++){
5130             if(ci && ci.id == id){
5131                 r[++ri] = ci;
5132                 return r;
5133             }
5134         }
5135         return r;
5136     };
5137
5138     function byAttribute(cs, attr, value, op, custom){
5139         var r = [], ri = -1, st = custom=="{";
5140         var f = Roo.DomQuery.operators[op];
5141         for(var i = 0, ci; ci = cs[i]; i++){
5142             var a;
5143             if(st){
5144                 a = Roo.DomQuery.getStyle(ci, attr);
5145             }
5146             else if(attr == "class" || attr == "className"){
5147                 a = ci.className;
5148             }else if(attr == "for"){
5149                 a = ci.htmlFor;
5150             }else if(attr == "href"){
5151                 a = ci.getAttribute("href", 2);
5152             }else{
5153                 a = ci.getAttribute(attr);
5154             }
5155             if((f && f(a, value)) || (!f && a)){
5156                 r[++ri] = ci;
5157             }
5158         }
5159         return r;
5160     };
5161
5162     function byPseudo(cs, name, value){
5163         return Roo.DomQuery.pseudos[name](cs, value);
5164     };
5165
5166     // This is for IE MSXML which does not support expandos.
5167     // IE runs the same speed using setAttribute, however FF slows way down
5168     // and Safari completely fails so they need to continue to use expandos.
5169     var isIE = window.ActiveXObject ? true : false;
5170
5171     // this eval is stop the compressor from
5172     // renaming the variable to something shorter
5173     
5174     /** eval:var:batch */
5175     var batch = 30803; 
5176
5177     var key = 30803;
5178
5179     function nodupIEXml(cs){
5180         var d = ++key;
5181         cs[0].setAttribute("_nodup", d);
5182         var r = [cs[0]];
5183         for(var i = 1, len = cs.length; i < len; i++){
5184             var c = cs[i];
5185             if(!c.getAttribute("_nodup") != d){
5186                 c.setAttribute("_nodup", d);
5187                 r[r.length] = c;
5188             }
5189         }
5190         for(var i = 0, len = cs.length; i < len; i++){
5191             cs[i].removeAttribute("_nodup");
5192         }
5193         return r;
5194     }
5195
5196     function nodup(cs){
5197         if(!cs){
5198             return [];
5199         }
5200         var len = cs.length, c, i, r = cs, cj, ri = -1;
5201         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5202             return cs;
5203         }
5204         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5205             return nodupIEXml(cs);
5206         }
5207         var d = ++key;
5208         cs[0]._nodup = d;
5209         for(i = 1; c = cs[i]; i++){
5210             if(c._nodup != d){
5211                 c._nodup = d;
5212             }else{
5213                 r = [];
5214                 for(var j = 0; j < i; j++){
5215                     r[++ri] = cs[j];
5216                 }
5217                 for(j = i+1; cj = cs[j]; j++){
5218                     if(cj._nodup != d){
5219                         cj._nodup = d;
5220                         r[++ri] = cj;
5221                     }
5222                 }
5223                 return r;
5224             }
5225         }
5226         return r;
5227     }
5228
5229     function quickDiffIEXml(c1, c2){
5230         var d = ++key;
5231         for(var i = 0, len = c1.length; i < len; i++){
5232             c1[i].setAttribute("_qdiff", d);
5233         }
5234         var r = [];
5235         for(var i = 0, len = c2.length; i < len; i++){
5236             if(c2[i].getAttribute("_qdiff") != d){
5237                 r[r.length] = c2[i];
5238             }
5239         }
5240         for(var i = 0, len = c1.length; i < len; i++){
5241            c1[i].removeAttribute("_qdiff");
5242         }
5243         return r;
5244     }
5245
5246     function quickDiff(c1, c2){
5247         var len1 = c1.length;
5248         if(!len1){
5249             return c2;
5250         }
5251         if(isIE && c1[0].selectSingleNode){
5252             return quickDiffIEXml(c1, c2);
5253         }
5254         var d = ++key;
5255         for(var i = 0; i < len1; i++){
5256             c1[i]._qdiff = d;
5257         }
5258         var r = [];
5259         for(var i = 0, len = c2.length; i < len; i++){
5260             if(c2[i]._qdiff != d){
5261                 r[r.length] = c2[i];
5262             }
5263         }
5264         return r;
5265     }
5266
5267     function quickId(ns, mode, root, id){
5268         if(ns == root){
5269            var d = root.ownerDocument || root;
5270            return d.getElementById(id);
5271         }
5272         ns = getNodes(ns, mode, "*");
5273         return byId(ns, null, id);
5274     }
5275
5276     return {
5277         getStyle : function(el, name){
5278             return Roo.fly(el).getStyle(name);
5279         },
5280         /**
5281          * Compiles a selector/xpath query into a reusable function. The returned function
5282          * takes one parameter "root" (optional), which is the context node from where the query should start.
5283          * @param {String} selector The selector/xpath query
5284          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5285          * @return {Function}
5286          */
5287         compile : function(path, type){
5288             type = type || "select";
5289             
5290             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5291             var q = path, mode, lq;
5292             var tk = Roo.DomQuery.matchers;
5293             var tklen = tk.length;
5294             var mm;
5295
5296             // accept leading mode switch
5297             var lmode = q.match(modeRe);
5298             if(lmode && lmode[1]){
5299                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5300                 q = q.replace(lmode[1], "");
5301             }
5302             // strip leading slashes
5303             while(path.substr(0, 1)=="/"){
5304                 path = path.substr(1);
5305             }
5306
5307             while(q && lq != q){
5308                 lq = q;
5309                 var tm = q.match(tagTokenRe);
5310                 if(type == "select"){
5311                     if(tm){
5312                         if(tm[1] == "#"){
5313                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5314                         }else{
5315                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5316                         }
5317                         q = q.replace(tm[0], "");
5318                     }else if(q.substr(0, 1) != '@'){
5319                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5320                     }
5321                 }else{
5322                     if(tm){
5323                         if(tm[1] == "#"){
5324                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5325                         }else{
5326                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5327                         }
5328                         q = q.replace(tm[0], "");
5329                     }
5330                 }
5331                 while(!(mm = q.match(modeRe))){
5332                     var matched = false;
5333                     for(var j = 0; j < tklen; j++){
5334                         var t = tk[j];
5335                         var m = q.match(t.re);
5336                         if(m){
5337                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5338                                                     return m[i];
5339                                                 });
5340                             q = q.replace(m[0], "");
5341                             matched = true;
5342                             break;
5343                         }
5344                     }
5345                     // prevent infinite loop on bad selector
5346                     if(!matched){
5347                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5348                     }
5349                 }
5350                 if(mm[1]){
5351                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5352                     q = q.replace(mm[1], "");
5353                 }
5354             }
5355             fn[fn.length] = "return nodup(n);\n}";
5356             
5357              /** 
5358               * list of variables that need from compression as they are used by eval.
5359              *  eval:var:batch 
5360              *  eval:var:nodup
5361              *  eval:var:byTag
5362              *  eval:var:ById
5363              *  eval:var:getNodes
5364              *  eval:var:quickId
5365              *  eval:var:mode
5366              *  eval:var:root
5367              *  eval:var:n
5368              *  eval:var:byClassName
5369              *  eval:var:byPseudo
5370              *  eval:var:byAttribute
5371              *  eval:var:attrValue
5372              * 
5373              **/ 
5374             eval(fn.join(""));
5375             return f;
5376         },
5377
5378         /**
5379          * Selects a group of elements.
5380          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5381          * @param {Node} root (optional) The start of the query (defaults to document).
5382          * @return {Array}
5383          */
5384         select : function(path, root, type){
5385             if(!root || root == document){
5386                 root = document;
5387             }
5388             if(typeof root == "string"){
5389                 root = document.getElementById(root);
5390             }
5391             var paths = path.split(",");
5392             var results = [];
5393             for(var i = 0, len = paths.length; i < len; i++){
5394                 var p = paths[i].replace(trimRe, "");
5395                 if(!cache[p]){
5396                     cache[p] = Roo.DomQuery.compile(p);
5397                     if(!cache[p]){
5398                         throw p + " is not a valid selector";
5399                     }
5400                 }
5401                 var result = cache[p](root);
5402                 if(result && result != document){
5403                     results = results.concat(result);
5404                 }
5405             }
5406             if(paths.length > 1){
5407                 return nodup(results);
5408             }
5409             return results;
5410         },
5411
5412         /**
5413          * Selects a single element.
5414          * @param {String} selector The selector/xpath query
5415          * @param {Node} root (optional) The start of the query (defaults to document).
5416          * @return {Element}
5417          */
5418         selectNode : function(path, root){
5419             return Roo.DomQuery.select(path, root)[0];
5420         },
5421
5422         /**
5423          * Selects the value of a node, optionally replacing null with the defaultValue.
5424          * @param {String} selector The selector/xpath query
5425          * @param {Node} root (optional) The start of the query (defaults to document).
5426          * @param {String} defaultValue
5427          */
5428         selectValue : function(path, root, defaultValue){
5429             path = path.replace(trimRe, "");
5430             if(!valueCache[path]){
5431                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5432             }
5433             var n = valueCache[path](root);
5434             n = n[0] ? n[0] : n;
5435             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5436             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5437         },
5438
5439         /**
5440          * Selects the value of a node, parsing integers and floats.
5441          * @param {String} selector The selector/xpath query
5442          * @param {Node} root (optional) The start of the query (defaults to document).
5443          * @param {Number} defaultValue
5444          * @return {Number}
5445          */
5446         selectNumber : function(path, root, defaultValue){
5447             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5448             return parseFloat(v);
5449         },
5450
5451         /**
5452          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5453          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5454          * @param {String} selector The simple selector to test
5455          * @return {Boolean}
5456          */
5457         is : function(el, ss){
5458             if(typeof el == "string"){
5459                 el = document.getElementById(el);
5460             }
5461             var isArray = (el instanceof Array);
5462             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5463             return isArray ? (result.length == el.length) : (result.length > 0);
5464         },
5465
5466         /**
5467          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5468          * @param {Array} el An array of elements to filter
5469          * @param {String} selector The simple selector to test
5470          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5471          * the selector instead of the ones that match
5472          * @return {Array}
5473          */
5474         filter : function(els, ss, nonMatches){
5475             ss = ss.replace(trimRe, "");
5476             if(!simpleCache[ss]){
5477                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5478             }
5479             var result = simpleCache[ss](els);
5480             return nonMatches ? quickDiff(result, els) : result;
5481         },
5482
5483         /**
5484          * Collection of matching regular expressions and code snippets.
5485          */
5486         matchers : [{
5487                 re: /^\.([\w-]+)/,
5488                 select: 'n = byClassName(n, null, " {1} ");'
5489             }, {
5490                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5491                 select: 'n = byPseudo(n, "{1}", "{2}");'
5492             },{
5493                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5494                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5495             }, {
5496                 re: /^#([\w-]+)/,
5497                 select: 'n = byId(n, null, "{1}");'
5498             },{
5499                 re: /^@([\w-]+)/,
5500                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5501             }
5502         ],
5503
5504         /**
5505          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5506          * 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;.
5507          */
5508         operators : {
5509             "=" : function(a, v){
5510                 return a == v;
5511             },
5512             "!=" : function(a, v){
5513                 return a != v;
5514             },
5515             "^=" : function(a, v){
5516                 return a && a.substr(0, v.length) == v;
5517             },
5518             "$=" : function(a, v){
5519                 return a && a.substr(a.length-v.length) == v;
5520             },
5521             "*=" : function(a, v){
5522                 return a && a.indexOf(v) !== -1;
5523             },
5524             "%=" : function(a, v){
5525                 return (a % v) == 0;
5526             },
5527             "|=" : function(a, v){
5528                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5529             },
5530             "~=" : function(a, v){
5531                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5532             }
5533         },
5534
5535         /**
5536          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5537          * and the argument (if any) supplied in the selector.
5538          */
5539         pseudos : {
5540             "first-child" : function(c){
5541                 var r = [], ri = -1, n;
5542                 for(var i = 0, ci; ci = n = c[i]; i++){
5543                     while((n = n.previousSibling) && n.nodeType != 1);
5544                     if(!n){
5545                         r[++ri] = ci;
5546                     }
5547                 }
5548                 return r;
5549             },
5550
5551             "last-child" : function(c){
5552                 var r = [], ri = -1, n;
5553                 for(var i = 0, ci; ci = n = c[i]; i++){
5554                     while((n = n.nextSibling) && n.nodeType != 1);
5555                     if(!n){
5556                         r[++ri] = ci;
5557                     }
5558                 }
5559                 return r;
5560             },
5561
5562             "nth-child" : function(c, a) {
5563                 var r = [], ri = -1;
5564                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5565                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5566                 for(var i = 0, n; n = c[i]; i++){
5567                     var pn = n.parentNode;
5568                     if (batch != pn._batch) {
5569                         var j = 0;
5570                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5571                             if(cn.nodeType == 1){
5572                                cn.nodeIndex = ++j;
5573                             }
5574                         }
5575                         pn._batch = batch;
5576                     }
5577                     if (f == 1) {
5578                         if (l == 0 || n.nodeIndex == l){
5579                             r[++ri] = n;
5580                         }
5581                     } else if ((n.nodeIndex + l) % f == 0){
5582                         r[++ri] = n;
5583                     }
5584                 }
5585
5586                 return r;
5587             },
5588
5589             "only-child" : function(c){
5590                 var r = [], ri = -1;;
5591                 for(var i = 0, ci; ci = c[i]; i++){
5592                     if(!prev(ci) && !next(ci)){
5593                         r[++ri] = ci;
5594                     }
5595                 }
5596                 return r;
5597             },
5598
5599             "empty" : function(c){
5600                 var r = [], ri = -1;
5601                 for(var i = 0, ci; ci = c[i]; i++){
5602                     var cns = ci.childNodes, j = 0, cn, empty = true;
5603                     while(cn = cns[j]){
5604                         ++j;
5605                         if(cn.nodeType == 1 || cn.nodeType == 3){
5606                             empty = false;
5607                             break;
5608                         }
5609                     }
5610                     if(empty){
5611                         r[++ri] = ci;
5612                     }
5613                 }
5614                 return r;
5615             },
5616
5617             "contains" : function(c, v){
5618                 var r = [], ri = -1;
5619                 for(var i = 0, ci; ci = c[i]; i++){
5620                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5621                         r[++ri] = ci;
5622                     }
5623                 }
5624                 return r;
5625             },
5626
5627             "nodeValue" : function(c, v){
5628                 var r = [], ri = -1;
5629                 for(var i = 0, ci; ci = c[i]; i++){
5630                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5631                         r[++ri] = ci;
5632                     }
5633                 }
5634                 return r;
5635             },
5636
5637             "checked" : function(c){
5638                 var r = [], ri = -1;
5639                 for(var i = 0, ci; ci = c[i]; i++){
5640                     if(ci.checked == true){
5641                         r[++ri] = ci;
5642                     }
5643                 }
5644                 return r;
5645             },
5646
5647             "not" : function(c, ss){
5648                 return Roo.DomQuery.filter(c, ss, true);
5649             },
5650
5651             "odd" : function(c){
5652                 return this["nth-child"](c, "odd");
5653             },
5654
5655             "even" : function(c){
5656                 return this["nth-child"](c, "even");
5657             },
5658
5659             "nth" : function(c, a){
5660                 return c[a-1] || [];
5661             },
5662
5663             "first" : function(c){
5664                 return c[0] || [];
5665             },
5666
5667             "last" : function(c){
5668                 return c[c.length-1] || [];
5669             },
5670
5671             "has" : function(c, ss){
5672                 var s = Roo.DomQuery.select;
5673                 var r = [], ri = -1;
5674                 for(var i = 0, ci; ci = c[i]; i++){
5675                     if(s(ss, ci).length > 0){
5676                         r[++ri] = ci;
5677                     }
5678                 }
5679                 return r;
5680             },
5681
5682             "next" : function(c, ss){
5683                 var is = Roo.DomQuery.is;
5684                 var r = [], ri = -1;
5685                 for(var i = 0, ci; ci = c[i]; i++){
5686                     var n = next(ci);
5687                     if(n && is(n, ss)){
5688                         r[++ri] = ci;
5689                     }
5690                 }
5691                 return r;
5692             },
5693
5694             "prev" : function(c, ss){
5695                 var is = Roo.DomQuery.is;
5696                 var r = [], ri = -1;
5697                 for(var i = 0, ci; ci = c[i]; i++){
5698                     var n = prev(ci);
5699                     if(n && is(n, ss)){
5700                         r[++ri] = ci;
5701                     }
5702                 }
5703                 return r;
5704             }
5705         }
5706     };
5707 }();
5708
5709 /**
5710  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5711  * @param {String} path The selector/xpath query
5712  * @param {Node} root (optional) The start of the query (defaults to document).
5713  * @return {Array}
5714  * @member Roo
5715  * @method query
5716  */
5717 Roo.query = Roo.DomQuery.select;
5718 /*
5719  * Based on:
5720  * Ext JS Library 1.1.1
5721  * Copyright(c) 2006-2007, Ext JS, LLC.
5722  *
5723  * Originally Released Under LGPL - original licence link has changed is not relivant.
5724  *
5725  * Fork - LGPL
5726  * <script type="text/javascript">
5727  */
5728
5729 /**
5730  * @class Roo.util.Observable
5731  * Base class that provides a common interface for publishing events. Subclasses are expected to
5732  * to have a property "events" with all the events defined.<br>
5733  * For example:
5734  * <pre><code>
5735  Employee = function(name){
5736     this.name = name;
5737     this.addEvents({
5738         "fired" : true,
5739         "quit" : true
5740     });
5741  }
5742  Roo.extend(Employee, Roo.util.Observable);
5743 </code></pre>
5744  * @param {Object} config properties to use (incuding events / listeners)
5745  */
5746
5747 Roo.util.Observable = function(cfg){
5748     
5749     cfg = cfg|| {};
5750     this.addEvents(cfg.events || {});
5751     if (cfg.events) {
5752         delete cfg.events; // make sure
5753     }
5754      
5755     Roo.apply(this, cfg);
5756     
5757     if(this.listeners){
5758         this.on(this.listeners);
5759         delete this.listeners;
5760     }
5761 };
5762 Roo.util.Observable.prototype = {
5763     /** 
5764  * @cfg {Object} listeners  list of events and functions to call for this object, 
5765  * For example :
5766  * <pre><code>
5767     listeners :  { 
5768        'click' : function(e) {
5769            ..... 
5770         } ,
5771         .... 
5772     } 
5773   </code></pre>
5774  */
5775     
5776     
5777     /**
5778      * Fires the specified event with the passed parameters (minus the event name).
5779      * @param {String} eventName
5780      * @param {Object...} args Variable number of parameters are passed to handlers
5781      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5782      */
5783     fireEvent : function(){
5784         var ce = this.events[arguments[0].toLowerCase()];
5785         if(typeof ce == "object"){
5786             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5787         }else{
5788             return true;
5789         }
5790     },
5791
5792     // private
5793     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5794
5795     /**
5796      * Appends an event handler to this component
5797      * @param {String}   eventName The type of event to listen for
5798      * @param {Function} handler The method the event invokes
5799      * @param {Object}   scope (optional) The scope in which to execute the handler
5800      * function. The handler function's "this" context.
5801      * @param {Object}   options (optional) An object containing handler configuration
5802      * properties. This may contain any of the following properties:<ul>
5803      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5804      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5805      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5806      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5807      * by the specified number of milliseconds. If the event fires again within that time, the original
5808      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5809      * </ul><br>
5810      * <p>
5811      * <b>Combining Options</b><br>
5812      * Using the options argument, it is possible to combine different types of listeners:<br>
5813      * <br>
5814      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5815                 <pre><code>
5816                 el.on('click', this.onClick, this, {
5817                         single: true,
5818                 delay: 100,
5819                 forumId: 4
5820                 });
5821                 </code></pre>
5822      * <p>
5823      * <b>Attaching multiple handlers in 1 call</b><br>
5824      * The method also allows for a single argument to be passed which is a config object containing properties
5825      * which specify multiple handlers.
5826      * <pre><code>
5827                 el.on({
5828                         'click': {
5829                         fn: this.onClick,
5830                         scope: this,
5831                         delay: 100
5832                 }, 
5833                 'mouseover': {
5834                         fn: this.onMouseOver,
5835                         scope: this
5836                 },
5837                 'mouseout': {
5838                         fn: this.onMouseOut,
5839                         scope: this
5840                 }
5841                 });
5842                 </code></pre>
5843      * <p>
5844      * Or a shorthand syntax which passes the same scope object to all handlers:
5845         <pre><code>
5846                 el.on({
5847                         'click': this.onClick,
5848                 'mouseover': this.onMouseOver,
5849                 'mouseout': this.onMouseOut,
5850                 scope: this
5851                 });
5852                 </code></pre>
5853      */
5854     addListener : function(eventName, fn, scope, o){
5855         if(typeof eventName == "object"){
5856             o = eventName;
5857             for(var e in o){
5858                 if(this.filterOptRe.test(e)){
5859                     continue;
5860                 }
5861                 if(typeof o[e] == "function"){
5862                     // shared options
5863                     this.addListener(e, o[e], o.scope,  o);
5864                 }else{
5865                     // individual options
5866                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5867                 }
5868             }
5869             return;
5870         }
5871         o = (!o || typeof o == "boolean") ? {} : o;
5872         eventName = eventName.toLowerCase();
5873         var ce = this.events[eventName] || true;
5874         if(typeof ce == "boolean"){
5875             ce = new Roo.util.Event(this, eventName);
5876             this.events[eventName] = ce;
5877         }
5878         ce.addListener(fn, scope, o);
5879     },
5880
5881     /**
5882      * Removes a listener
5883      * @param {String}   eventName     The type of event to listen for
5884      * @param {Function} handler        The handler to remove
5885      * @param {Object}   scope  (optional) The scope (this object) for the handler
5886      */
5887     removeListener : function(eventName, fn, scope){
5888         var ce = this.events[eventName.toLowerCase()];
5889         if(typeof ce == "object"){
5890             ce.removeListener(fn, scope);
5891         }
5892     },
5893
5894     /**
5895      * Removes all listeners for this object
5896      */
5897     purgeListeners : function(){
5898         for(var evt in this.events){
5899             if(typeof this.events[evt] == "object"){
5900                  this.events[evt].clearListeners();
5901             }
5902         }
5903     },
5904
5905     relayEvents : function(o, events){
5906         var createHandler = function(ename){
5907             return function(){
5908                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5909             };
5910         };
5911         for(var i = 0, len = events.length; i < len; i++){
5912             var ename = events[i];
5913             if(!this.events[ename]){ this.events[ename] = true; };
5914             o.on(ename, createHandler(ename), this);
5915         }
5916     },
5917
5918     /**
5919      * Used to define events on this Observable
5920      * @param {Object} object The object with the events defined
5921      */
5922     addEvents : function(o){
5923         if(!this.events){
5924             this.events = {};
5925         }
5926         Roo.applyIf(this.events, o);
5927     },
5928
5929     /**
5930      * Checks to see if this object has any listeners for a specified event
5931      * @param {String} eventName The name of the event to check for
5932      * @return {Boolean} True if the event is being listened for, else false
5933      */
5934     hasListener : function(eventName){
5935         var e = this.events[eventName];
5936         return typeof e == "object" && e.listeners.length > 0;
5937     }
5938 };
5939 /**
5940  * Appends an event handler to this element (shorthand for addListener)
5941  * @param {String}   eventName     The type of event to listen for
5942  * @param {Function} handler        The method the event invokes
5943  * @param {Object}   scope (optional) The scope in which to execute the handler
5944  * function. The handler function's "this" context.
5945  * @param {Object}   options  (optional)
5946  * @method
5947  */
5948 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5949 /**
5950  * Removes a listener (shorthand for removeListener)
5951  * @param {String}   eventName     The type of event to listen for
5952  * @param {Function} handler        The handler to remove
5953  * @param {Object}   scope  (optional) The scope (this object) for the handler
5954  * @method
5955  */
5956 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5957
5958 /**
5959  * Starts capture on the specified Observable. All events will be passed
5960  * to the supplied function with the event name + standard signature of the event
5961  * <b>before</b> the event is fired. If the supplied function returns false,
5962  * the event will not fire.
5963  * @param {Observable} o The Observable to capture
5964  * @param {Function} fn The function to call
5965  * @param {Object} scope (optional) The scope (this object) for the fn
5966  * @static
5967  */
5968 Roo.util.Observable.capture = function(o, fn, scope){
5969     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5970 };
5971
5972 /**
5973  * Removes <b>all</b> added captures from the Observable.
5974  * @param {Observable} o The Observable to release
5975  * @static
5976  */
5977 Roo.util.Observable.releaseCapture = function(o){
5978     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5979 };
5980
5981 (function(){
5982
5983     var createBuffered = function(h, o, scope){
5984         var task = new Roo.util.DelayedTask();
5985         return function(){
5986             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5987         };
5988     };
5989
5990     var createSingle = function(h, e, fn, scope){
5991         return function(){
5992             e.removeListener(fn, scope);
5993             return h.apply(scope, arguments);
5994         };
5995     };
5996
5997     var createDelayed = function(h, o, scope){
5998         return function(){
5999             var args = Array.prototype.slice.call(arguments, 0);
6000             setTimeout(function(){
6001                 h.apply(scope, args);
6002             }, o.delay || 10);
6003         };
6004     };
6005
6006     Roo.util.Event = function(obj, name){
6007         this.name = name;
6008         this.obj = obj;
6009         this.listeners = [];
6010     };
6011
6012     Roo.util.Event.prototype = {
6013         addListener : function(fn, scope, options){
6014             var o = options || {};
6015             scope = scope || this.obj;
6016             if(!this.isListening(fn, scope)){
6017                 var l = {fn: fn, scope: scope, options: o};
6018                 var h = fn;
6019                 if(o.delay){
6020                     h = createDelayed(h, o, scope);
6021                 }
6022                 if(o.single){
6023                     h = createSingle(h, this, fn, scope);
6024                 }
6025                 if(o.buffer){
6026                     h = createBuffered(h, o, scope);
6027                 }
6028                 l.fireFn = h;
6029                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6030                     this.listeners.push(l);
6031                 }else{
6032                     this.listeners = this.listeners.slice(0);
6033                     this.listeners.push(l);
6034                 }
6035             }
6036         },
6037
6038         findListener : function(fn, scope){
6039             scope = scope || this.obj;
6040             var ls = this.listeners;
6041             for(var i = 0, len = ls.length; i < len; i++){
6042                 var l = ls[i];
6043                 if(l.fn == fn && l.scope == scope){
6044                     return i;
6045                 }
6046             }
6047             return -1;
6048         },
6049
6050         isListening : function(fn, scope){
6051             return this.findListener(fn, scope) != -1;
6052         },
6053
6054         removeListener : function(fn, scope){
6055             var index;
6056             if((index = this.findListener(fn, scope)) != -1){
6057                 if(!this.firing){
6058                     this.listeners.splice(index, 1);
6059                 }else{
6060                     this.listeners = this.listeners.slice(0);
6061                     this.listeners.splice(index, 1);
6062                 }
6063                 return true;
6064             }
6065             return false;
6066         },
6067
6068         clearListeners : function(){
6069             this.listeners = [];
6070         },
6071
6072         fire : function(){
6073             var ls = this.listeners, scope, len = ls.length;
6074             if(len > 0){
6075                 this.firing = true;
6076                 var args = Array.prototype.slice.call(arguments, 0);
6077                 for(var i = 0; i < len; i++){
6078                     var l = ls[i];
6079                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6080                         this.firing = false;
6081                         return false;
6082                     }
6083                 }
6084                 this.firing = false;
6085             }
6086             return true;
6087         }
6088     };
6089 })();/*
6090  * RooJS Library 
6091  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6092  *
6093  * Licence LGPL 
6094  *
6095  */
6096  
6097 /**
6098  * @class Roo.Document
6099  * @extends Roo.util.Observable
6100  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6101  * 
6102  * @param {Object} config the methods and properties of the 'base' class for the application.
6103  * 
6104  *  Generic Page handler - implement this to start your app..
6105  * 
6106  * eg.
6107  *  MyProject = new Roo.Document({
6108         events : {
6109             'load' : true // your events..
6110         },
6111         listeners : {
6112             'ready' : function() {
6113                 // fired on Roo.onReady()
6114             }
6115         }
6116  * 
6117  */
6118 Roo.Document = function(cfg) {
6119      
6120     this.addEvents({ 
6121         'ready' : true
6122     });
6123     Roo.util.Observable.call(this,cfg);
6124     
6125     var _this = this;
6126     
6127     Roo.onReady(function() {
6128         _this.fireEvent('ready');
6129     },null,false);
6130     
6131     
6132 }
6133
6134 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6135  * Based on:
6136  * Ext JS Library 1.1.1
6137  * Copyright(c) 2006-2007, Ext JS, LLC.
6138  *
6139  * Originally Released Under LGPL - original licence link has changed is not relivant.
6140  *
6141  * Fork - LGPL
6142  * <script type="text/javascript">
6143  */
6144
6145 /**
6146  * @class Roo.EventManager
6147  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6148  * several useful events directly.
6149  * See {@link Roo.EventObject} for more details on normalized event objects.
6150  * @singleton
6151  */
6152 Roo.EventManager = function(){
6153     var docReadyEvent, docReadyProcId, docReadyState = false;
6154     var resizeEvent, resizeTask, textEvent, textSize;
6155     var E = Roo.lib.Event;
6156     var D = Roo.lib.Dom;
6157
6158     
6159     
6160
6161     var fireDocReady = function(){
6162         if(!docReadyState){
6163             docReadyState = true;
6164             Roo.isReady = true;
6165             if(docReadyProcId){
6166                 clearInterval(docReadyProcId);
6167             }
6168             if(Roo.isGecko || Roo.isOpera) {
6169                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6170             }
6171             if(Roo.isIE){
6172                 var defer = document.getElementById("ie-deferred-loader");
6173                 if(defer){
6174                     defer.onreadystatechange = null;
6175                     defer.parentNode.removeChild(defer);
6176                 }
6177             }
6178             if(docReadyEvent){
6179                 docReadyEvent.fire();
6180                 docReadyEvent.clearListeners();
6181             }
6182         }
6183     };
6184     
6185     var initDocReady = function(){
6186         docReadyEvent = new Roo.util.Event();
6187         if(Roo.isGecko || Roo.isOpera) {
6188             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6189         }else if(Roo.isIE){
6190             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6191             var defer = document.getElementById("ie-deferred-loader");
6192             defer.onreadystatechange = function(){
6193                 if(this.readyState == "complete"){
6194                     fireDocReady();
6195                 }
6196             };
6197         }else if(Roo.isSafari){ 
6198             docReadyProcId = setInterval(function(){
6199                 var rs = document.readyState;
6200                 if(rs == "complete") {
6201                     fireDocReady();     
6202                  }
6203             }, 10);
6204         }
6205         // no matter what, make sure it fires on load
6206         E.on(window, "load", fireDocReady);
6207     };
6208
6209     var createBuffered = function(h, o){
6210         var task = new Roo.util.DelayedTask(h);
6211         return function(e){
6212             // create new event object impl so new events don't wipe out properties
6213             e = new Roo.EventObjectImpl(e);
6214             task.delay(o.buffer, h, null, [e]);
6215         };
6216     };
6217
6218     var createSingle = function(h, el, ename, fn){
6219         return function(e){
6220             Roo.EventManager.removeListener(el, ename, fn);
6221             h(e);
6222         };
6223     };
6224
6225     var createDelayed = function(h, o){
6226         return function(e){
6227             // create new event object impl so new events don't wipe out properties
6228             e = new Roo.EventObjectImpl(e);
6229             setTimeout(function(){
6230                 h(e);
6231             }, o.delay || 10);
6232         };
6233     };
6234     var transitionEndVal = false;
6235     
6236     var transitionEnd = function()
6237     {
6238         if (transitionEndVal) {
6239             return transitionEndVal;
6240         }
6241         var el = document.createElement('div');
6242
6243         var transEndEventNames = {
6244             WebkitTransition : 'webkitTransitionEnd',
6245             MozTransition    : 'transitionend',
6246             OTransition      : 'oTransitionEnd otransitionend',
6247             transition       : 'transitionend'
6248         };
6249     
6250         for (var name in transEndEventNames) {
6251             if (el.style[name] !== undefined) {
6252                 transitionEndVal = transEndEventNames[name];
6253                 return  transitionEndVal ;
6254             }
6255         }
6256     }
6257     
6258
6259     var listen = function(element, ename, opt, fn, scope){
6260         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6261         fn = fn || o.fn; scope = scope || o.scope;
6262         var el = Roo.getDom(element);
6263         
6264         
6265         if(!el){
6266             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6267         }
6268         
6269         if (ename == 'transitionend') {
6270             ename = transitionEnd();
6271         }
6272         var h = function(e){
6273             e = Roo.EventObject.setEvent(e);
6274             var t;
6275             if(o.delegate){
6276                 t = e.getTarget(o.delegate, el);
6277                 if(!t){
6278                     return;
6279                 }
6280             }else{
6281                 t = e.target;
6282             }
6283             if(o.stopEvent === true){
6284                 e.stopEvent();
6285             }
6286             if(o.preventDefault === true){
6287                e.preventDefault();
6288             }
6289             if(o.stopPropagation === true){
6290                 e.stopPropagation();
6291             }
6292
6293             if(o.normalized === false){
6294                 e = e.browserEvent;
6295             }
6296
6297             fn.call(scope || el, e, t, o);
6298         };
6299         if(o.delay){
6300             h = createDelayed(h, o);
6301         }
6302         if(o.single){
6303             h = createSingle(h, el, ename, fn);
6304         }
6305         if(o.buffer){
6306             h = createBuffered(h, o);
6307         }
6308         
6309         fn._handlers = fn._handlers || [];
6310         
6311         
6312         fn._handlers.push([Roo.id(el), ename, h]);
6313         
6314         
6315          
6316         E.on(el, ename, h);
6317         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6318             el.addEventListener("DOMMouseScroll", h, false);
6319             E.on(window, 'unload', function(){
6320                 el.removeEventListener("DOMMouseScroll", h, false);
6321             });
6322         }
6323         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6324             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6325         }
6326         return h;
6327     };
6328
6329     var stopListening = function(el, ename, fn){
6330         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6331         if(hds){
6332             for(var i = 0, len = hds.length; i < len; i++){
6333                 var h = hds[i];
6334                 if(h[0] == id && h[1] == ename){
6335                     hd = h[2];
6336                     hds.splice(i, 1);
6337                     break;
6338                 }
6339             }
6340         }
6341         E.un(el, ename, hd);
6342         el = Roo.getDom(el);
6343         if(ename == "mousewheel" && el.addEventListener){
6344             el.removeEventListener("DOMMouseScroll", hd, false);
6345         }
6346         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6347             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6348         }
6349     };
6350
6351     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6352     
6353     var pub = {
6354         
6355         
6356         /** 
6357          * Fix for doc tools
6358          * @scope Roo.EventManager
6359          */
6360         
6361         
6362         /** 
6363          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6364          * object with a Roo.EventObject
6365          * @param {Function} fn        The method the event invokes
6366          * @param {Object}   scope    An object that becomes the scope of the handler
6367          * @param {boolean}  override If true, the obj passed in becomes
6368          *                             the execution scope of the listener
6369          * @return {Function} The wrapped function
6370          * @deprecated
6371          */
6372         wrap : function(fn, scope, override){
6373             return function(e){
6374                 Roo.EventObject.setEvent(e);
6375                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6376             };
6377         },
6378         
6379         /**
6380      * Appends an event handler to an element (shorthand for addListener)
6381      * @param {String/HTMLElement}   element        The html element or id to assign the
6382      * @param {String}   eventName The type of event to listen for
6383      * @param {Function} handler The method the event invokes
6384      * @param {Object}   scope (optional) The scope in which to execute the handler
6385      * function. The handler function's "this" context.
6386      * @param {Object}   options (optional) An object containing handler configuration
6387      * properties. This may contain any of the following properties:<ul>
6388      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6389      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6390      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6391      * <li>preventDefault {Boolean} True to prevent the default action</li>
6392      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6393      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6394      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6395      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6396      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6397      * by the specified number of milliseconds. If the event fires again within that time, the original
6398      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6399      * </ul><br>
6400      * <p>
6401      * <b>Combining Options</b><br>
6402      * Using the options argument, it is possible to combine different types of listeners:<br>
6403      * <br>
6404      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6405      * Code:<pre><code>
6406 el.on('click', this.onClick, this, {
6407     single: true,
6408     delay: 100,
6409     stopEvent : true,
6410     forumId: 4
6411 });</code></pre>
6412      * <p>
6413      * <b>Attaching multiple handlers in 1 call</b><br>
6414       * The method also allows for a single argument to be passed which is a config object containing properties
6415      * which specify multiple handlers.
6416      * <p>
6417      * Code:<pre><code>
6418 el.on({
6419     'click' : {
6420         fn: this.onClick
6421         scope: this,
6422         delay: 100
6423     },
6424     'mouseover' : {
6425         fn: this.onMouseOver
6426         scope: this
6427     },
6428     'mouseout' : {
6429         fn: this.onMouseOut
6430         scope: this
6431     }
6432 });</code></pre>
6433      * <p>
6434      * Or a shorthand syntax:<br>
6435      * Code:<pre><code>
6436 el.on({
6437     'click' : this.onClick,
6438     'mouseover' : this.onMouseOver,
6439     'mouseout' : this.onMouseOut
6440     scope: this
6441 });</code></pre>
6442      */
6443         addListener : function(element, eventName, fn, scope, options){
6444             if(typeof eventName == "object"){
6445                 var o = eventName;
6446                 for(var e in o){
6447                     if(propRe.test(e)){
6448                         continue;
6449                     }
6450                     if(typeof o[e] == "function"){
6451                         // shared options
6452                         listen(element, e, o, o[e], o.scope);
6453                     }else{
6454                         // individual options
6455                         listen(element, e, o[e]);
6456                     }
6457                 }
6458                 return;
6459             }
6460             return listen(element, eventName, options, fn, scope);
6461         },
6462         
6463         /**
6464          * Removes an event handler
6465          *
6466          * @param {String/HTMLElement}   element        The id or html element to remove the 
6467          *                             event from
6468          * @param {String}   eventName     The type of event
6469          * @param {Function} fn
6470          * @return {Boolean} True if a listener was actually removed
6471          */
6472         removeListener : function(element, eventName, fn){
6473             return stopListening(element, eventName, fn);
6474         },
6475         
6476         /**
6477          * Fires when the document is ready (before onload and before images are loaded). Can be 
6478          * accessed shorthanded Roo.onReady().
6479          * @param {Function} fn        The method the event invokes
6480          * @param {Object}   scope    An  object that becomes the scope of the handler
6481          * @param {boolean}  options
6482          */
6483         onDocumentReady : function(fn, scope, options){
6484             if(docReadyState){ // if it already fired
6485                 docReadyEvent.addListener(fn, scope, options);
6486                 docReadyEvent.fire();
6487                 docReadyEvent.clearListeners();
6488                 return;
6489             }
6490             if(!docReadyEvent){
6491                 initDocReady();
6492             }
6493             docReadyEvent.addListener(fn, scope, options);
6494         },
6495         
6496         /**
6497          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6498          * @param {Function} fn        The method the event invokes
6499          * @param {Object}   scope    An object that becomes the scope of the handler
6500          * @param {boolean}  options
6501          */
6502         onWindowResize : function(fn, scope, options){
6503             if(!resizeEvent){
6504                 resizeEvent = new Roo.util.Event();
6505                 resizeTask = new Roo.util.DelayedTask(function(){
6506                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6507                 });
6508                 E.on(window, "resize", function(){
6509                     if(Roo.isIE){
6510                         resizeTask.delay(50);
6511                     }else{
6512                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6513                     }
6514                 });
6515             }
6516             resizeEvent.addListener(fn, scope, options);
6517         },
6518
6519         /**
6520          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6521          * @param {Function} fn        The method the event invokes
6522          * @param {Object}   scope    An object that becomes the scope of the handler
6523          * @param {boolean}  options
6524          */
6525         onTextResize : function(fn, scope, options){
6526             if(!textEvent){
6527                 textEvent = new Roo.util.Event();
6528                 var textEl = new Roo.Element(document.createElement('div'));
6529                 textEl.dom.className = 'x-text-resize';
6530                 textEl.dom.innerHTML = 'X';
6531                 textEl.appendTo(document.body);
6532                 textSize = textEl.dom.offsetHeight;
6533                 setInterval(function(){
6534                     if(textEl.dom.offsetHeight != textSize){
6535                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6536                     }
6537                 }, this.textResizeInterval);
6538             }
6539             textEvent.addListener(fn, scope, options);
6540         },
6541
6542         /**
6543          * Removes the passed window resize listener.
6544          * @param {Function} fn        The method the event invokes
6545          * @param {Object}   scope    The scope of handler
6546          */
6547         removeResizeListener : function(fn, scope){
6548             if(resizeEvent){
6549                 resizeEvent.removeListener(fn, scope);
6550             }
6551         },
6552
6553         // private
6554         fireResize : function(){
6555             if(resizeEvent){
6556                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6557             }   
6558         },
6559         /**
6560          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6561          */
6562         ieDeferSrc : false,
6563         /**
6564          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6565          */
6566         textResizeInterval : 50
6567     };
6568     
6569     /**
6570      * Fix for doc tools
6571      * @scopeAlias pub=Roo.EventManager
6572      */
6573     
6574      /**
6575      * Appends an event handler to an element (shorthand for addListener)
6576      * @param {String/HTMLElement}   element        The html element or id to assign the
6577      * @param {String}   eventName The type of event to listen for
6578      * @param {Function} handler The method the event invokes
6579      * @param {Object}   scope (optional) The scope in which to execute the handler
6580      * function. The handler function's "this" context.
6581      * @param {Object}   options (optional) An object containing handler configuration
6582      * properties. This may contain any of the following properties:<ul>
6583      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6584      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6585      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6586      * <li>preventDefault {Boolean} True to prevent the default action</li>
6587      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6588      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6589      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6590      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6591      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6592      * by the specified number of milliseconds. If the event fires again within that time, the original
6593      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6594      * </ul><br>
6595      * <p>
6596      * <b>Combining Options</b><br>
6597      * Using the options argument, it is possible to combine different types of listeners:<br>
6598      * <br>
6599      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6600      * Code:<pre><code>
6601 el.on('click', this.onClick, this, {
6602     single: true,
6603     delay: 100,
6604     stopEvent : true,
6605     forumId: 4
6606 });</code></pre>
6607      * <p>
6608      * <b>Attaching multiple handlers in 1 call</b><br>
6609       * The method also allows for a single argument to be passed which is a config object containing properties
6610      * which specify multiple handlers.
6611      * <p>
6612      * Code:<pre><code>
6613 el.on({
6614     'click' : {
6615         fn: this.onClick
6616         scope: this,
6617         delay: 100
6618     },
6619     'mouseover' : {
6620         fn: this.onMouseOver
6621         scope: this
6622     },
6623     'mouseout' : {
6624         fn: this.onMouseOut
6625         scope: this
6626     }
6627 });</code></pre>
6628      * <p>
6629      * Or a shorthand syntax:<br>
6630      * Code:<pre><code>
6631 el.on({
6632     'click' : this.onClick,
6633     'mouseover' : this.onMouseOver,
6634     'mouseout' : this.onMouseOut
6635     scope: this
6636 });</code></pre>
6637      */
6638     pub.on = pub.addListener;
6639     pub.un = pub.removeListener;
6640
6641     pub.stoppedMouseDownEvent = new Roo.util.Event();
6642     return pub;
6643 }();
6644 /**
6645   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6646   * @param {Function} fn        The method the event invokes
6647   * @param {Object}   scope    An  object that becomes the scope of the handler
6648   * @param {boolean}  override If true, the obj passed in becomes
6649   *                             the execution scope of the listener
6650   * @member Roo
6651   * @method onReady
6652  */
6653 Roo.onReady = Roo.EventManager.onDocumentReady;
6654
6655 Roo.onReady(function(){
6656     var bd = Roo.get(document.body);
6657     if(!bd){ return; }
6658
6659     var cls = [
6660             Roo.isIE ? "roo-ie"
6661             : Roo.isIE11 ? "roo-ie11"
6662             : Roo.isEdge ? "roo-edge"
6663             : Roo.isGecko ? "roo-gecko"
6664             : Roo.isOpera ? "roo-opera"
6665             : Roo.isSafari ? "roo-safari" : ""];
6666
6667     if(Roo.isMac){
6668         cls.push("roo-mac");
6669     }
6670     if(Roo.isLinux){
6671         cls.push("roo-linux");
6672     }
6673     if(Roo.isIOS){
6674         cls.push("roo-ios");
6675     }
6676     if(Roo.isTouch){
6677         cls.push("roo-touch");
6678     }
6679     if(Roo.isBorderBox){
6680         cls.push('roo-border-box');
6681     }
6682     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6683         var p = bd.dom.parentNode;
6684         if(p){
6685             p.className += ' roo-strict';
6686         }
6687     }
6688     bd.addClass(cls.join(' '));
6689 });
6690
6691 /**
6692  * @class Roo.EventObject
6693  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6694  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6695  * Example:
6696  * <pre><code>
6697  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6698     e.preventDefault();
6699     var target = e.getTarget();
6700     ...
6701  }
6702  var myDiv = Roo.get("myDiv");
6703  myDiv.on("click", handleClick);
6704  //or
6705  Roo.EventManager.on("myDiv", 'click', handleClick);
6706  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6707  </code></pre>
6708  * @singleton
6709  */
6710 Roo.EventObject = function(){
6711     
6712     var E = Roo.lib.Event;
6713     
6714     // safari keypress events for special keys return bad keycodes
6715     var safariKeys = {
6716         63234 : 37, // left
6717         63235 : 39, // right
6718         63232 : 38, // up
6719         63233 : 40, // down
6720         63276 : 33, // page up
6721         63277 : 34, // page down
6722         63272 : 46, // delete
6723         63273 : 36, // home
6724         63275 : 35  // end
6725     };
6726
6727     // normalize button clicks
6728     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6729                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6730
6731     Roo.EventObjectImpl = function(e){
6732         if(e){
6733             this.setEvent(e.browserEvent || e);
6734         }
6735     };
6736     Roo.EventObjectImpl.prototype = {
6737         /**
6738          * Used to fix doc tools.
6739          * @scope Roo.EventObject.prototype
6740          */
6741             
6742
6743         
6744         
6745         /** The normal browser event */
6746         browserEvent : null,
6747         /** The button pressed in a mouse event */
6748         button : -1,
6749         /** True if the shift key was down during the event */
6750         shiftKey : false,
6751         /** True if the control key was down during the event */
6752         ctrlKey : false,
6753         /** True if the alt key was down during the event */
6754         altKey : false,
6755
6756         /** Key constant 
6757         * @type Number */
6758         BACKSPACE : 8,
6759         /** Key constant 
6760         * @type Number */
6761         TAB : 9,
6762         /** Key constant 
6763         * @type Number */
6764         RETURN : 13,
6765         /** Key constant 
6766         * @type Number */
6767         ENTER : 13,
6768         /** Key constant 
6769         * @type Number */
6770         SHIFT : 16,
6771         /** Key constant 
6772         * @type Number */
6773         CONTROL : 17,
6774         /** Key constant 
6775         * @type Number */
6776         ESC : 27,
6777         /** Key constant 
6778         * @type Number */
6779         SPACE : 32,
6780         /** Key constant 
6781         * @type Number */
6782         PAGEUP : 33,
6783         /** Key constant 
6784         * @type Number */
6785         PAGEDOWN : 34,
6786         /** Key constant 
6787         * @type Number */
6788         END : 35,
6789         /** Key constant 
6790         * @type Number */
6791         HOME : 36,
6792         /** Key constant 
6793         * @type Number */
6794         LEFT : 37,
6795         /** Key constant 
6796         * @type Number */
6797         UP : 38,
6798         /** Key constant 
6799         * @type Number */
6800         RIGHT : 39,
6801         /** Key constant 
6802         * @type Number */
6803         DOWN : 40,
6804         /** Key constant 
6805         * @type Number */
6806         DELETE : 46,
6807         /** Key constant 
6808         * @type Number */
6809         F5 : 116,
6810
6811            /** @private */
6812         setEvent : function(e){
6813             if(e == this || (e && e.browserEvent)){ // already wrapped
6814                 return e;
6815             }
6816             this.browserEvent = e;
6817             if(e){
6818                 // normalize buttons
6819                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6820                 if(e.type == 'click' && this.button == -1){
6821                     this.button = 0;
6822                 }
6823                 this.type = e.type;
6824                 this.shiftKey = e.shiftKey;
6825                 // mac metaKey behaves like ctrlKey
6826                 this.ctrlKey = e.ctrlKey || e.metaKey;
6827                 this.altKey = e.altKey;
6828                 // in getKey these will be normalized for the mac
6829                 this.keyCode = e.keyCode;
6830                 // keyup warnings on firefox.
6831                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6832                 // cache the target for the delayed and or buffered events
6833                 this.target = E.getTarget(e);
6834                 // same for XY
6835                 this.xy = E.getXY(e);
6836             }else{
6837                 this.button = -1;
6838                 this.shiftKey = false;
6839                 this.ctrlKey = false;
6840                 this.altKey = false;
6841                 this.keyCode = 0;
6842                 this.charCode =0;
6843                 this.target = null;
6844                 this.xy = [0, 0];
6845             }
6846             return this;
6847         },
6848
6849         /**
6850          * Stop the event (preventDefault and stopPropagation)
6851          */
6852         stopEvent : function(){
6853             if(this.browserEvent){
6854                 if(this.browserEvent.type == 'mousedown'){
6855                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6856                 }
6857                 E.stopEvent(this.browserEvent);
6858             }
6859         },
6860
6861         /**
6862          * Prevents the browsers default handling of the event.
6863          */
6864         preventDefault : function(){
6865             if(this.browserEvent){
6866                 E.preventDefault(this.browserEvent);
6867             }
6868         },
6869
6870         /** @private */
6871         isNavKeyPress : function(){
6872             var k = this.keyCode;
6873             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6874             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6875         },
6876
6877         isSpecialKey : function(){
6878             var k = this.keyCode;
6879             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6880             (k == 16) || (k == 17) ||
6881             (k >= 18 && k <= 20) ||
6882             (k >= 33 && k <= 35) ||
6883             (k >= 36 && k <= 39) ||
6884             (k >= 44 && k <= 45);
6885         },
6886         /**
6887          * Cancels bubbling of the event.
6888          */
6889         stopPropagation : function(){
6890             if(this.browserEvent){
6891                 if(this.type == 'mousedown'){
6892                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6893                 }
6894                 E.stopPropagation(this.browserEvent);
6895             }
6896         },
6897
6898         /**
6899          * Gets the key code for the event.
6900          * @return {Number}
6901          */
6902         getCharCode : function(){
6903             return this.charCode || this.keyCode;
6904         },
6905
6906         /**
6907          * Returns a normalized keyCode for the event.
6908          * @return {Number} The key code
6909          */
6910         getKey : function(){
6911             var k = this.keyCode || this.charCode;
6912             return Roo.isSafari ? (safariKeys[k] || k) : k;
6913         },
6914
6915         /**
6916          * Gets the x coordinate of the event.
6917          * @return {Number}
6918          */
6919         getPageX : function(){
6920             return this.xy[0];
6921         },
6922
6923         /**
6924          * Gets the y coordinate of the event.
6925          * @return {Number}
6926          */
6927         getPageY : function(){
6928             return this.xy[1];
6929         },
6930
6931         /**
6932          * Gets the time of the event.
6933          * @return {Number}
6934          */
6935         getTime : function(){
6936             if(this.browserEvent){
6937                 return E.getTime(this.browserEvent);
6938             }
6939             return null;
6940         },
6941
6942         /**
6943          * Gets the page coordinates of the event.
6944          * @return {Array} The xy values like [x, y]
6945          */
6946         getXY : function(){
6947             return this.xy;
6948         },
6949
6950         /**
6951          * Gets the target for the event.
6952          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6953          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6954                 search as a number or element (defaults to 10 || document.body)
6955          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6956          * @return {HTMLelement}
6957          */
6958         getTarget : function(selector, maxDepth, returnEl){
6959             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6960         },
6961         /**
6962          * Gets the related target.
6963          * @return {HTMLElement}
6964          */
6965         getRelatedTarget : function(){
6966             if(this.browserEvent){
6967                 return E.getRelatedTarget(this.browserEvent);
6968             }
6969             return null;
6970         },
6971
6972         /**
6973          * Normalizes mouse wheel delta across browsers
6974          * @return {Number} The delta
6975          */
6976         getWheelDelta : function(){
6977             var e = this.browserEvent;
6978             var delta = 0;
6979             if(e.wheelDelta){ /* IE/Opera. */
6980                 delta = e.wheelDelta/120;
6981             }else if(e.detail){ /* Mozilla case. */
6982                 delta = -e.detail/3;
6983             }
6984             return delta;
6985         },
6986
6987         /**
6988          * Returns true if the control, meta, shift or alt key was pressed during this event.
6989          * @return {Boolean}
6990          */
6991         hasModifier : function(){
6992             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6993         },
6994
6995         /**
6996          * Returns true if the target of this event equals el or is a child of el
6997          * @param {String/HTMLElement/Element} el
6998          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6999          * @return {Boolean}
7000          */
7001         within : function(el, related){
7002             var t = this[related ? "getRelatedTarget" : "getTarget"]();
7003             return t && Roo.fly(el).contains(t);
7004         },
7005
7006         getPoint : function(){
7007             return new Roo.lib.Point(this.xy[0], this.xy[1]);
7008         }
7009     };
7010
7011     return new Roo.EventObjectImpl();
7012 }();
7013             
7014     /*
7015  * Based on:
7016  * Ext JS Library 1.1.1
7017  * Copyright(c) 2006-2007, Ext JS, LLC.
7018  *
7019  * Originally Released Under LGPL - original licence link has changed is not relivant.
7020  *
7021  * Fork - LGPL
7022  * <script type="text/javascript">
7023  */
7024
7025  
7026 // was in Composite Element!??!?!
7027  
7028 (function(){
7029     var D = Roo.lib.Dom;
7030     var E = Roo.lib.Event;
7031     var A = Roo.lib.Anim;
7032
7033     // local style camelizing for speed
7034     var propCache = {};
7035     var camelRe = /(-[a-z])/gi;
7036     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7037     var view = document.defaultView;
7038
7039 /**
7040  * @class Roo.Element
7041  * Represents an Element in the DOM.<br><br>
7042  * Usage:<br>
7043 <pre><code>
7044 var el = Roo.get("my-div");
7045
7046 // or with getEl
7047 var el = getEl("my-div");
7048
7049 // or with a DOM element
7050 var el = Roo.get(myDivElement);
7051 </code></pre>
7052  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7053  * each call instead of constructing a new one.<br><br>
7054  * <b>Animations</b><br />
7055  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7056  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7057 <pre>
7058 Option    Default   Description
7059 --------- --------  ---------------------------------------------
7060 duration  .35       The duration of the animation in seconds
7061 easing    easeOut   The YUI easing method
7062 callback  none      A function to execute when the anim completes
7063 scope     this      The scope (this) of the callback function
7064 </pre>
7065 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7066 * manipulate the animation. Here's an example:
7067 <pre><code>
7068 var el = Roo.get("my-div");
7069
7070 // no animation
7071 el.setWidth(100);
7072
7073 // default animation
7074 el.setWidth(100, true);
7075
7076 // animation with some options set
7077 el.setWidth(100, {
7078     duration: 1,
7079     callback: this.foo,
7080     scope: this
7081 });
7082
7083 // using the "anim" property to get the Anim object
7084 var opt = {
7085     duration: 1,
7086     callback: this.foo,
7087     scope: this
7088 };
7089 el.setWidth(100, opt);
7090 ...
7091 if(opt.anim.isAnimated()){
7092     opt.anim.stop();
7093 }
7094 </code></pre>
7095 * <b> Composite (Collections of) Elements</b><br />
7096  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7097  * @constructor Create a new Element directly.
7098  * @param {String/HTMLElement} element
7099  * @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).
7100  */
7101     Roo.Element = function(element, forceNew){
7102         var dom = typeof element == "string" ?
7103                 document.getElementById(element) : element;
7104         if(!dom){ // invalid id/element
7105             return null;
7106         }
7107         var id = dom.id;
7108         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7109             return Roo.Element.cache[id];
7110         }
7111
7112         /**
7113          * The DOM element
7114          * @type HTMLElement
7115          */
7116         this.dom = dom;
7117
7118         /**
7119          * The DOM element ID
7120          * @type String
7121          */
7122         this.id = id || Roo.id(dom);
7123     };
7124
7125     var El = Roo.Element;
7126
7127     El.prototype = {
7128         /**
7129          * The element's default display mode  (defaults to "")
7130          * @type String
7131          */
7132         originalDisplay : "",
7133
7134         visibilityMode : 1,
7135         /**
7136          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7137          * @type String
7138          */
7139         defaultUnit : "px",
7140         
7141         /**
7142          * Sets the element's visibility mode. When setVisible() is called it
7143          * will use this to determine whether to set the visibility or the display property.
7144          * @param visMode Element.VISIBILITY or Element.DISPLAY
7145          * @return {Roo.Element} this
7146          */
7147         setVisibilityMode : function(visMode){
7148             this.visibilityMode = visMode;
7149             return this;
7150         },
7151         /**
7152          * Convenience method for setVisibilityMode(Element.DISPLAY)
7153          * @param {String} display (optional) What to set display to when visible
7154          * @return {Roo.Element} this
7155          */
7156         enableDisplayMode : function(display){
7157             this.setVisibilityMode(El.DISPLAY);
7158             if(typeof display != "undefined") { this.originalDisplay = display; }
7159             return this;
7160         },
7161
7162         /**
7163          * 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)
7164          * @param {String} selector The simple selector to test
7165          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7166                 search as a number or element (defaults to 10 || document.body)
7167          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7168          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7169          */
7170         findParent : function(simpleSelector, maxDepth, returnEl){
7171             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7172             maxDepth = maxDepth || 50;
7173             if(typeof maxDepth != "number"){
7174                 stopEl = Roo.getDom(maxDepth);
7175                 maxDepth = 10;
7176             }
7177             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7178                 if(dq.is(p, simpleSelector)){
7179                     return returnEl ? Roo.get(p) : p;
7180                 }
7181                 depth++;
7182                 p = p.parentNode;
7183             }
7184             return null;
7185         },
7186
7187
7188         /**
7189          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7190          * @param {String} selector The simple selector to test
7191          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7192                 search as a number or element (defaults to 10 || document.body)
7193          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7194          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7195          */
7196         findParentNode : function(simpleSelector, maxDepth, returnEl){
7197             var p = Roo.fly(this.dom.parentNode, '_internal');
7198             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7199         },
7200         
7201         /**
7202          * Looks at  the scrollable parent element
7203          */
7204         findScrollableParent : function()
7205         {
7206             var overflowRegex = /(auto|scroll)/;
7207             
7208             if(this.getStyle('position') === 'fixed'){
7209                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7210             }
7211             
7212             var excludeStaticParent = this.getStyle('position') === "absolute";
7213             
7214             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7215                 
7216                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7217                     continue;
7218                 }
7219                 
7220                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7221                     return parent;
7222                 }
7223                 
7224                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7225                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7226                 }
7227             }
7228             
7229             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7230         },
7231
7232         /**
7233          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7234          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7235          * @param {String} selector The simple selector to test
7236          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7237                 search as a number or element (defaults to 10 || document.body)
7238          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7239          */
7240         up : function(simpleSelector, maxDepth){
7241             return this.findParentNode(simpleSelector, maxDepth, true);
7242         },
7243
7244
7245
7246         /**
7247          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7248          * @param {String} selector The simple selector to test
7249          * @return {Boolean} True if this element matches the selector, else false
7250          */
7251         is : function(simpleSelector){
7252             return Roo.DomQuery.is(this.dom, simpleSelector);
7253         },
7254
7255         /**
7256          * Perform animation on this element.
7257          * @param {Object} args The YUI animation control args
7258          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7259          * @param {Function} onComplete (optional) Function to call when animation completes
7260          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7261          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7262          * @return {Roo.Element} this
7263          */
7264         animate : function(args, duration, onComplete, easing, animType){
7265             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7266             return this;
7267         },
7268
7269         /*
7270          * @private Internal animation call
7271          */
7272         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7273             animType = animType || 'run';
7274             opt = opt || {};
7275             var anim = Roo.lib.Anim[animType](
7276                 this.dom, args,
7277                 (opt.duration || defaultDur) || .35,
7278                 (opt.easing || defaultEase) || 'easeOut',
7279                 function(){
7280                     Roo.callback(cb, this);
7281                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7282                 },
7283                 this
7284             );
7285             opt.anim = anim;
7286             return anim;
7287         },
7288
7289         // private legacy anim prep
7290         preanim : function(a, i){
7291             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7292         },
7293
7294         /**
7295          * Removes worthless text nodes
7296          * @param {Boolean} forceReclean (optional) By default the element
7297          * keeps track if it has been cleaned already so
7298          * you can call this over and over. However, if you update the element and
7299          * need to force a reclean, you can pass true.
7300          */
7301         clean : function(forceReclean){
7302             if(this.isCleaned && forceReclean !== true){
7303                 return this;
7304             }
7305             var ns = /\S/;
7306             var d = this.dom, n = d.firstChild, ni = -1;
7307             while(n){
7308                 var nx = n.nextSibling;
7309                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7310                     d.removeChild(n);
7311                 }else{
7312                     n.nodeIndex = ++ni;
7313                 }
7314                 n = nx;
7315             }
7316             this.isCleaned = true;
7317             return this;
7318         },
7319
7320         // private
7321         calcOffsetsTo : function(el){
7322             el = Roo.get(el);
7323             var d = el.dom;
7324             var restorePos = false;
7325             if(el.getStyle('position') == 'static'){
7326                 el.position('relative');
7327                 restorePos = true;
7328             }
7329             var x = 0, y =0;
7330             var op = this.dom;
7331             while(op && op != d && op.tagName != 'HTML'){
7332                 x+= op.offsetLeft;
7333                 y+= op.offsetTop;
7334                 op = op.offsetParent;
7335             }
7336             if(restorePos){
7337                 el.position('static');
7338             }
7339             return [x, y];
7340         },
7341
7342         /**
7343          * Scrolls this element into view within the passed container.
7344          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7345          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7346          * @return {Roo.Element} this
7347          */
7348         scrollIntoView : function(container, hscroll){
7349             var c = Roo.getDom(container) || document.body;
7350             var el = this.dom;
7351
7352             var o = this.calcOffsetsTo(c),
7353                 l = o[0],
7354                 t = o[1],
7355                 b = t+el.offsetHeight,
7356                 r = l+el.offsetWidth;
7357
7358             var ch = c.clientHeight;
7359             var ct = parseInt(c.scrollTop, 10);
7360             var cl = parseInt(c.scrollLeft, 10);
7361             var cb = ct + ch;
7362             var cr = cl + c.clientWidth;
7363
7364             if(t < ct){
7365                 c.scrollTop = t;
7366             }else if(b > cb){
7367                 c.scrollTop = b-ch;
7368             }
7369
7370             if(hscroll !== false){
7371                 if(l < cl){
7372                     c.scrollLeft = l;
7373                 }else if(r > cr){
7374                     c.scrollLeft = r-c.clientWidth;
7375                 }
7376             }
7377             return this;
7378         },
7379
7380         // private
7381         scrollChildIntoView : function(child, hscroll){
7382             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7383         },
7384
7385         /**
7386          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7387          * the new height may not be available immediately.
7388          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7389          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7390          * @param {Function} onComplete (optional) Function to call when animation completes
7391          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7392          * @return {Roo.Element} this
7393          */
7394         autoHeight : function(animate, duration, onComplete, easing){
7395             var oldHeight = this.getHeight();
7396             this.clip();
7397             this.setHeight(1); // force clipping
7398             setTimeout(function(){
7399                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7400                 if(!animate){
7401                     this.setHeight(height);
7402                     this.unclip();
7403                     if(typeof onComplete == "function"){
7404                         onComplete();
7405                     }
7406                 }else{
7407                     this.setHeight(oldHeight); // restore original height
7408                     this.setHeight(height, animate, duration, function(){
7409                         this.unclip();
7410                         if(typeof onComplete == "function") { onComplete(); }
7411                     }.createDelegate(this), easing);
7412                 }
7413             }.createDelegate(this), 0);
7414             return this;
7415         },
7416
7417         /**
7418          * Returns true if this element is an ancestor of the passed element
7419          * @param {HTMLElement/String} el The element to check
7420          * @return {Boolean} True if this element is an ancestor of el, else false
7421          */
7422         contains : function(el){
7423             if(!el){return false;}
7424             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7425         },
7426
7427         /**
7428          * Checks whether the element is currently visible using both visibility and display properties.
7429          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7430          * @return {Boolean} True if the element is currently visible, else false
7431          */
7432         isVisible : function(deep) {
7433             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7434             if(deep !== true || !vis){
7435                 return vis;
7436             }
7437             var p = this.dom.parentNode;
7438             while(p && p.tagName.toLowerCase() != "body"){
7439                 if(!Roo.fly(p, '_isVisible').isVisible()){
7440                     return false;
7441                 }
7442                 p = p.parentNode;
7443             }
7444             return true;
7445         },
7446
7447         /**
7448          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7449          * @param {String} selector The CSS selector
7450          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7451          * @return {CompositeElement/CompositeElementLite} The composite element
7452          */
7453         select : function(selector, unique){
7454             return El.select(selector, unique, this.dom);
7455         },
7456
7457         /**
7458          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7459          * @param {String} selector The CSS selector
7460          * @return {Array} An array of the matched nodes
7461          */
7462         query : function(selector, unique){
7463             return Roo.DomQuery.select(selector, this.dom);
7464         },
7465
7466         /**
7467          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7468          * @param {String} selector The CSS selector
7469          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7470          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7471          */
7472         child : function(selector, returnDom){
7473             var n = Roo.DomQuery.selectNode(selector, this.dom);
7474             return returnDom ? n : Roo.get(n);
7475         },
7476
7477         /**
7478          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7479          * @param {String} selector The CSS selector
7480          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7481          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7482          */
7483         down : function(selector, returnDom){
7484             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7485             return returnDom ? n : Roo.get(n);
7486         },
7487
7488         /**
7489          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7490          * @param {String} group The group the DD object is member of
7491          * @param {Object} config The DD config object
7492          * @param {Object} overrides An object containing methods to override/implement on the DD object
7493          * @return {Roo.dd.DD} The DD object
7494          */
7495         initDD : function(group, config, overrides){
7496             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7497             return Roo.apply(dd, overrides);
7498         },
7499
7500         /**
7501          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7502          * @param {String} group The group the DDProxy object is member of
7503          * @param {Object} config The DDProxy config object
7504          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7505          * @return {Roo.dd.DDProxy} The DDProxy object
7506          */
7507         initDDProxy : function(group, config, overrides){
7508             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7509             return Roo.apply(dd, overrides);
7510         },
7511
7512         /**
7513          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7514          * @param {String} group The group the DDTarget object is member of
7515          * @param {Object} config The DDTarget config object
7516          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7517          * @return {Roo.dd.DDTarget} The DDTarget object
7518          */
7519         initDDTarget : function(group, config, overrides){
7520             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7521             return Roo.apply(dd, overrides);
7522         },
7523
7524         /**
7525          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7526          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7527          * @param {Boolean} visible Whether the element is visible
7528          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7529          * @return {Roo.Element} this
7530          */
7531          setVisible : function(visible, animate){
7532             if(!animate || !A){
7533                 if(this.visibilityMode == El.DISPLAY){
7534                     this.setDisplayed(visible);
7535                 }else{
7536                     this.fixDisplay();
7537                     this.dom.style.visibility = visible ? "visible" : "hidden";
7538                 }
7539             }else{
7540                 // closure for composites
7541                 var dom = this.dom;
7542                 var visMode = this.visibilityMode;
7543                 if(visible){
7544                     this.setOpacity(.01);
7545                     this.setVisible(true);
7546                 }
7547                 this.anim({opacity: { to: (visible?1:0) }},
7548                       this.preanim(arguments, 1),
7549                       null, .35, 'easeIn', function(){
7550                          if(!visible){
7551                              if(visMode == El.DISPLAY){
7552                                  dom.style.display = "none";
7553                              }else{
7554                                  dom.style.visibility = "hidden";
7555                              }
7556                              Roo.get(dom).setOpacity(1);
7557                          }
7558                      });
7559             }
7560             return this;
7561         },
7562
7563         /**
7564          * Returns true if display is not "none"
7565          * @return {Boolean}
7566          */
7567         isDisplayed : function() {
7568             return this.getStyle("display") != "none";
7569         },
7570
7571         /**
7572          * Toggles the element's visibility or display, depending on visibility mode.
7573          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7574          * @return {Roo.Element} this
7575          */
7576         toggle : function(animate){
7577             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7578             return this;
7579         },
7580
7581         /**
7582          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7583          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7584          * @return {Roo.Element} this
7585          */
7586         setDisplayed : function(value) {
7587             if(typeof value == "boolean"){
7588                value = value ? this.originalDisplay : "none";
7589             }
7590             this.setStyle("display", value);
7591             return this;
7592         },
7593
7594         /**
7595          * Tries to focus the element. Any exceptions are caught and ignored.
7596          * @return {Roo.Element} this
7597          */
7598         focus : function() {
7599             try{
7600                 this.dom.focus();
7601             }catch(e){}
7602             return this;
7603         },
7604
7605         /**
7606          * Tries to blur the element. Any exceptions are caught and ignored.
7607          * @return {Roo.Element} this
7608          */
7609         blur : function() {
7610             try{
7611                 this.dom.blur();
7612             }catch(e){}
7613             return this;
7614         },
7615
7616         /**
7617          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7618          * @param {String/Array} className The CSS class to add, or an array of classes
7619          * @return {Roo.Element} this
7620          */
7621         addClass : function(className){
7622             if(className instanceof Array){
7623                 for(var i = 0, len = className.length; i < len; i++) {
7624                     this.addClass(className[i]);
7625                 }
7626             }else{
7627                 if(className && !this.hasClass(className)){
7628                     this.dom.className = this.dom.className + " " + className;
7629                 }
7630             }
7631             return this;
7632         },
7633
7634         /**
7635          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7636          * @param {String/Array} className The CSS class to add, or an array of classes
7637          * @return {Roo.Element} this
7638          */
7639         radioClass : function(className){
7640             var siblings = this.dom.parentNode.childNodes;
7641             for(var i = 0; i < siblings.length; i++) {
7642                 var s = siblings[i];
7643                 if(s.nodeType == 1){
7644                     Roo.get(s).removeClass(className);
7645                 }
7646             }
7647             this.addClass(className);
7648             return this;
7649         },
7650
7651         /**
7652          * Removes one or more CSS classes from the element.
7653          * @param {String/Array} className The CSS class to remove, or an array of classes
7654          * @return {Roo.Element} this
7655          */
7656         removeClass : function(className){
7657             if(!className || !this.dom.className){
7658                 return this;
7659             }
7660             if(className instanceof Array){
7661                 for(var i = 0, len = className.length; i < len; i++) {
7662                     this.removeClass(className[i]);
7663                 }
7664             }else{
7665                 if(this.hasClass(className)){
7666                     var re = this.classReCache[className];
7667                     if (!re) {
7668                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7669                        this.classReCache[className] = re;
7670                     }
7671                     this.dom.className =
7672                         this.dom.className.replace(re, " ");
7673                 }
7674             }
7675             return this;
7676         },
7677
7678         // private
7679         classReCache: {},
7680
7681         /**
7682          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7683          * @param {String} className The CSS class to toggle
7684          * @return {Roo.Element} this
7685          */
7686         toggleClass : function(className){
7687             if(this.hasClass(className)){
7688                 this.removeClass(className);
7689             }else{
7690                 this.addClass(className);
7691             }
7692             return this;
7693         },
7694
7695         /**
7696          * Checks if the specified CSS class exists on this element's DOM node.
7697          * @param {String} className The CSS class to check for
7698          * @return {Boolean} True if the class exists, else false
7699          */
7700         hasClass : function(className){
7701             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7702         },
7703
7704         /**
7705          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7706          * @param {String} oldClassName The CSS class to replace
7707          * @param {String} newClassName The replacement CSS class
7708          * @return {Roo.Element} this
7709          */
7710         replaceClass : function(oldClassName, newClassName){
7711             this.removeClass(oldClassName);
7712             this.addClass(newClassName);
7713             return this;
7714         },
7715
7716         /**
7717          * Returns an object with properties matching the styles requested.
7718          * For example, el.getStyles('color', 'font-size', 'width') might return
7719          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7720          * @param {String} style1 A style name
7721          * @param {String} style2 A style name
7722          * @param {String} etc.
7723          * @return {Object} The style object
7724          */
7725         getStyles : function(){
7726             var a = arguments, len = a.length, r = {};
7727             for(var i = 0; i < len; i++){
7728                 r[a[i]] = this.getStyle(a[i]);
7729             }
7730             return r;
7731         },
7732
7733         /**
7734          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7735          * @param {String} property The style property whose value is returned.
7736          * @return {String} The current value of the style property for this element.
7737          */
7738         getStyle : function(){
7739             return view && view.getComputedStyle ?
7740                 function(prop){
7741                     var el = this.dom, v, cs, camel;
7742                     if(prop == 'float'){
7743                         prop = "cssFloat";
7744                     }
7745                     if(el.style && (v = el.style[prop])){
7746                         return v;
7747                     }
7748                     if(cs = view.getComputedStyle(el, "")){
7749                         if(!(camel = propCache[prop])){
7750                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7751                         }
7752                         return cs[camel];
7753                     }
7754                     return null;
7755                 } :
7756                 function(prop){
7757                     var el = this.dom, v, cs, camel;
7758                     if(prop == 'opacity'){
7759                         if(typeof el.style.filter == 'string'){
7760                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7761                             if(m){
7762                                 var fv = parseFloat(m[1]);
7763                                 if(!isNaN(fv)){
7764                                     return fv ? fv / 100 : 0;
7765                                 }
7766                             }
7767                         }
7768                         return 1;
7769                     }else if(prop == 'float'){
7770                         prop = "styleFloat";
7771                     }
7772                     if(!(camel = propCache[prop])){
7773                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7774                     }
7775                     if(v = el.style[camel]){
7776                         return v;
7777                     }
7778                     if(cs = el.currentStyle){
7779                         return cs[camel];
7780                     }
7781                     return null;
7782                 };
7783         }(),
7784
7785         /**
7786          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7787          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7788          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7789          * @return {Roo.Element} this
7790          */
7791         setStyle : function(prop, value){
7792             if(typeof prop == "string"){
7793                 
7794                 if (prop == 'float') {
7795                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7796                     return this;
7797                 }
7798                 
7799                 var camel;
7800                 if(!(camel = propCache[prop])){
7801                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7802                 }
7803                 
7804                 if(camel == 'opacity') {
7805                     this.setOpacity(value);
7806                 }else{
7807                     this.dom.style[camel] = value;
7808                 }
7809             }else{
7810                 for(var style in prop){
7811                     if(typeof prop[style] != "function"){
7812                        this.setStyle(style, prop[style]);
7813                     }
7814                 }
7815             }
7816             return this;
7817         },
7818
7819         /**
7820          * More flexible version of {@link #setStyle} for setting style properties.
7821          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7822          * a function which returns such a specification.
7823          * @return {Roo.Element} this
7824          */
7825         applyStyles : function(style){
7826             Roo.DomHelper.applyStyles(this.dom, style);
7827             return this;
7828         },
7829
7830         /**
7831           * 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).
7832           * @return {Number} The X position of the element
7833           */
7834         getX : function(){
7835             return D.getX(this.dom);
7836         },
7837
7838         /**
7839           * 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).
7840           * @return {Number} The Y position of the element
7841           */
7842         getY : function(){
7843             return D.getY(this.dom);
7844         },
7845
7846         /**
7847           * 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).
7848           * @return {Array} The XY position of the element
7849           */
7850         getXY : function(){
7851             return D.getXY(this.dom);
7852         },
7853
7854         /**
7855          * 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).
7856          * @param {Number} The X position of the element
7857          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7858          * @return {Roo.Element} this
7859          */
7860         setX : function(x, animate){
7861             if(!animate || !A){
7862                 D.setX(this.dom, x);
7863             }else{
7864                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7865             }
7866             return this;
7867         },
7868
7869         /**
7870          * 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).
7871          * @param {Number} The Y position of the element
7872          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7873          * @return {Roo.Element} this
7874          */
7875         setY : function(y, animate){
7876             if(!animate || !A){
7877                 D.setY(this.dom, y);
7878             }else{
7879                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7880             }
7881             return this;
7882         },
7883
7884         /**
7885          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7886          * @param {String} left The left CSS property value
7887          * @return {Roo.Element} this
7888          */
7889         setLeft : function(left){
7890             this.setStyle("left", this.addUnits(left));
7891             return this;
7892         },
7893
7894         /**
7895          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7896          * @param {String} top The top CSS property value
7897          * @return {Roo.Element} this
7898          */
7899         setTop : function(top){
7900             this.setStyle("top", this.addUnits(top));
7901             return this;
7902         },
7903
7904         /**
7905          * Sets the element's CSS right style.
7906          * @param {String} right The right CSS property value
7907          * @return {Roo.Element} this
7908          */
7909         setRight : function(right){
7910             this.setStyle("right", this.addUnits(right));
7911             return this;
7912         },
7913
7914         /**
7915          * Sets the element's CSS bottom style.
7916          * @param {String} bottom The bottom CSS property value
7917          * @return {Roo.Element} this
7918          */
7919         setBottom : function(bottom){
7920             this.setStyle("bottom", this.addUnits(bottom));
7921             return this;
7922         },
7923
7924         /**
7925          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7926          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7927          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7928          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7929          * @return {Roo.Element} this
7930          */
7931         setXY : function(pos, animate){
7932             if(!animate || !A){
7933                 D.setXY(this.dom, pos);
7934             }else{
7935                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7936             }
7937             return this;
7938         },
7939
7940         /**
7941          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7942          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7943          * @param {Number} x X value for new position (coordinates are page-based)
7944          * @param {Number} y Y value for new position (coordinates are page-based)
7945          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7946          * @return {Roo.Element} this
7947          */
7948         setLocation : function(x, y, animate){
7949             this.setXY([x, y], this.preanim(arguments, 2));
7950             return this;
7951         },
7952
7953         /**
7954          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7955          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7956          * @param {Number} x X value for new position (coordinates are page-based)
7957          * @param {Number} y Y value for new position (coordinates are page-based)
7958          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7959          * @return {Roo.Element} this
7960          */
7961         moveTo : function(x, y, animate){
7962             this.setXY([x, y], this.preanim(arguments, 2));
7963             return this;
7964         },
7965
7966         /**
7967          * Returns the region of the given element.
7968          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7969          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7970          */
7971         getRegion : function(){
7972             return D.getRegion(this.dom);
7973         },
7974
7975         /**
7976          * Returns the offset height of the element
7977          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7978          * @return {Number} The element's height
7979          */
7980         getHeight : function(contentHeight){
7981             var h = this.dom.offsetHeight || 0;
7982             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7983         },
7984
7985         /**
7986          * Returns the offset width of the element
7987          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7988          * @return {Number} The element's width
7989          */
7990         getWidth : function(contentWidth){
7991             var w = this.dom.offsetWidth || 0;
7992             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7993         },
7994
7995         /**
7996          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7997          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7998          * if a height has not been set using CSS.
7999          * @return {Number}
8000          */
8001         getComputedHeight : function(){
8002             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8003             if(!h){
8004                 h = parseInt(this.getStyle('height'), 10) || 0;
8005                 if(!this.isBorderBox()){
8006                     h += this.getFrameWidth('tb');
8007                 }
8008             }
8009             return h;
8010         },
8011
8012         /**
8013          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8014          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8015          * if a width has not been set using CSS.
8016          * @return {Number}
8017          */
8018         getComputedWidth : function(){
8019             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8020             if(!w){
8021                 w = parseInt(this.getStyle('width'), 10) || 0;
8022                 if(!this.isBorderBox()){
8023                     w += this.getFrameWidth('lr');
8024                 }
8025             }
8026             return w;
8027         },
8028
8029         /**
8030          * Returns the size of the element.
8031          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8032          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8033          */
8034         getSize : function(contentSize){
8035             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8036         },
8037
8038         /**
8039          * Returns the width and height of the viewport.
8040          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8041          */
8042         getViewSize : function(){
8043             var d = this.dom, doc = document, aw = 0, ah = 0;
8044             if(d == doc || d == doc.body){
8045                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8046             }else{
8047                 return {
8048                     width : d.clientWidth,
8049                     height: d.clientHeight
8050                 };
8051             }
8052         },
8053
8054         /**
8055          * Returns the value of the "value" attribute
8056          * @param {Boolean} asNumber true to parse the value as a number
8057          * @return {String/Number}
8058          */
8059         getValue : function(asNumber){
8060             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8061         },
8062
8063         // private
8064         adjustWidth : function(width){
8065             if(typeof width == "number"){
8066                 if(this.autoBoxAdjust && !this.isBorderBox()){
8067                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8068                 }
8069                 if(width < 0){
8070                     width = 0;
8071                 }
8072             }
8073             return width;
8074         },
8075
8076         // private
8077         adjustHeight : function(height){
8078             if(typeof height == "number"){
8079                if(this.autoBoxAdjust && !this.isBorderBox()){
8080                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8081                }
8082                if(height < 0){
8083                    height = 0;
8084                }
8085             }
8086             return height;
8087         },
8088
8089         /**
8090          * Set the width of the element
8091          * @param {Number} width The new width
8092          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8093          * @return {Roo.Element} this
8094          */
8095         setWidth : function(width, animate){
8096             width = this.adjustWidth(width);
8097             if(!animate || !A){
8098                 this.dom.style.width = this.addUnits(width);
8099             }else{
8100                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8101             }
8102             return this;
8103         },
8104
8105         /**
8106          * Set the height of the element
8107          * @param {Number} height The new height
8108          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8109          * @return {Roo.Element} this
8110          */
8111          setHeight : function(height, animate){
8112             height = this.adjustHeight(height);
8113             if(!animate || !A){
8114                 this.dom.style.height = this.addUnits(height);
8115             }else{
8116                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8117             }
8118             return this;
8119         },
8120
8121         /**
8122          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8123          * @param {Number} width The new width
8124          * @param {Number} height The new height
8125          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8126          * @return {Roo.Element} this
8127          */
8128          setSize : function(width, height, animate){
8129             if(typeof width == "object"){ // in case of object from getSize()
8130                 height = width.height; width = width.width;
8131             }
8132             width = this.adjustWidth(width); height = this.adjustHeight(height);
8133             if(!animate || !A){
8134                 this.dom.style.width = this.addUnits(width);
8135                 this.dom.style.height = this.addUnits(height);
8136             }else{
8137                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8138             }
8139             return this;
8140         },
8141
8142         /**
8143          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8144          * @param {Number} x X value for new position (coordinates are page-based)
8145          * @param {Number} y Y value for new position (coordinates are page-based)
8146          * @param {Number} width The new width
8147          * @param {Number} height The new height
8148          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8149          * @return {Roo.Element} this
8150          */
8151         setBounds : function(x, y, width, height, animate){
8152             if(!animate || !A){
8153                 this.setSize(width, height);
8154                 this.setLocation(x, y);
8155             }else{
8156                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8157                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8158                               this.preanim(arguments, 4), 'motion');
8159             }
8160             return this;
8161         },
8162
8163         /**
8164          * 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.
8165          * @param {Roo.lib.Region} region The region to fill
8166          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8167          * @return {Roo.Element} this
8168          */
8169         setRegion : function(region, animate){
8170             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8171             return this;
8172         },
8173
8174         /**
8175          * Appends an event handler
8176          *
8177          * @param {String}   eventName     The type of event to append
8178          * @param {Function} fn        The method the event invokes
8179          * @param {Object} scope       (optional) The scope (this object) of the fn
8180          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8181          */
8182         addListener : function(eventName, fn, scope, options){
8183             if (this.dom) {
8184                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8185             }
8186         },
8187
8188         /**
8189          * Removes an event handler from this element
8190          * @param {String} eventName the type of event to remove
8191          * @param {Function} fn the method the event invokes
8192          * @return {Roo.Element} this
8193          */
8194         removeListener : function(eventName, fn){
8195             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8196             return this;
8197         },
8198
8199         /**
8200          * Removes all previous added listeners from this element
8201          * @return {Roo.Element} this
8202          */
8203         removeAllListeners : function(){
8204             E.purgeElement(this.dom);
8205             return this;
8206         },
8207
8208         relayEvent : function(eventName, observable){
8209             this.on(eventName, function(e){
8210                 observable.fireEvent(eventName, e);
8211             });
8212         },
8213
8214         /**
8215          * Set the opacity of the element
8216          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8217          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8218          * @return {Roo.Element} this
8219          */
8220          setOpacity : function(opacity, animate){
8221             if(!animate || !A){
8222                 var s = this.dom.style;
8223                 if(Roo.isIE){
8224                     s.zoom = 1;
8225                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8226                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8227                 }else{
8228                     s.opacity = opacity;
8229                 }
8230             }else{
8231                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8232             }
8233             return this;
8234         },
8235
8236         /**
8237          * Gets the left X coordinate
8238          * @param {Boolean} local True to get the local css position instead of page coordinate
8239          * @return {Number}
8240          */
8241         getLeft : function(local){
8242             if(!local){
8243                 return this.getX();
8244             }else{
8245                 return parseInt(this.getStyle("left"), 10) || 0;
8246             }
8247         },
8248
8249         /**
8250          * Gets the right X coordinate of the element (element X position + element width)
8251          * @param {Boolean} local True to get the local css position instead of page coordinate
8252          * @return {Number}
8253          */
8254         getRight : function(local){
8255             if(!local){
8256                 return this.getX() + this.getWidth();
8257             }else{
8258                 return (this.getLeft(true) + this.getWidth()) || 0;
8259             }
8260         },
8261
8262         /**
8263          * Gets the top Y coordinate
8264          * @param {Boolean} local True to get the local css position instead of page coordinate
8265          * @return {Number}
8266          */
8267         getTop : function(local) {
8268             if(!local){
8269                 return this.getY();
8270             }else{
8271                 return parseInt(this.getStyle("top"), 10) || 0;
8272             }
8273         },
8274
8275         /**
8276          * Gets the bottom Y coordinate of the element (element Y position + element height)
8277          * @param {Boolean} local True to get the local css position instead of page coordinate
8278          * @return {Number}
8279          */
8280         getBottom : function(local){
8281             if(!local){
8282                 return this.getY() + this.getHeight();
8283             }else{
8284                 return (this.getTop(true) + this.getHeight()) || 0;
8285             }
8286         },
8287
8288         /**
8289         * Initializes positioning on this element. If a desired position is not passed, it will make the
8290         * the element positioned relative IF it is not already positioned.
8291         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8292         * @param {Number} zIndex (optional) The zIndex to apply
8293         * @param {Number} x (optional) Set the page X position
8294         * @param {Number} y (optional) Set the page Y position
8295         */
8296         position : function(pos, zIndex, x, y){
8297             if(!pos){
8298                if(this.getStyle('position') == 'static'){
8299                    this.setStyle('position', 'relative');
8300                }
8301             }else{
8302                 this.setStyle("position", pos);
8303             }
8304             if(zIndex){
8305                 this.setStyle("z-index", zIndex);
8306             }
8307             if(x !== undefined && y !== undefined){
8308                 this.setXY([x, y]);
8309             }else if(x !== undefined){
8310                 this.setX(x);
8311             }else if(y !== undefined){
8312                 this.setY(y);
8313             }
8314         },
8315
8316         /**
8317         * Clear positioning back to the default when the document was loaded
8318         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8319         * @return {Roo.Element} this
8320          */
8321         clearPositioning : function(value){
8322             value = value ||'';
8323             this.setStyle({
8324                 "left": value,
8325                 "right": value,
8326                 "top": value,
8327                 "bottom": value,
8328                 "z-index": "",
8329                 "position" : "static"
8330             });
8331             return this;
8332         },
8333
8334         /**
8335         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8336         * snapshot before performing an update and then restoring the element.
8337         * @return {Object}
8338         */
8339         getPositioning : function(){
8340             var l = this.getStyle("left");
8341             var t = this.getStyle("top");
8342             return {
8343                 "position" : this.getStyle("position"),
8344                 "left" : l,
8345                 "right" : l ? "" : this.getStyle("right"),
8346                 "top" : t,
8347                 "bottom" : t ? "" : this.getStyle("bottom"),
8348                 "z-index" : this.getStyle("z-index")
8349             };
8350         },
8351
8352         /**
8353          * Gets the width of the border(s) for the specified side(s)
8354          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8355          * passing lr would get the border (l)eft width + the border (r)ight width.
8356          * @return {Number} The width of the sides passed added together
8357          */
8358         getBorderWidth : function(side){
8359             return this.addStyles(side, El.borders);
8360         },
8361
8362         /**
8363          * Gets the width of the padding(s) for the specified side(s)
8364          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8365          * passing lr would get the padding (l)eft + the padding (r)ight.
8366          * @return {Number} The padding of the sides passed added together
8367          */
8368         getPadding : function(side){
8369             return this.addStyles(side, El.paddings);
8370         },
8371
8372         /**
8373         * Set positioning with an object returned by getPositioning().
8374         * @param {Object} posCfg
8375         * @return {Roo.Element} this
8376          */
8377         setPositioning : function(pc){
8378             this.applyStyles(pc);
8379             if(pc.right == "auto"){
8380                 this.dom.style.right = "";
8381             }
8382             if(pc.bottom == "auto"){
8383                 this.dom.style.bottom = "";
8384             }
8385             return this;
8386         },
8387
8388         // private
8389         fixDisplay : function(){
8390             if(this.getStyle("display") == "none"){
8391                 this.setStyle("visibility", "hidden");
8392                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8393                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8394                     this.setStyle("display", "block");
8395                 }
8396             }
8397         },
8398
8399         /**
8400          * Quick set left and top adding default units
8401          * @param {String} left The left CSS property value
8402          * @param {String} top The top CSS property value
8403          * @return {Roo.Element} this
8404          */
8405          setLeftTop : function(left, top){
8406             this.dom.style.left = this.addUnits(left);
8407             this.dom.style.top = this.addUnits(top);
8408             return this;
8409         },
8410
8411         /**
8412          * Move this element relative to its current position.
8413          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8414          * @param {Number} distance How far to move the element in pixels
8415          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8416          * @return {Roo.Element} this
8417          */
8418          move : function(direction, distance, animate){
8419             var xy = this.getXY();
8420             direction = direction.toLowerCase();
8421             switch(direction){
8422                 case "l":
8423                 case "left":
8424                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8425                     break;
8426                case "r":
8427                case "right":
8428                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8429                     break;
8430                case "t":
8431                case "top":
8432                case "up":
8433                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8434                     break;
8435                case "b":
8436                case "bottom":
8437                case "down":
8438                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8439                     break;
8440             }
8441             return this;
8442         },
8443
8444         /**
8445          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8446          * @return {Roo.Element} this
8447          */
8448         clip : function(){
8449             if(!this.isClipped){
8450                this.isClipped = true;
8451                this.originalClip = {
8452                    "o": this.getStyle("overflow"),
8453                    "x": this.getStyle("overflow-x"),
8454                    "y": this.getStyle("overflow-y")
8455                };
8456                this.setStyle("overflow", "hidden");
8457                this.setStyle("overflow-x", "hidden");
8458                this.setStyle("overflow-y", "hidden");
8459             }
8460             return this;
8461         },
8462
8463         /**
8464          *  Return clipping (overflow) to original clipping before clip() was called
8465          * @return {Roo.Element} this
8466          */
8467         unclip : function(){
8468             if(this.isClipped){
8469                 this.isClipped = false;
8470                 var o = this.originalClip;
8471                 if(o.o){this.setStyle("overflow", o.o);}
8472                 if(o.x){this.setStyle("overflow-x", o.x);}
8473                 if(o.y){this.setStyle("overflow-y", o.y);}
8474             }
8475             return this;
8476         },
8477
8478
8479         /**
8480          * Gets the x,y coordinates specified by the anchor position on the element.
8481          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8482          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8483          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8484          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8485          * @return {Array} [x, y] An array containing the element's x and y coordinates
8486          */
8487         getAnchorXY : function(anchor, local, s){
8488             //Passing a different size is useful for pre-calculating anchors,
8489             //especially for anchored animations that change the el size.
8490
8491             var w, h, vp = false;
8492             if(!s){
8493                 var d = this.dom;
8494                 if(d == document.body || d == document){
8495                     vp = true;
8496                     w = D.getViewWidth(); h = D.getViewHeight();
8497                 }else{
8498                     w = this.getWidth(); h = this.getHeight();
8499                 }
8500             }else{
8501                 w = s.width;  h = s.height;
8502             }
8503             var x = 0, y = 0, r = Math.round;
8504             switch((anchor || "tl").toLowerCase()){
8505                 case "c":
8506                     x = r(w*.5);
8507                     y = r(h*.5);
8508                 break;
8509                 case "t":
8510                     x = r(w*.5);
8511                     y = 0;
8512                 break;
8513                 case "l":
8514                     x = 0;
8515                     y = r(h*.5);
8516                 break;
8517                 case "r":
8518                     x = w;
8519                     y = r(h*.5);
8520                 break;
8521                 case "b":
8522                     x = r(w*.5);
8523                     y = h;
8524                 break;
8525                 case "tl":
8526                     x = 0;
8527                     y = 0;
8528                 break;
8529                 case "bl":
8530                     x = 0;
8531                     y = h;
8532                 break;
8533                 case "br":
8534                     x = w;
8535                     y = h;
8536                 break;
8537                 case "tr":
8538                     x = w;
8539                     y = 0;
8540                 break;
8541             }
8542             if(local === true){
8543                 return [x, y];
8544             }
8545             if(vp){
8546                 var sc = this.getScroll();
8547                 return [x + sc.left, y + sc.top];
8548             }
8549             //Add the element's offset xy
8550             var o = this.getXY();
8551             return [x+o[0], y+o[1]];
8552         },
8553
8554         /**
8555          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8556          * supported position values.
8557          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8558          * @param {String} position The position to align to.
8559          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8560          * @return {Array} [x, y]
8561          */
8562         getAlignToXY : function(el, p, o){
8563             el = Roo.get(el);
8564             var d = this.dom;
8565             if(!el.dom){
8566                 throw "Element.alignTo with an element that doesn't exist";
8567             }
8568             var c = false; //constrain to viewport
8569             var p1 = "", p2 = "";
8570             o = o || [0,0];
8571
8572             if(!p){
8573                 p = "tl-bl";
8574             }else if(p == "?"){
8575                 p = "tl-bl?";
8576             }else if(p.indexOf("-") == -1){
8577                 p = "tl-" + p;
8578             }
8579             p = p.toLowerCase();
8580             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8581             if(!m){
8582                throw "Element.alignTo with an invalid alignment " + p;
8583             }
8584             p1 = m[1]; p2 = m[2]; c = !!m[3];
8585
8586             //Subtract the aligned el's internal xy from the target's offset xy
8587             //plus custom offset to get the aligned el's new offset xy
8588             var a1 = this.getAnchorXY(p1, true);
8589             var a2 = el.getAnchorXY(p2, false);
8590             var x = a2[0] - a1[0] + o[0];
8591             var y = a2[1] - a1[1] + o[1];
8592             if(c){
8593                 //constrain the aligned el to viewport if necessary
8594                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8595                 // 5px of margin for ie
8596                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8597
8598                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8599                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8600                 //otherwise swap the aligned el to the opposite border of the target.
8601                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8602                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8603                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8604                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8605
8606                var doc = document;
8607                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8608                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8609
8610                if((x+w) > dw + scrollX){
8611                     x = swapX ? r.left-w : dw+scrollX-w;
8612                 }
8613                if(x < scrollX){
8614                    x = swapX ? r.right : scrollX;
8615                }
8616                if((y+h) > dh + scrollY){
8617                     y = swapY ? r.top-h : dh+scrollY-h;
8618                 }
8619                if (y < scrollY){
8620                    y = swapY ? r.bottom : scrollY;
8621                }
8622             }
8623             return [x,y];
8624         },
8625
8626         // private
8627         getConstrainToXY : function(){
8628             var os = {top:0, left:0, bottom:0, right: 0};
8629
8630             return function(el, local, offsets, proposedXY){
8631                 el = Roo.get(el);
8632                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8633
8634                 var vw, vh, vx = 0, vy = 0;
8635                 if(el.dom == document.body || el.dom == document){
8636                     vw = Roo.lib.Dom.getViewWidth();
8637                     vh = Roo.lib.Dom.getViewHeight();
8638                 }else{
8639                     vw = el.dom.clientWidth;
8640                     vh = el.dom.clientHeight;
8641                     if(!local){
8642                         var vxy = el.getXY();
8643                         vx = vxy[0];
8644                         vy = vxy[1];
8645                     }
8646                 }
8647
8648                 var s = el.getScroll();
8649
8650                 vx += offsets.left + s.left;
8651                 vy += offsets.top + s.top;
8652
8653                 vw -= offsets.right;
8654                 vh -= offsets.bottom;
8655
8656                 var vr = vx+vw;
8657                 var vb = vy+vh;
8658
8659                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8660                 var x = xy[0], y = xy[1];
8661                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8662
8663                 // only move it if it needs it
8664                 var moved = false;
8665
8666                 // first validate right/bottom
8667                 if((x + w) > vr){
8668                     x = vr - w;
8669                     moved = true;
8670                 }
8671                 if((y + h) > vb){
8672                     y = vb - h;
8673                     moved = true;
8674                 }
8675                 // then make sure top/left isn't negative
8676                 if(x < vx){
8677                     x = vx;
8678                     moved = true;
8679                 }
8680                 if(y < vy){
8681                     y = vy;
8682                     moved = true;
8683                 }
8684                 return moved ? [x, y] : false;
8685             };
8686         }(),
8687
8688         // private
8689         adjustForConstraints : function(xy, parent, offsets){
8690             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8691         },
8692
8693         /**
8694          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8695          * document it aligns it to the viewport.
8696          * The position parameter is optional, and can be specified in any one of the following formats:
8697          * <ul>
8698          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8699          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8700          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8701          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8702          *   <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
8703          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8704          * </ul>
8705          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8706          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8707          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8708          * that specified in order to enforce the viewport constraints.
8709          * Following are all of the supported anchor positions:
8710     <pre>
8711     Value  Description
8712     -----  -----------------------------
8713     tl     The top left corner (default)
8714     t      The center of the top edge
8715     tr     The top right corner
8716     l      The center of the left edge
8717     c      In the center of the element
8718     r      The center of the right edge
8719     bl     The bottom left corner
8720     b      The center of the bottom edge
8721     br     The bottom right corner
8722     </pre>
8723     Example Usage:
8724     <pre><code>
8725     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8726     el.alignTo("other-el");
8727
8728     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8729     el.alignTo("other-el", "tr?");
8730
8731     // align the bottom right corner of el with the center left edge of other-el
8732     el.alignTo("other-el", "br-l?");
8733
8734     // align the center of el with the bottom left corner of other-el and
8735     // adjust the x position by -6 pixels (and the y position by 0)
8736     el.alignTo("other-el", "c-bl", [-6, 0]);
8737     </code></pre>
8738          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8739          * @param {String} position The position to align to.
8740          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8741          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8742          * @return {Roo.Element} this
8743          */
8744         alignTo : function(element, position, offsets, animate){
8745             var xy = this.getAlignToXY(element, position, offsets);
8746             this.setXY(xy, this.preanim(arguments, 3));
8747             return this;
8748         },
8749
8750         /**
8751          * Anchors an element to another element and realigns it when the window is resized.
8752          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8753          * @param {String} position The position to align to.
8754          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8755          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8756          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8757          * is a number, it is used as the buffer delay (defaults to 50ms).
8758          * @param {Function} callback The function to call after the animation finishes
8759          * @return {Roo.Element} this
8760          */
8761         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8762             var action = function(){
8763                 this.alignTo(el, alignment, offsets, animate);
8764                 Roo.callback(callback, this);
8765             };
8766             Roo.EventManager.onWindowResize(action, this);
8767             var tm = typeof monitorScroll;
8768             if(tm != 'undefined'){
8769                 Roo.EventManager.on(window, 'scroll', action, this,
8770                     {buffer: tm == 'number' ? monitorScroll : 50});
8771             }
8772             action.call(this); // align immediately
8773             return this;
8774         },
8775         /**
8776          * Clears any opacity settings from this element. Required in some cases for IE.
8777          * @return {Roo.Element} this
8778          */
8779         clearOpacity : function(){
8780             if (window.ActiveXObject) {
8781                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8782                     this.dom.style.filter = "";
8783                 }
8784             } else {
8785                 this.dom.style.opacity = "";
8786                 this.dom.style["-moz-opacity"] = "";
8787                 this.dom.style["-khtml-opacity"] = "";
8788             }
8789             return this;
8790         },
8791
8792         /**
8793          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8794          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8795          * @return {Roo.Element} this
8796          */
8797         hide : function(animate){
8798             this.setVisible(false, this.preanim(arguments, 0));
8799             return this;
8800         },
8801
8802         /**
8803         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8804         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8805          * @return {Roo.Element} this
8806          */
8807         show : function(animate){
8808             this.setVisible(true, this.preanim(arguments, 0));
8809             return this;
8810         },
8811
8812         /**
8813          * @private Test if size has a unit, otherwise appends the default
8814          */
8815         addUnits : function(size){
8816             return Roo.Element.addUnits(size, this.defaultUnit);
8817         },
8818
8819         /**
8820          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8821          * @return {Roo.Element} this
8822          */
8823         beginMeasure : function(){
8824             var el = this.dom;
8825             if(el.offsetWidth || el.offsetHeight){
8826                 return this; // offsets work already
8827             }
8828             var changed = [];
8829             var p = this.dom, b = document.body; // start with this element
8830             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8831                 var pe = Roo.get(p);
8832                 if(pe.getStyle('display') == 'none'){
8833                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8834                     p.style.visibility = "hidden";
8835                     p.style.display = "block";
8836                 }
8837                 p = p.parentNode;
8838             }
8839             this._measureChanged = changed;
8840             return this;
8841
8842         },
8843
8844         /**
8845          * Restores displays to before beginMeasure was called
8846          * @return {Roo.Element} this
8847          */
8848         endMeasure : function(){
8849             var changed = this._measureChanged;
8850             if(changed){
8851                 for(var i = 0, len = changed.length; i < len; i++) {
8852                     var r = changed[i];
8853                     r.el.style.visibility = r.visibility;
8854                     r.el.style.display = "none";
8855                 }
8856                 this._measureChanged = null;
8857             }
8858             return this;
8859         },
8860
8861         /**
8862         * Update the innerHTML of this element, optionally searching for and processing scripts
8863         * @param {String} html The new HTML
8864         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8865         * @param {Function} callback For async script loading you can be noticed when the update completes
8866         * @return {Roo.Element} this
8867          */
8868         update : function(html, loadScripts, callback){
8869             if(typeof html == "undefined"){
8870                 html = "";
8871             }
8872             if(loadScripts !== true){
8873                 this.dom.innerHTML = html;
8874                 if(typeof callback == "function"){
8875                     callback();
8876                 }
8877                 return this;
8878             }
8879             var id = Roo.id();
8880             var dom = this.dom;
8881
8882             html += '<span id="' + id + '"></span>';
8883
8884             E.onAvailable(id, function(){
8885                 var hd = document.getElementsByTagName("head")[0];
8886                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8887                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8888                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8889
8890                 var match;
8891                 while(match = re.exec(html)){
8892                     var attrs = match[1];
8893                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8894                     if(srcMatch && srcMatch[2]){
8895                        var s = document.createElement("script");
8896                        s.src = srcMatch[2];
8897                        var typeMatch = attrs.match(typeRe);
8898                        if(typeMatch && typeMatch[2]){
8899                            s.type = typeMatch[2];
8900                        }
8901                        hd.appendChild(s);
8902                     }else if(match[2] && match[2].length > 0){
8903                         if(window.execScript) {
8904                            window.execScript(match[2]);
8905                         } else {
8906                             /**
8907                              * eval:var:id
8908                              * eval:var:dom
8909                              * eval:var:html
8910                              * 
8911                              */
8912                            window.eval(match[2]);
8913                         }
8914                     }
8915                 }
8916                 var el = document.getElementById(id);
8917                 if(el){el.parentNode.removeChild(el);}
8918                 if(typeof callback == "function"){
8919                     callback();
8920                 }
8921             });
8922             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8923             return this;
8924         },
8925
8926         /**
8927          * Direct access to the UpdateManager update() method (takes the same parameters).
8928          * @param {String/Function} url The url for this request or a function to call to get the url
8929          * @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}
8930          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8931          * @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.
8932          * @return {Roo.Element} this
8933          */
8934         load : function(){
8935             var um = this.getUpdateManager();
8936             um.update.apply(um, arguments);
8937             return this;
8938         },
8939
8940         /**
8941         * Gets this element's UpdateManager
8942         * @return {Roo.UpdateManager} The UpdateManager
8943         */
8944         getUpdateManager : function(){
8945             if(!this.updateManager){
8946                 this.updateManager = new Roo.UpdateManager(this);
8947             }
8948             return this.updateManager;
8949         },
8950
8951         /**
8952          * Disables text selection for this element (normalized across browsers)
8953          * @return {Roo.Element} this
8954          */
8955         unselectable : function(){
8956             this.dom.unselectable = "on";
8957             this.swallowEvent("selectstart", true);
8958             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8959             this.addClass("x-unselectable");
8960             return this;
8961         },
8962
8963         /**
8964         * Calculates the x, y to center this element on the screen
8965         * @return {Array} The x, y values [x, y]
8966         */
8967         getCenterXY : function(){
8968             return this.getAlignToXY(document, 'c-c');
8969         },
8970
8971         /**
8972         * Centers the Element in either the viewport, or another Element.
8973         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8974         */
8975         center : function(centerIn){
8976             this.alignTo(centerIn || document, 'c-c');
8977             return this;
8978         },
8979
8980         /**
8981          * Tests various css rules/browsers to determine if this element uses a border box
8982          * @return {Boolean}
8983          */
8984         isBorderBox : function(){
8985             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8986         },
8987
8988         /**
8989          * Return a box {x, y, width, height} that can be used to set another elements
8990          * size/location to match this element.
8991          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8992          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8993          * @return {Object} box An object in the format {x, y, width, height}
8994          */
8995         getBox : function(contentBox, local){
8996             var xy;
8997             if(!local){
8998                 xy = this.getXY();
8999             }else{
9000                 var left = parseInt(this.getStyle("left"), 10) || 0;
9001                 var top = parseInt(this.getStyle("top"), 10) || 0;
9002                 xy = [left, top];
9003             }
9004             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9005             if(!contentBox){
9006                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9007             }else{
9008                 var l = this.getBorderWidth("l")+this.getPadding("l");
9009                 var r = this.getBorderWidth("r")+this.getPadding("r");
9010                 var t = this.getBorderWidth("t")+this.getPadding("t");
9011                 var b = this.getBorderWidth("b")+this.getPadding("b");
9012                 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)};
9013             }
9014             bx.right = bx.x + bx.width;
9015             bx.bottom = bx.y + bx.height;
9016             return bx;
9017         },
9018
9019         /**
9020          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9021          for more information about the sides.
9022          * @param {String} sides
9023          * @return {Number}
9024          */
9025         getFrameWidth : function(sides, onlyContentBox){
9026             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9027         },
9028
9029         /**
9030          * 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.
9031          * @param {Object} box The box to fill {x, y, width, height}
9032          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9033          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9034          * @return {Roo.Element} this
9035          */
9036         setBox : function(box, adjust, animate){
9037             var w = box.width, h = box.height;
9038             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9039                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9040                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9041             }
9042             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9043             return this;
9044         },
9045
9046         /**
9047          * Forces the browser to repaint this element
9048          * @return {Roo.Element} this
9049          */
9050          repaint : function(){
9051             var dom = this.dom;
9052             this.addClass("x-repaint");
9053             setTimeout(function(){
9054                 Roo.get(dom).removeClass("x-repaint");
9055             }, 1);
9056             return this;
9057         },
9058
9059         /**
9060          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9061          * then it returns the calculated width of the sides (see getPadding)
9062          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9063          * @return {Object/Number}
9064          */
9065         getMargins : function(side){
9066             if(!side){
9067                 return {
9068                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9069                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9070                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9071                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9072                 };
9073             }else{
9074                 return this.addStyles(side, El.margins);
9075              }
9076         },
9077
9078         // private
9079         addStyles : function(sides, styles){
9080             var val = 0, v, w;
9081             for(var i = 0, len = sides.length; i < len; i++){
9082                 v = this.getStyle(styles[sides.charAt(i)]);
9083                 if(v){
9084                      w = parseInt(v, 10);
9085                      if(w){ val += w; }
9086                 }
9087             }
9088             return val;
9089         },
9090
9091         /**
9092          * Creates a proxy element of this element
9093          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9094          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9095          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9096          * @return {Roo.Element} The new proxy element
9097          */
9098         createProxy : function(config, renderTo, matchBox){
9099             if(renderTo){
9100                 renderTo = Roo.getDom(renderTo);
9101             }else{
9102                 renderTo = document.body;
9103             }
9104             config = typeof config == "object" ?
9105                 config : {tag : "div", cls: config};
9106             var proxy = Roo.DomHelper.append(renderTo, config, true);
9107             if(matchBox){
9108                proxy.setBox(this.getBox());
9109             }
9110             return proxy;
9111         },
9112
9113         /**
9114          * Puts a mask over this element to disable user interaction. Requires core.css.
9115          * This method can only be applied to elements which accept child nodes.
9116          * @param {String} msg (optional) A message to display in the mask
9117          * @param {String} msgCls (optional) A css class to apply to the msg element
9118          * @return {Element} The mask  element
9119          */
9120         mask : function(msg, msgCls)
9121         {
9122             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9123                 this.setStyle("position", "relative");
9124             }
9125             if(!this._mask){
9126                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9127             }
9128             
9129             this.addClass("x-masked");
9130             this._mask.setDisplayed(true);
9131             
9132             // we wander
9133             var z = 0;
9134             var dom = this.dom;
9135             while (dom && dom.style) {
9136                 if (!isNaN(parseInt(dom.style.zIndex))) {
9137                     z = Math.max(z, parseInt(dom.style.zIndex));
9138                 }
9139                 dom = dom.parentNode;
9140             }
9141             // if we are masking the body - then it hides everything..
9142             if (this.dom == document.body) {
9143                 z = 1000000;
9144                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9145                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9146             }
9147            
9148             if(typeof msg == 'string'){
9149                 if(!this._maskMsg){
9150                     this._maskMsg = Roo.DomHelper.append(this.dom, {
9151                         cls: "roo-el-mask-msg", 
9152                         cn: [
9153                             {
9154                                 tag: 'i',
9155                                 cls: 'fa fa-spinner fa-spin'
9156                             },
9157                             {
9158                                 tag: 'div'
9159                             }   
9160                         ]
9161                     }, true);
9162                 }
9163                 var mm = this._maskMsg;
9164                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9165                 if (mm.dom.lastChild) { // weird IE issue?
9166                     mm.dom.lastChild.innerHTML = msg;
9167                 }
9168                 mm.setDisplayed(true);
9169                 mm.center(this);
9170                 mm.setStyle('z-index', z + 102);
9171             }
9172             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9173                 this._mask.setHeight(this.getHeight());
9174             }
9175             this._mask.setStyle('z-index', z + 100);
9176             
9177             return this._mask;
9178         },
9179
9180         /**
9181          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9182          * it is cached for reuse.
9183          */
9184         unmask : function(removeEl){
9185             if(this._mask){
9186                 if(removeEl === true){
9187                     this._mask.remove();
9188                     delete this._mask;
9189                     if(this._maskMsg){
9190                         this._maskMsg.remove();
9191                         delete this._maskMsg;
9192                     }
9193                 }else{
9194                     this._mask.setDisplayed(false);
9195                     if(this._maskMsg){
9196                         this._maskMsg.setDisplayed(false);
9197                     }
9198                 }
9199             }
9200             this.removeClass("x-masked");
9201         },
9202
9203         /**
9204          * Returns true if this element is masked
9205          * @return {Boolean}
9206          */
9207         isMasked : function(){
9208             return this._mask && this._mask.isVisible();
9209         },
9210
9211         /**
9212          * Creates an iframe shim for this element to keep selects and other windowed objects from
9213          * showing through.
9214          * @return {Roo.Element} The new shim element
9215          */
9216         createShim : function(){
9217             var el = document.createElement('iframe');
9218             el.frameBorder = 'no';
9219             el.className = 'roo-shim';
9220             if(Roo.isIE && Roo.isSecure){
9221                 el.src = Roo.SSL_SECURE_URL;
9222             }
9223             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9224             shim.autoBoxAdjust = false;
9225             return shim;
9226         },
9227
9228         /**
9229          * Removes this element from the DOM and deletes it from the cache
9230          */
9231         remove : function(){
9232             if(this.dom.parentNode){
9233                 this.dom.parentNode.removeChild(this.dom);
9234             }
9235             delete El.cache[this.dom.id];
9236         },
9237
9238         /**
9239          * Sets up event handlers to add and remove a css class when the mouse is over this element
9240          * @param {String} className
9241          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9242          * mouseout events for children elements
9243          * @return {Roo.Element} this
9244          */
9245         addClassOnOver : function(className, preventFlicker){
9246             this.on("mouseover", function(){
9247                 Roo.fly(this, '_internal').addClass(className);
9248             }, this.dom);
9249             var removeFn = function(e){
9250                 if(preventFlicker !== true || !e.within(this, true)){
9251                     Roo.fly(this, '_internal').removeClass(className);
9252                 }
9253             };
9254             this.on("mouseout", removeFn, this.dom);
9255             return this;
9256         },
9257
9258         /**
9259          * Sets up event handlers to add and remove a css class when this element has the focus
9260          * @param {String} className
9261          * @return {Roo.Element} this
9262          */
9263         addClassOnFocus : function(className){
9264             this.on("focus", function(){
9265                 Roo.fly(this, '_internal').addClass(className);
9266             }, this.dom);
9267             this.on("blur", function(){
9268                 Roo.fly(this, '_internal').removeClass(className);
9269             }, this.dom);
9270             return this;
9271         },
9272         /**
9273          * 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)
9274          * @param {String} className
9275          * @return {Roo.Element} this
9276          */
9277         addClassOnClick : function(className){
9278             var dom = this.dom;
9279             this.on("mousedown", function(){
9280                 Roo.fly(dom, '_internal').addClass(className);
9281                 var d = Roo.get(document);
9282                 var fn = function(){
9283                     Roo.fly(dom, '_internal').removeClass(className);
9284                     d.removeListener("mouseup", fn);
9285                 };
9286                 d.on("mouseup", fn);
9287             });
9288             return this;
9289         },
9290
9291         /**
9292          * Stops the specified event from bubbling and optionally prevents the default action
9293          * @param {String} eventName
9294          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9295          * @return {Roo.Element} this
9296          */
9297         swallowEvent : function(eventName, preventDefault){
9298             var fn = function(e){
9299                 e.stopPropagation();
9300                 if(preventDefault){
9301                     e.preventDefault();
9302                 }
9303             };
9304             if(eventName instanceof Array){
9305                 for(var i = 0, len = eventName.length; i < len; i++){
9306                      this.on(eventName[i], fn);
9307                 }
9308                 return this;
9309             }
9310             this.on(eventName, fn);
9311             return this;
9312         },
9313
9314         /**
9315          * @private
9316          */
9317       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9318
9319         /**
9320          * Sizes this element to its parent element's dimensions performing
9321          * neccessary box adjustments.
9322          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9323          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9324          * @return {Roo.Element} this
9325          */
9326         fitToParent : function(monitorResize, targetParent) {
9327           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9328           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9329           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9330             return;
9331           }
9332           var p = Roo.get(targetParent || this.dom.parentNode);
9333           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9334           if (monitorResize === true) {
9335             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9336             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9337           }
9338           return this;
9339         },
9340
9341         /**
9342          * Gets the next sibling, skipping text nodes
9343          * @return {HTMLElement} The next sibling or null
9344          */
9345         getNextSibling : function(){
9346             var n = this.dom.nextSibling;
9347             while(n && n.nodeType != 1){
9348                 n = n.nextSibling;
9349             }
9350             return n;
9351         },
9352
9353         /**
9354          * Gets the previous sibling, skipping text nodes
9355          * @return {HTMLElement} The previous sibling or null
9356          */
9357         getPrevSibling : function(){
9358             var n = this.dom.previousSibling;
9359             while(n && n.nodeType != 1){
9360                 n = n.previousSibling;
9361             }
9362             return n;
9363         },
9364
9365
9366         /**
9367          * Appends the passed element(s) to this element
9368          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9369          * @return {Roo.Element} this
9370          */
9371         appendChild: function(el){
9372             el = Roo.get(el);
9373             el.appendTo(this);
9374             return this;
9375         },
9376
9377         /**
9378          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9379          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9380          * automatically generated with the specified attributes.
9381          * @param {HTMLElement} insertBefore (optional) a child element of this element
9382          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9383          * @return {Roo.Element} The new child element
9384          */
9385         createChild: function(config, insertBefore, returnDom){
9386             config = config || {tag:'div'};
9387             if(insertBefore){
9388                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9389             }
9390             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9391         },
9392
9393         /**
9394          * Appends this element to the passed element
9395          * @param {String/HTMLElement/Element} el The new parent element
9396          * @return {Roo.Element} this
9397          */
9398         appendTo: function(el){
9399             el = Roo.getDom(el);
9400             el.appendChild(this.dom);
9401             return this;
9402         },
9403
9404         /**
9405          * Inserts this element before the passed element in the DOM
9406          * @param {String/HTMLElement/Element} el The element to insert before
9407          * @return {Roo.Element} this
9408          */
9409         insertBefore: function(el){
9410             el = Roo.getDom(el);
9411             el.parentNode.insertBefore(this.dom, el);
9412             return this;
9413         },
9414
9415         /**
9416          * Inserts this element after the passed element in the DOM
9417          * @param {String/HTMLElement/Element} el The element to insert after
9418          * @return {Roo.Element} this
9419          */
9420         insertAfter: function(el){
9421             el = Roo.getDom(el);
9422             el.parentNode.insertBefore(this.dom, el.nextSibling);
9423             return this;
9424         },
9425
9426         /**
9427          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9428          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9429          * @return {Roo.Element} The new child
9430          */
9431         insertFirst: function(el, returnDom){
9432             el = el || {};
9433             if(typeof el == 'object' && !el.nodeType){ // dh config
9434                 return this.createChild(el, this.dom.firstChild, returnDom);
9435             }else{
9436                 el = Roo.getDom(el);
9437                 this.dom.insertBefore(el, this.dom.firstChild);
9438                 return !returnDom ? Roo.get(el) : el;
9439             }
9440         },
9441
9442         /**
9443          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9444          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9445          * @param {String} where (optional) 'before' or 'after' defaults to before
9446          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9447          * @return {Roo.Element} the inserted Element
9448          */
9449         insertSibling: function(el, where, returnDom){
9450             where = where ? where.toLowerCase() : 'before';
9451             el = el || {};
9452             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9453
9454             if(typeof el == 'object' && !el.nodeType){ // dh config
9455                 if(where == 'after' && !this.dom.nextSibling){
9456                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9457                 }else{
9458                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9459                 }
9460
9461             }else{
9462                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9463                             where == 'before' ? this.dom : this.dom.nextSibling);
9464                 if(!returnDom){
9465                     rt = Roo.get(rt);
9466                 }
9467             }
9468             return rt;
9469         },
9470
9471         /**
9472          * Creates and wraps this element with another element
9473          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9474          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9475          * @return {HTMLElement/Element} The newly created wrapper element
9476          */
9477         wrap: function(config, returnDom){
9478             if(!config){
9479                 config = {tag: "div"};
9480             }
9481             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9482             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9483             return newEl;
9484         },
9485
9486         /**
9487          * Replaces the passed element with this element
9488          * @param {String/HTMLElement/Element} el The element to replace
9489          * @return {Roo.Element} this
9490          */
9491         replace: function(el){
9492             el = Roo.get(el);
9493             this.insertBefore(el);
9494             el.remove();
9495             return this;
9496         },
9497
9498         /**
9499          * Inserts an html fragment into this element
9500          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9501          * @param {String} html The HTML fragment
9502          * @param {Boolean} returnEl True to return an Roo.Element
9503          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9504          */
9505         insertHtml : function(where, html, returnEl){
9506             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9507             return returnEl ? Roo.get(el) : el;
9508         },
9509
9510         /**
9511          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9512          * @param {Object} o The object with the attributes
9513          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9514          * @return {Roo.Element} this
9515          */
9516         set : function(o, useSet){
9517             var el = this.dom;
9518             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9519             for(var attr in o){
9520                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9521                 if(attr=="cls"){
9522                     el.className = o["cls"];
9523                 }else{
9524                     if(useSet) {
9525                         el.setAttribute(attr, o[attr]);
9526                     } else {
9527                         el[attr] = o[attr];
9528                     }
9529                 }
9530             }
9531             if(o.style){
9532                 Roo.DomHelper.applyStyles(el, o.style);
9533             }
9534             return this;
9535         },
9536
9537         /**
9538          * Convenience method for constructing a KeyMap
9539          * @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:
9540          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9541          * @param {Function} fn The function to call
9542          * @param {Object} scope (optional) The scope of the function
9543          * @return {Roo.KeyMap} The KeyMap created
9544          */
9545         addKeyListener : function(key, fn, scope){
9546             var config;
9547             if(typeof key != "object" || key instanceof Array){
9548                 config = {
9549                     key: key,
9550                     fn: fn,
9551                     scope: scope
9552                 };
9553             }else{
9554                 config = {
9555                     key : key.key,
9556                     shift : key.shift,
9557                     ctrl : key.ctrl,
9558                     alt : key.alt,
9559                     fn: fn,
9560                     scope: scope
9561                 };
9562             }
9563             return new Roo.KeyMap(this, config);
9564         },
9565
9566         /**
9567          * Creates a KeyMap for this element
9568          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9569          * @return {Roo.KeyMap} The KeyMap created
9570          */
9571         addKeyMap : function(config){
9572             return new Roo.KeyMap(this, config);
9573         },
9574
9575         /**
9576          * Returns true if this element is scrollable.
9577          * @return {Boolean}
9578          */
9579          isScrollable : function(){
9580             var dom = this.dom;
9581             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9582         },
9583
9584         /**
9585          * 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().
9586          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9587          * @param {Number} value The new scroll value
9588          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9589          * @return {Element} this
9590          */
9591
9592         scrollTo : function(side, value, animate){
9593             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9594             if(!animate || !A){
9595                 this.dom[prop] = value;
9596             }else{
9597                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9598                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9599             }
9600             return this;
9601         },
9602
9603         /**
9604          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9605          * within this element's scrollable range.
9606          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9607          * @param {Number} distance How far to scroll the element in pixels
9608          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9609          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9610          * was scrolled as far as it could go.
9611          */
9612          scroll : function(direction, distance, animate){
9613              if(!this.isScrollable()){
9614                  return;
9615              }
9616              var el = this.dom;
9617              var l = el.scrollLeft, t = el.scrollTop;
9618              var w = el.scrollWidth, h = el.scrollHeight;
9619              var cw = el.clientWidth, ch = el.clientHeight;
9620              direction = direction.toLowerCase();
9621              var scrolled = false;
9622              var a = this.preanim(arguments, 2);
9623              switch(direction){
9624                  case "l":
9625                  case "left":
9626                      if(w - l > cw){
9627                          var v = Math.min(l + distance, w-cw);
9628                          this.scrollTo("left", v, a);
9629                          scrolled = true;
9630                      }
9631                      break;
9632                 case "r":
9633                 case "right":
9634                      if(l > 0){
9635                          var v = Math.max(l - distance, 0);
9636                          this.scrollTo("left", v, a);
9637                          scrolled = true;
9638                      }
9639                      break;
9640                 case "t":
9641                 case "top":
9642                 case "up":
9643                      if(t > 0){
9644                          var v = Math.max(t - distance, 0);
9645                          this.scrollTo("top", v, a);
9646                          scrolled = true;
9647                      }
9648                      break;
9649                 case "b":
9650                 case "bottom":
9651                 case "down":
9652                      if(h - t > ch){
9653                          var v = Math.min(t + distance, h-ch);
9654                          this.scrollTo("top", v, a);
9655                          scrolled = true;
9656                      }
9657                      break;
9658              }
9659              return scrolled;
9660         },
9661
9662         /**
9663          * Translates the passed page coordinates into left/top css values for this element
9664          * @param {Number/Array} x The page x or an array containing [x, y]
9665          * @param {Number} y The page y
9666          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9667          */
9668         translatePoints : function(x, y){
9669             if(typeof x == 'object' || x instanceof Array){
9670                 y = x[1]; x = x[0];
9671             }
9672             var p = this.getStyle('position');
9673             var o = this.getXY();
9674
9675             var l = parseInt(this.getStyle('left'), 10);
9676             var t = parseInt(this.getStyle('top'), 10);
9677
9678             if(isNaN(l)){
9679                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9680             }
9681             if(isNaN(t)){
9682                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9683             }
9684
9685             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9686         },
9687
9688         /**
9689          * Returns the current scroll position of the element.
9690          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9691          */
9692         getScroll : function(){
9693             var d = this.dom, doc = document;
9694             if(d == doc || d == doc.body){
9695                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9696                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9697                 return {left: l, top: t};
9698             }else{
9699                 return {left: d.scrollLeft, top: d.scrollTop};
9700             }
9701         },
9702
9703         /**
9704          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9705          * are convert to standard 6 digit hex color.
9706          * @param {String} attr The css attribute
9707          * @param {String} defaultValue The default value to use when a valid color isn't found
9708          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9709          * YUI color anims.
9710          */
9711         getColor : function(attr, defaultValue, prefix){
9712             var v = this.getStyle(attr);
9713             if(!v || v == "transparent" || v == "inherit") {
9714                 return defaultValue;
9715             }
9716             var color = typeof prefix == "undefined" ? "#" : prefix;
9717             if(v.substr(0, 4) == "rgb("){
9718                 var rvs = v.slice(4, v.length -1).split(",");
9719                 for(var i = 0; i < 3; i++){
9720                     var h = parseInt(rvs[i]).toString(16);
9721                     if(h < 16){
9722                         h = "0" + h;
9723                     }
9724                     color += h;
9725                 }
9726             } else {
9727                 if(v.substr(0, 1) == "#"){
9728                     if(v.length == 4) {
9729                         for(var i = 1; i < 4; i++){
9730                             var c = v.charAt(i);
9731                             color +=  c + c;
9732                         }
9733                     }else if(v.length == 7){
9734                         color += v.substr(1);
9735                     }
9736                 }
9737             }
9738             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9739         },
9740
9741         /**
9742          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9743          * gradient background, rounded corners and a 4-way shadow.
9744          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9745          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9746          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9747          * @return {Roo.Element} this
9748          */
9749         boxWrap : function(cls){
9750             cls = cls || 'x-box';
9751             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9752             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9753             return el;
9754         },
9755
9756         /**
9757          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9758          * @param {String} namespace The namespace in which to look for the attribute
9759          * @param {String} name The attribute name
9760          * @return {String} The attribute value
9761          */
9762         getAttributeNS : Roo.isIE ? function(ns, name){
9763             var d = this.dom;
9764             var type = typeof d[ns+":"+name];
9765             if(type != 'undefined' && type != 'unknown'){
9766                 return d[ns+":"+name];
9767             }
9768             return d[name];
9769         } : function(ns, name){
9770             var d = this.dom;
9771             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9772         },
9773         
9774         
9775         /**
9776          * Sets or Returns the value the dom attribute value
9777          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9778          * @param {String} value (optional) The value to set the attribute to
9779          * @return {String} The attribute value
9780          */
9781         attr : function(name){
9782             if (arguments.length > 1) {
9783                 this.dom.setAttribute(name, arguments[1]);
9784                 return arguments[1];
9785             }
9786             if (typeof(name) == 'object') {
9787                 for(var i in name) {
9788                     this.attr(i, name[i]);
9789                 }
9790                 return name;
9791             }
9792             
9793             
9794             if (!this.dom.hasAttribute(name)) {
9795                 return undefined;
9796             }
9797             return this.dom.getAttribute(name);
9798         }
9799         
9800         
9801         
9802     };
9803
9804     var ep = El.prototype;
9805
9806     /**
9807      * Appends an event handler (Shorthand for addListener)
9808      * @param {String}   eventName     The type of event to append
9809      * @param {Function} fn        The method the event invokes
9810      * @param {Object} scope       (optional) The scope (this object) of the fn
9811      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9812      * @method
9813      */
9814     ep.on = ep.addListener;
9815         // backwards compat
9816     ep.mon = ep.addListener;
9817
9818     /**
9819      * Removes an event handler from this element (shorthand for removeListener)
9820      * @param {String} eventName the type of event to remove
9821      * @param {Function} fn the method the event invokes
9822      * @return {Roo.Element} this
9823      * @method
9824      */
9825     ep.un = ep.removeListener;
9826
9827     /**
9828      * true to automatically adjust width and height settings for box-model issues (default to true)
9829      */
9830     ep.autoBoxAdjust = true;
9831
9832     // private
9833     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9834
9835     // private
9836     El.addUnits = function(v, defaultUnit){
9837         if(v === "" || v == "auto"){
9838             return v;
9839         }
9840         if(v === undefined){
9841             return '';
9842         }
9843         if(typeof v == "number" || !El.unitPattern.test(v)){
9844             return v + (defaultUnit || 'px');
9845         }
9846         return v;
9847     };
9848
9849     // special markup used throughout Roo when box wrapping elements
9850     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>';
9851     /**
9852      * Visibility mode constant - Use visibility to hide element
9853      * @static
9854      * @type Number
9855      */
9856     El.VISIBILITY = 1;
9857     /**
9858      * Visibility mode constant - Use display to hide element
9859      * @static
9860      * @type Number
9861      */
9862     El.DISPLAY = 2;
9863
9864     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9865     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9866     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9867
9868
9869
9870     /**
9871      * @private
9872      */
9873     El.cache = {};
9874
9875     var docEl;
9876
9877     /**
9878      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9879      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9880      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9881      * @return {Element} The Element object
9882      * @static
9883      */
9884     El.get = function(el){
9885         var ex, elm, id;
9886         if(!el){ return null; }
9887         if(typeof el == "string"){ // element id
9888             if(!(elm = document.getElementById(el))){
9889                 return null;
9890             }
9891             if(ex = El.cache[el]){
9892                 ex.dom = elm;
9893             }else{
9894                 ex = El.cache[el] = new El(elm);
9895             }
9896             return ex;
9897         }else if(el.tagName){ // dom element
9898             if(!(id = el.id)){
9899                 id = Roo.id(el);
9900             }
9901             if(ex = El.cache[id]){
9902                 ex.dom = el;
9903             }else{
9904                 ex = El.cache[id] = new El(el);
9905             }
9906             return ex;
9907         }else if(el instanceof El){
9908             if(el != docEl){
9909                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9910                                                               // catch case where it hasn't been appended
9911                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9912             }
9913             return el;
9914         }else if(el.isComposite){
9915             return el;
9916         }else if(el instanceof Array){
9917             return El.select(el);
9918         }else if(el == document){
9919             // create a bogus element object representing the document object
9920             if(!docEl){
9921                 var f = function(){};
9922                 f.prototype = El.prototype;
9923                 docEl = new f();
9924                 docEl.dom = document;
9925             }
9926             return docEl;
9927         }
9928         return null;
9929     };
9930
9931     // private
9932     El.uncache = function(el){
9933         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9934             if(a[i]){
9935                 delete El.cache[a[i].id || a[i]];
9936             }
9937         }
9938     };
9939
9940     // private
9941     // Garbage collection - uncache elements/purge listeners on orphaned elements
9942     // so we don't hold a reference and cause the browser to retain them
9943     El.garbageCollect = function(){
9944         if(!Roo.enableGarbageCollector){
9945             clearInterval(El.collectorThread);
9946             return;
9947         }
9948         for(var eid in El.cache){
9949             var el = El.cache[eid], d = el.dom;
9950             // -------------------------------------------------------
9951             // Determining what is garbage:
9952             // -------------------------------------------------------
9953             // !d
9954             // dom node is null, definitely garbage
9955             // -------------------------------------------------------
9956             // !d.parentNode
9957             // no parentNode == direct orphan, definitely garbage
9958             // -------------------------------------------------------
9959             // !d.offsetParent && !document.getElementById(eid)
9960             // display none elements have no offsetParent so we will
9961             // also try to look it up by it's id. However, check
9962             // offsetParent first so we don't do unneeded lookups.
9963             // This enables collection of elements that are not orphans
9964             // directly, but somewhere up the line they have an orphan
9965             // parent.
9966             // -------------------------------------------------------
9967             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9968                 delete El.cache[eid];
9969                 if(d && Roo.enableListenerCollection){
9970                     E.purgeElement(d);
9971                 }
9972             }
9973         }
9974     }
9975     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9976
9977
9978     // dom is optional
9979     El.Flyweight = function(dom){
9980         this.dom = dom;
9981     };
9982     El.Flyweight.prototype = El.prototype;
9983
9984     El._flyweights = {};
9985     /**
9986      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9987      * the dom node can be overwritten by other code.
9988      * @param {String/HTMLElement} el The dom node or id
9989      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9990      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9991      * @static
9992      * @return {Element} The shared Element object
9993      */
9994     El.fly = function(el, named){
9995         named = named || '_global';
9996         el = Roo.getDom(el);
9997         if(!el){
9998             return null;
9999         }
10000         if(!El._flyweights[named]){
10001             El._flyweights[named] = new El.Flyweight();
10002         }
10003         El._flyweights[named].dom = el;
10004         return El._flyweights[named];
10005     };
10006
10007     /**
10008      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10009      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10010      * Shorthand of {@link Roo.Element#get}
10011      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10012      * @return {Element} The Element object
10013      * @member Roo
10014      * @method get
10015      */
10016     Roo.get = El.get;
10017     /**
10018      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10019      * the dom node can be overwritten by other code.
10020      * Shorthand of {@link Roo.Element#fly}
10021      * @param {String/HTMLElement} el The dom node or id
10022      * @param {String} named (optional) Allows for creation of named reusable flyweights to
10023      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
10024      * @static
10025      * @return {Element} The shared Element object
10026      * @member Roo
10027      * @method fly
10028      */
10029     Roo.fly = El.fly;
10030
10031     // speedy lookup for elements never to box adjust
10032     var noBoxAdjust = Roo.isStrict ? {
10033         select:1
10034     } : {
10035         input:1, select:1, textarea:1
10036     };
10037     if(Roo.isIE || Roo.isGecko){
10038         noBoxAdjust['button'] = 1;
10039     }
10040
10041
10042     Roo.EventManager.on(window, 'unload', function(){
10043         delete El.cache;
10044         delete El._flyweights;
10045     });
10046 })();
10047
10048
10049
10050
10051 if(Roo.DomQuery){
10052     Roo.Element.selectorFunction = Roo.DomQuery.select;
10053 }
10054
10055 Roo.Element.select = function(selector, unique, root){
10056     var els;
10057     if(typeof selector == "string"){
10058         els = Roo.Element.selectorFunction(selector, root);
10059     }else if(selector.length !== undefined){
10060         els = selector;
10061     }else{
10062         throw "Invalid selector";
10063     }
10064     if(unique === true){
10065         return new Roo.CompositeElement(els);
10066     }else{
10067         return new Roo.CompositeElementLite(els);
10068     }
10069 };
10070 /**
10071  * Selects elements based on the passed CSS selector to enable working on them as 1.
10072  * @param {String/Array} selector The CSS selector or an array of elements
10073  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10074  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10075  * @return {CompositeElementLite/CompositeElement}
10076  * @member Roo
10077  * @method select
10078  */
10079 Roo.select = Roo.Element.select;
10080
10081
10082
10083
10084
10085
10086
10087
10088
10089
10090
10091
10092
10093
10094 /*
10095  * Based on:
10096  * Ext JS Library 1.1.1
10097  * Copyright(c) 2006-2007, Ext JS, LLC.
10098  *
10099  * Originally Released Under LGPL - original licence link has changed is not relivant.
10100  *
10101  * Fork - LGPL
10102  * <script type="text/javascript">
10103  */
10104
10105
10106
10107 //Notifies Element that fx methods are available
10108 Roo.enableFx = true;
10109
10110 /**
10111  * @class Roo.Fx
10112  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10113  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10114  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10115  * Element effects to work.</p><br/>
10116  *
10117  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10118  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10119  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10120  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10121  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10122  * expected results and should be done with care.</p><br/>
10123  *
10124  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10125  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10126 <pre>
10127 Value  Description
10128 -----  -----------------------------
10129 tl     The top left corner
10130 t      The center of the top edge
10131 tr     The top right corner
10132 l      The center of the left edge
10133 r      The center of the right edge
10134 bl     The bottom left corner
10135 b      The center of the bottom edge
10136 br     The bottom right corner
10137 </pre>
10138  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10139  * below are common options that can be passed to any Fx method.</b>
10140  * @cfg {Function} callback A function called when the effect is finished
10141  * @cfg {Object} scope The scope of the effect function
10142  * @cfg {String} easing A valid Easing value for the effect
10143  * @cfg {String} afterCls A css class to apply after the effect
10144  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10145  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10146  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10147  * effects that end with the element being visually hidden, ignored otherwise)
10148  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10149  * a function which returns such a specification that will be applied to the Element after the effect finishes
10150  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10151  * @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
10152  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10153  */
10154 Roo.Fx = {
10155         /**
10156          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10157          * origin for the slide effect.  This function automatically handles wrapping the element with
10158          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10159          * Usage:
10160          *<pre><code>
10161 // default: slide the element in from the top
10162 el.slideIn();
10163
10164 // custom: slide the element in from the right with a 2-second duration
10165 el.slideIn('r', { duration: 2 });
10166
10167 // common config options shown with default values
10168 el.slideIn('t', {
10169     easing: 'easeOut',
10170     duration: .5
10171 });
10172 </code></pre>
10173          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10174          * @param {Object} options (optional) Object literal with any of the Fx config options
10175          * @return {Roo.Element} The Element
10176          */
10177     slideIn : function(anchor, o){
10178         var el = this.getFxEl();
10179         o = o || {};
10180
10181         el.queueFx(o, function(){
10182
10183             anchor = anchor || "t";
10184
10185             // fix display to visibility
10186             this.fixDisplay();
10187
10188             // restore values after effect
10189             var r = this.getFxRestore();
10190             var b = this.getBox();
10191             // fixed size for slide
10192             this.setSize(b);
10193
10194             // wrap if needed
10195             var wrap = this.fxWrap(r.pos, o, "hidden");
10196
10197             var st = this.dom.style;
10198             st.visibility = "visible";
10199             st.position = "absolute";
10200
10201             // clear out temp styles after slide and unwrap
10202             var after = function(){
10203                 el.fxUnwrap(wrap, r.pos, o);
10204                 st.width = r.width;
10205                 st.height = r.height;
10206                 el.afterFx(o);
10207             };
10208             // time to calc the positions
10209             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10210
10211             switch(anchor.toLowerCase()){
10212                 case "t":
10213                     wrap.setSize(b.width, 0);
10214                     st.left = st.bottom = "0";
10215                     a = {height: bh};
10216                 break;
10217                 case "l":
10218                     wrap.setSize(0, b.height);
10219                     st.right = st.top = "0";
10220                     a = {width: bw};
10221                 break;
10222                 case "r":
10223                     wrap.setSize(0, b.height);
10224                     wrap.setX(b.right);
10225                     st.left = st.top = "0";
10226                     a = {width: bw, points: pt};
10227                 break;
10228                 case "b":
10229                     wrap.setSize(b.width, 0);
10230                     wrap.setY(b.bottom);
10231                     st.left = st.top = "0";
10232                     a = {height: bh, points: pt};
10233                 break;
10234                 case "tl":
10235                     wrap.setSize(0, 0);
10236                     st.right = st.bottom = "0";
10237                     a = {width: bw, height: bh};
10238                 break;
10239                 case "bl":
10240                     wrap.setSize(0, 0);
10241                     wrap.setY(b.y+b.height);
10242                     st.right = st.top = "0";
10243                     a = {width: bw, height: bh, points: pt};
10244                 break;
10245                 case "br":
10246                     wrap.setSize(0, 0);
10247                     wrap.setXY([b.right, b.bottom]);
10248                     st.left = st.top = "0";
10249                     a = {width: bw, height: bh, points: pt};
10250                 break;
10251                 case "tr":
10252                     wrap.setSize(0, 0);
10253                     wrap.setX(b.x+b.width);
10254                     st.left = st.bottom = "0";
10255                     a = {width: bw, height: bh, points: pt};
10256                 break;
10257             }
10258             this.dom.style.visibility = "visible";
10259             wrap.show();
10260
10261             arguments.callee.anim = wrap.fxanim(a,
10262                 o,
10263                 'motion',
10264                 .5,
10265                 'easeOut', after);
10266         });
10267         return this;
10268     },
10269     
10270         /**
10271          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10272          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10273          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10274          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10275          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10276          * Usage:
10277          *<pre><code>
10278 // default: slide the element out to the top
10279 el.slideOut();
10280
10281 // custom: slide the element out to the right with a 2-second duration
10282 el.slideOut('r', { duration: 2 });
10283
10284 // common config options shown with default values
10285 el.slideOut('t', {
10286     easing: 'easeOut',
10287     duration: .5,
10288     remove: false,
10289     useDisplay: false
10290 });
10291 </code></pre>
10292          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10293          * @param {Object} options (optional) Object literal with any of the Fx config options
10294          * @return {Roo.Element} The Element
10295          */
10296     slideOut : function(anchor, o){
10297         var el = this.getFxEl();
10298         o = o || {};
10299
10300         el.queueFx(o, function(){
10301
10302             anchor = anchor || "t";
10303
10304             // restore values after effect
10305             var r = this.getFxRestore();
10306             
10307             var b = this.getBox();
10308             // fixed size for slide
10309             this.setSize(b);
10310
10311             // wrap if needed
10312             var wrap = this.fxWrap(r.pos, o, "visible");
10313
10314             var st = this.dom.style;
10315             st.visibility = "visible";
10316             st.position = "absolute";
10317
10318             wrap.setSize(b);
10319
10320             var after = function(){
10321                 if(o.useDisplay){
10322                     el.setDisplayed(false);
10323                 }else{
10324                     el.hide();
10325                 }
10326
10327                 el.fxUnwrap(wrap, r.pos, o);
10328
10329                 st.width = r.width;
10330                 st.height = r.height;
10331
10332                 el.afterFx(o);
10333             };
10334
10335             var a, zero = {to: 0};
10336             switch(anchor.toLowerCase()){
10337                 case "t":
10338                     st.left = st.bottom = "0";
10339                     a = {height: zero};
10340                 break;
10341                 case "l":
10342                     st.right = st.top = "0";
10343                     a = {width: zero};
10344                 break;
10345                 case "r":
10346                     st.left = st.top = "0";
10347                     a = {width: zero, points: {to:[b.right, b.y]}};
10348                 break;
10349                 case "b":
10350                     st.left = st.top = "0";
10351                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10352                 break;
10353                 case "tl":
10354                     st.right = st.bottom = "0";
10355                     a = {width: zero, height: zero};
10356                 break;
10357                 case "bl":
10358                     st.right = st.top = "0";
10359                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10360                 break;
10361                 case "br":
10362                     st.left = st.top = "0";
10363                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10364                 break;
10365                 case "tr":
10366                     st.left = st.bottom = "0";
10367                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10368                 break;
10369             }
10370
10371             arguments.callee.anim = wrap.fxanim(a,
10372                 o,
10373                 'motion',
10374                 .5,
10375                 "easeOut", after);
10376         });
10377         return this;
10378     },
10379
10380         /**
10381          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10382          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10383          * The element must be removed from the DOM using the 'remove' config option if desired.
10384          * Usage:
10385          *<pre><code>
10386 // default
10387 el.puff();
10388
10389 // common config options shown with default values
10390 el.puff({
10391     easing: 'easeOut',
10392     duration: .5,
10393     remove: false,
10394     useDisplay: false
10395 });
10396 </code></pre>
10397          * @param {Object} options (optional) Object literal with any of the Fx config options
10398          * @return {Roo.Element} The Element
10399          */
10400     puff : function(o){
10401         var el = this.getFxEl();
10402         o = o || {};
10403
10404         el.queueFx(o, function(){
10405             this.clearOpacity();
10406             this.show();
10407
10408             // restore values after effect
10409             var r = this.getFxRestore();
10410             var st = this.dom.style;
10411
10412             var after = function(){
10413                 if(o.useDisplay){
10414                     el.setDisplayed(false);
10415                 }else{
10416                     el.hide();
10417                 }
10418
10419                 el.clearOpacity();
10420
10421                 el.setPositioning(r.pos);
10422                 st.width = r.width;
10423                 st.height = r.height;
10424                 st.fontSize = '';
10425                 el.afterFx(o);
10426             };
10427
10428             var width = this.getWidth();
10429             var height = this.getHeight();
10430
10431             arguments.callee.anim = this.fxanim({
10432                     width : {to: this.adjustWidth(width * 2)},
10433                     height : {to: this.adjustHeight(height * 2)},
10434                     points : {by: [-(width * .5), -(height * .5)]},
10435                     opacity : {to: 0},
10436                     fontSize: {to:200, unit: "%"}
10437                 },
10438                 o,
10439                 'motion',
10440                 .5,
10441                 "easeOut", after);
10442         });
10443         return this;
10444     },
10445
10446         /**
10447          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10448          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10449          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10450          * Usage:
10451          *<pre><code>
10452 // default
10453 el.switchOff();
10454
10455 // all config options shown with default values
10456 el.switchOff({
10457     easing: 'easeIn',
10458     duration: .3,
10459     remove: false,
10460     useDisplay: false
10461 });
10462 </code></pre>
10463          * @param {Object} options (optional) Object literal with any of the Fx config options
10464          * @return {Roo.Element} The Element
10465          */
10466     switchOff : function(o){
10467         var el = this.getFxEl();
10468         o = o || {};
10469
10470         el.queueFx(o, function(){
10471             this.clearOpacity();
10472             this.clip();
10473
10474             // restore values after effect
10475             var r = this.getFxRestore();
10476             var st = this.dom.style;
10477
10478             var after = function(){
10479                 if(o.useDisplay){
10480                     el.setDisplayed(false);
10481                 }else{
10482                     el.hide();
10483                 }
10484
10485                 el.clearOpacity();
10486                 el.setPositioning(r.pos);
10487                 st.width = r.width;
10488                 st.height = r.height;
10489
10490                 el.afterFx(o);
10491             };
10492
10493             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10494                 this.clearOpacity();
10495                 (function(){
10496                     this.fxanim({
10497                         height:{to:1},
10498                         points:{by:[0, this.getHeight() * .5]}
10499                     }, o, 'motion', 0.3, 'easeIn', after);
10500                 }).defer(100, this);
10501             });
10502         });
10503         return this;
10504     },
10505
10506     /**
10507      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10508      * changed using the "attr" config option) and then fading back to the original color. If no original
10509      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10510      * Usage:
10511 <pre><code>
10512 // default: highlight background to yellow
10513 el.highlight();
10514
10515 // custom: highlight foreground text to blue for 2 seconds
10516 el.highlight("0000ff", { attr: 'color', duration: 2 });
10517
10518 // common config options shown with default values
10519 el.highlight("ffff9c", {
10520     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10521     endColor: (current color) or "ffffff",
10522     easing: 'easeIn',
10523     duration: 1
10524 });
10525 </code></pre>
10526      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10527      * @param {Object} options (optional) Object literal with any of the Fx config options
10528      * @return {Roo.Element} The Element
10529      */ 
10530     highlight : function(color, o){
10531         var el = this.getFxEl();
10532         o = o || {};
10533
10534         el.queueFx(o, function(){
10535             color = color || "ffff9c";
10536             attr = o.attr || "backgroundColor";
10537
10538             this.clearOpacity();
10539             this.show();
10540
10541             var origColor = this.getColor(attr);
10542             var restoreColor = this.dom.style[attr];
10543             endColor = (o.endColor || origColor) || "ffffff";
10544
10545             var after = function(){
10546                 el.dom.style[attr] = restoreColor;
10547                 el.afterFx(o);
10548             };
10549
10550             var a = {};
10551             a[attr] = {from: color, to: endColor};
10552             arguments.callee.anim = this.fxanim(a,
10553                 o,
10554                 'color',
10555                 1,
10556                 'easeIn', after);
10557         });
10558         return this;
10559     },
10560
10561    /**
10562     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10563     * Usage:
10564 <pre><code>
10565 // default: a single light blue ripple
10566 el.frame();
10567
10568 // custom: 3 red ripples lasting 3 seconds total
10569 el.frame("ff0000", 3, { duration: 3 });
10570
10571 // common config options shown with default values
10572 el.frame("C3DAF9", 1, {
10573     duration: 1 //duration of entire animation (not each individual ripple)
10574     // Note: Easing is not configurable and will be ignored if included
10575 });
10576 </code></pre>
10577     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10578     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10579     * @param {Object} options (optional) Object literal with any of the Fx config options
10580     * @return {Roo.Element} The Element
10581     */
10582     frame : function(color, count, o){
10583         var el = this.getFxEl();
10584         o = o || {};
10585
10586         el.queueFx(o, function(){
10587             color = color || "#C3DAF9";
10588             if(color.length == 6){
10589                 color = "#" + color;
10590             }
10591             count = count || 1;
10592             duration = o.duration || 1;
10593             this.show();
10594
10595             var b = this.getBox();
10596             var animFn = function(){
10597                 var proxy = this.createProxy({
10598
10599                      style:{
10600                         visbility:"hidden",
10601                         position:"absolute",
10602                         "z-index":"35000", // yee haw
10603                         border:"0px solid " + color
10604                      }
10605                   });
10606                 var scale = Roo.isBorderBox ? 2 : 1;
10607                 proxy.animate({
10608                     top:{from:b.y, to:b.y - 20},
10609                     left:{from:b.x, to:b.x - 20},
10610                     borderWidth:{from:0, to:10},
10611                     opacity:{from:1, to:0},
10612                     height:{from:b.height, to:(b.height + (20*scale))},
10613                     width:{from:b.width, to:(b.width + (20*scale))}
10614                 }, duration, function(){
10615                     proxy.remove();
10616                 });
10617                 if(--count > 0){
10618                      animFn.defer((duration/2)*1000, this);
10619                 }else{
10620                     el.afterFx(o);
10621                 }
10622             };
10623             animFn.call(this);
10624         });
10625         return this;
10626     },
10627
10628    /**
10629     * Creates a pause before any subsequent queued effects begin.  If there are
10630     * no effects queued after the pause it will have no effect.
10631     * Usage:
10632 <pre><code>
10633 el.pause(1);
10634 </code></pre>
10635     * @param {Number} seconds The length of time to pause (in seconds)
10636     * @return {Roo.Element} The Element
10637     */
10638     pause : function(seconds){
10639         var el = this.getFxEl();
10640         var o = {};
10641
10642         el.queueFx(o, function(){
10643             setTimeout(function(){
10644                 el.afterFx(o);
10645             }, seconds * 1000);
10646         });
10647         return this;
10648     },
10649
10650    /**
10651     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10652     * using the "endOpacity" config option.
10653     * Usage:
10654 <pre><code>
10655 // default: fade in from opacity 0 to 100%
10656 el.fadeIn();
10657
10658 // custom: fade in from opacity 0 to 75% over 2 seconds
10659 el.fadeIn({ endOpacity: .75, duration: 2});
10660
10661 // common config options shown with default values
10662 el.fadeIn({
10663     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10664     easing: 'easeOut',
10665     duration: .5
10666 });
10667 </code></pre>
10668     * @param {Object} options (optional) Object literal with any of the Fx config options
10669     * @return {Roo.Element} The Element
10670     */
10671     fadeIn : function(o){
10672         var el = this.getFxEl();
10673         o = o || {};
10674         el.queueFx(o, function(){
10675             this.setOpacity(0);
10676             this.fixDisplay();
10677             this.dom.style.visibility = 'visible';
10678             var to = o.endOpacity || 1;
10679             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10680                 o, null, .5, "easeOut", function(){
10681                 if(to == 1){
10682                     this.clearOpacity();
10683                 }
10684                 el.afterFx(o);
10685             });
10686         });
10687         return this;
10688     },
10689
10690    /**
10691     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10692     * using the "endOpacity" config option.
10693     * Usage:
10694 <pre><code>
10695 // default: fade out from the element's current opacity to 0
10696 el.fadeOut();
10697
10698 // custom: fade out from the element's current opacity to 25% over 2 seconds
10699 el.fadeOut({ endOpacity: .25, duration: 2});
10700
10701 // common config options shown with default values
10702 el.fadeOut({
10703     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10704     easing: 'easeOut',
10705     duration: .5
10706     remove: false,
10707     useDisplay: false
10708 });
10709 </code></pre>
10710     * @param {Object} options (optional) Object literal with any of the Fx config options
10711     * @return {Roo.Element} The Element
10712     */
10713     fadeOut : function(o){
10714         var el = this.getFxEl();
10715         o = o || {};
10716         el.queueFx(o, function(){
10717             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10718                 o, null, .5, "easeOut", function(){
10719                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10720                      this.dom.style.display = "none";
10721                 }else{
10722                      this.dom.style.visibility = "hidden";
10723                 }
10724                 this.clearOpacity();
10725                 el.afterFx(o);
10726             });
10727         });
10728         return this;
10729     },
10730
10731    /**
10732     * Animates the transition of an element's dimensions from a starting height/width
10733     * to an ending height/width.
10734     * Usage:
10735 <pre><code>
10736 // change height and width to 100x100 pixels
10737 el.scale(100, 100);
10738
10739 // common config options shown with default values.  The height and width will default to
10740 // the element's existing values if passed as null.
10741 el.scale(
10742     [element's width],
10743     [element's height], {
10744     easing: 'easeOut',
10745     duration: .35
10746 });
10747 </code></pre>
10748     * @param {Number} width  The new width (pass undefined to keep the original width)
10749     * @param {Number} height  The new height (pass undefined to keep the original height)
10750     * @param {Object} options (optional) Object literal with any of the Fx config options
10751     * @return {Roo.Element} The Element
10752     */
10753     scale : function(w, h, o){
10754         this.shift(Roo.apply({}, o, {
10755             width: w,
10756             height: h
10757         }));
10758         return this;
10759     },
10760
10761    /**
10762     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10763     * Any of these properties not specified in the config object will not be changed.  This effect 
10764     * requires that at least one new dimension, position or opacity setting must be passed in on
10765     * the config object in order for the function to have any effect.
10766     * Usage:
10767 <pre><code>
10768 // slide the element horizontally to x position 200 while changing the height and opacity
10769 el.shift({ x: 200, height: 50, opacity: .8 });
10770
10771 // common config options shown with default values.
10772 el.shift({
10773     width: [element's width],
10774     height: [element's height],
10775     x: [element's x position],
10776     y: [element's y position],
10777     opacity: [element's opacity],
10778     easing: 'easeOut',
10779     duration: .35
10780 });
10781 </code></pre>
10782     * @param {Object} options  Object literal with any of the Fx config options
10783     * @return {Roo.Element} The Element
10784     */
10785     shift : function(o){
10786         var el = this.getFxEl();
10787         o = o || {};
10788         el.queueFx(o, function(){
10789             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10790             if(w !== undefined){
10791                 a.width = {to: this.adjustWidth(w)};
10792             }
10793             if(h !== undefined){
10794                 a.height = {to: this.adjustHeight(h)};
10795             }
10796             if(x !== undefined || y !== undefined){
10797                 a.points = {to: [
10798                     x !== undefined ? x : this.getX(),
10799                     y !== undefined ? y : this.getY()
10800                 ]};
10801             }
10802             if(op !== undefined){
10803                 a.opacity = {to: op};
10804             }
10805             if(o.xy !== undefined){
10806                 a.points = {to: o.xy};
10807             }
10808             arguments.callee.anim = this.fxanim(a,
10809                 o, 'motion', .35, "easeOut", function(){
10810                 el.afterFx(o);
10811             });
10812         });
10813         return this;
10814     },
10815
10816         /**
10817          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10818          * ending point of the effect.
10819          * Usage:
10820          *<pre><code>
10821 // default: slide the element downward while fading out
10822 el.ghost();
10823
10824 // custom: slide the element out to the right with a 2-second duration
10825 el.ghost('r', { duration: 2 });
10826
10827 // common config options shown with default values
10828 el.ghost('b', {
10829     easing: 'easeOut',
10830     duration: .5
10831     remove: false,
10832     useDisplay: false
10833 });
10834 </code></pre>
10835          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10836          * @param {Object} options (optional) Object literal with any of the Fx config options
10837          * @return {Roo.Element} The Element
10838          */
10839     ghost : function(anchor, o){
10840         var el = this.getFxEl();
10841         o = o || {};
10842
10843         el.queueFx(o, function(){
10844             anchor = anchor || "b";
10845
10846             // restore values after effect
10847             var r = this.getFxRestore();
10848             var w = this.getWidth(),
10849                 h = this.getHeight();
10850
10851             var st = this.dom.style;
10852
10853             var after = function(){
10854                 if(o.useDisplay){
10855                     el.setDisplayed(false);
10856                 }else{
10857                     el.hide();
10858                 }
10859
10860                 el.clearOpacity();
10861                 el.setPositioning(r.pos);
10862                 st.width = r.width;
10863                 st.height = r.height;
10864
10865                 el.afterFx(o);
10866             };
10867
10868             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10869             switch(anchor.toLowerCase()){
10870                 case "t":
10871                     pt.by = [0, -h];
10872                 break;
10873                 case "l":
10874                     pt.by = [-w, 0];
10875                 break;
10876                 case "r":
10877                     pt.by = [w, 0];
10878                 break;
10879                 case "b":
10880                     pt.by = [0, h];
10881                 break;
10882                 case "tl":
10883                     pt.by = [-w, -h];
10884                 break;
10885                 case "bl":
10886                     pt.by = [-w, h];
10887                 break;
10888                 case "br":
10889                     pt.by = [w, h];
10890                 break;
10891                 case "tr":
10892                     pt.by = [w, -h];
10893                 break;
10894             }
10895
10896             arguments.callee.anim = this.fxanim(a,
10897                 o,
10898                 'motion',
10899                 .5,
10900                 "easeOut", after);
10901         });
10902         return this;
10903     },
10904
10905         /**
10906          * Ensures that all effects queued after syncFx is called on the element are
10907          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10908          * @return {Roo.Element} The Element
10909          */
10910     syncFx : function(){
10911         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10912             block : false,
10913             concurrent : true,
10914             stopFx : false
10915         });
10916         return this;
10917     },
10918
10919         /**
10920          * Ensures that all effects queued after sequenceFx is called on the element are
10921          * run in sequence.  This is the opposite of {@link #syncFx}.
10922          * @return {Roo.Element} The Element
10923          */
10924     sequenceFx : function(){
10925         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10926             block : false,
10927             concurrent : false,
10928             stopFx : false
10929         });
10930         return this;
10931     },
10932
10933         /* @private */
10934     nextFx : function(){
10935         var ef = this.fxQueue[0];
10936         if(ef){
10937             ef.call(this);
10938         }
10939     },
10940
10941         /**
10942          * Returns true if the element has any effects actively running or queued, else returns false.
10943          * @return {Boolean} True if element has active effects, else false
10944          */
10945     hasActiveFx : function(){
10946         return this.fxQueue && this.fxQueue[0];
10947     },
10948
10949         /**
10950          * Stops any running effects and clears the element's internal effects queue if it contains
10951          * any additional effects that haven't started yet.
10952          * @return {Roo.Element} The Element
10953          */
10954     stopFx : function(){
10955         if(this.hasActiveFx()){
10956             var cur = this.fxQueue[0];
10957             if(cur && cur.anim && cur.anim.isAnimated()){
10958                 this.fxQueue = [cur]; // clear out others
10959                 cur.anim.stop(true);
10960             }
10961         }
10962         return this;
10963     },
10964
10965         /* @private */
10966     beforeFx : function(o){
10967         if(this.hasActiveFx() && !o.concurrent){
10968            if(o.stopFx){
10969                this.stopFx();
10970                return true;
10971            }
10972            return false;
10973         }
10974         return true;
10975     },
10976
10977         /**
10978          * Returns true if the element is currently blocking so that no other effect can be queued
10979          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10980          * used to ensure that an effect initiated by a user action runs to completion prior to the
10981          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10982          * @return {Boolean} True if blocking, else false
10983          */
10984     hasFxBlock : function(){
10985         var q = this.fxQueue;
10986         return q && q[0] && q[0].block;
10987     },
10988
10989         /* @private */
10990     queueFx : function(o, fn){
10991         if(!this.fxQueue){
10992             this.fxQueue = [];
10993         }
10994         if(!this.hasFxBlock()){
10995             Roo.applyIf(o, this.fxDefaults);
10996             if(!o.concurrent){
10997                 var run = this.beforeFx(o);
10998                 fn.block = o.block;
10999                 this.fxQueue.push(fn);
11000                 if(run){
11001                     this.nextFx();
11002                 }
11003             }else{
11004                 fn.call(this);
11005             }
11006         }
11007         return this;
11008     },
11009
11010         /* @private */
11011     fxWrap : function(pos, o, vis){
11012         var wrap;
11013         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11014             var wrapXY;
11015             if(o.fixPosition){
11016                 wrapXY = this.getXY();
11017             }
11018             var div = document.createElement("div");
11019             div.style.visibility = vis;
11020             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11021             wrap.setPositioning(pos);
11022             if(wrap.getStyle("position") == "static"){
11023                 wrap.position("relative");
11024             }
11025             this.clearPositioning('auto');
11026             wrap.clip();
11027             wrap.dom.appendChild(this.dom);
11028             if(wrapXY){
11029                 wrap.setXY(wrapXY);
11030             }
11031         }
11032         return wrap;
11033     },
11034
11035         /* @private */
11036     fxUnwrap : function(wrap, pos, o){
11037         this.clearPositioning();
11038         this.setPositioning(pos);
11039         if(!o.wrap){
11040             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11041             wrap.remove();
11042         }
11043     },
11044
11045         /* @private */
11046     getFxRestore : function(){
11047         var st = this.dom.style;
11048         return {pos: this.getPositioning(), width: st.width, height : st.height};
11049     },
11050
11051         /* @private */
11052     afterFx : function(o){
11053         if(o.afterStyle){
11054             this.applyStyles(o.afterStyle);
11055         }
11056         if(o.afterCls){
11057             this.addClass(o.afterCls);
11058         }
11059         if(o.remove === true){
11060             this.remove();
11061         }
11062         Roo.callback(o.callback, o.scope, [this]);
11063         if(!o.concurrent){
11064             this.fxQueue.shift();
11065             this.nextFx();
11066         }
11067     },
11068
11069         /* @private */
11070     getFxEl : function(){ // support for composite element fx
11071         return Roo.get(this.dom);
11072     },
11073
11074         /* @private */
11075     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11076         animType = animType || 'run';
11077         opt = opt || {};
11078         var anim = Roo.lib.Anim[animType](
11079             this.dom, args,
11080             (opt.duration || defaultDur) || .35,
11081             (opt.easing || defaultEase) || 'easeOut',
11082             function(){
11083                 Roo.callback(cb, this);
11084             },
11085             this
11086         );
11087         opt.anim = anim;
11088         return anim;
11089     }
11090 };
11091
11092 // backwords compat
11093 Roo.Fx.resize = Roo.Fx.scale;
11094
11095 //When included, Roo.Fx is automatically applied to Element so that all basic
11096 //effects are available directly via the Element API
11097 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11098  * Based on:
11099  * Ext JS Library 1.1.1
11100  * Copyright(c) 2006-2007, Ext JS, LLC.
11101  *
11102  * Originally Released Under LGPL - original licence link has changed is not relivant.
11103  *
11104  * Fork - LGPL
11105  * <script type="text/javascript">
11106  */
11107
11108
11109 /**
11110  * @class Roo.CompositeElement
11111  * Standard composite class. Creates a Roo.Element for every element in the collection.
11112  * <br><br>
11113  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11114  * actions will be performed on all the elements in this collection.</b>
11115  * <br><br>
11116  * All methods return <i>this</i> and can be chained.
11117  <pre><code>
11118  var els = Roo.select("#some-el div.some-class", true);
11119  // or select directly from an existing element
11120  var el = Roo.get('some-el');
11121  el.select('div.some-class', true);
11122
11123  els.setWidth(100); // all elements become 100 width
11124  els.hide(true); // all elements fade out and hide
11125  // or
11126  els.setWidth(100).hide(true);
11127  </code></pre>
11128  */
11129 Roo.CompositeElement = function(els){
11130     this.elements = [];
11131     this.addElements(els);
11132 };
11133 Roo.CompositeElement.prototype = {
11134     isComposite: true,
11135     addElements : function(els){
11136         if(!els) {
11137             return this;
11138         }
11139         if(typeof els == "string"){
11140             els = Roo.Element.selectorFunction(els);
11141         }
11142         var yels = this.elements;
11143         var index = yels.length-1;
11144         for(var i = 0, len = els.length; i < len; i++) {
11145                 yels[++index] = Roo.get(els[i]);
11146         }
11147         return this;
11148     },
11149
11150     /**
11151     * Clears this composite and adds the elements returned by the passed selector.
11152     * @param {String/Array} els A string CSS selector, an array of elements or an element
11153     * @return {CompositeElement} this
11154     */
11155     fill : function(els){
11156         this.elements = [];
11157         this.add(els);
11158         return this;
11159     },
11160
11161     /**
11162     * Filters this composite to only elements that match the passed selector.
11163     * @param {String} selector A string CSS selector
11164     * @param {Boolean} inverse return inverse filter (not matches)
11165     * @return {CompositeElement} this
11166     */
11167     filter : function(selector, inverse){
11168         var els = [];
11169         inverse = inverse || false;
11170         this.each(function(el){
11171             var match = inverse ? !el.is(selector) : el.is(selector);
11172             if(match){
11173                 els[els.length] = el.dom;
11174             }
11175         });
11176         this.fill(els);
11177         return this;
11178     },
11179
11180     invoke : function(fn, args){
11181         var els = this.elements;
11182         for(var i = 0, len = els.length; i < len; i++) {
11183                 Roo.Element.prototype[fn].apply(els[i], args);
11184         }
11185         return this;
11186     },
11187     /**
11188     * Adds elements to this composite.
11189     * @param {String/Array} els A string CSS selector, an array of elements or an element
11190     * @return {CompositeElement} this
11191     */
11192     add : function(els){
11193         if(typeof els == "string"){
11194             this.addElements(Roo.Element.selectorFunction(els));
11195         }else if(els.length !== undefined){
11196             this.addElements(els);
11197         }else{
11198             this.addElements([els]);
11199         }
11200         return this;
11201     },
11202     /**
11203     * Calls the passed function passing (el, this, index) for each element in this composite.
11204     * @param {Function} fn The function to call
11205     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11206     * @return {CompositeElement} this
11207     */
11208     each : function(fn, scope){
11209         var els = this.elements;
11210         for(var i = 0, len = els.length; i < len; i++){
11211             if(fn.call(scope || els[i], els[i], this, i) === false) {
11212                 break;
11213             }
11214         }
11215         return this;
11216     },
11217
11218     /**
11219      * Returns the Element object at the specified index
11220      * @param {Number} index
11221      * @return {Roo.Element}
11222      */
11223     item : function(index){
11224         return this.elements[index] || null;
11225     },
11226
11227     /**
11228      * Returns the first Element
11229      * @return {Roo.Element}
11230      */
11231     first : function(){
11232         return this.item(0);
11233     },
11234
11235     /**
11236      * Returns the last Element
11237      * @return {Roo.Element}
11238      */
11239     last : function(){
11240         return this.item(this.elements.length-1);
11241     },
11242
11243     /**
11244      * Returns the number of elements in this composite
11245      * @return Number
11246      */
11247     getCount : function(){
11248         return this.elements.length;
11249     },
11250
11251     /**
11252      * Returns true if this composite contains the passed element
11253      * @return Boolean
11254      */
11255     contains : function(el){
11256         return this.indexOf(el) !== -1;
11257     },
11258
11259     /**
11260      * Returns true if this composite contains the passed element
11261      * @return Boolean
11262      */
11263     indexOf : function(el){
11264         return this.elements.indexOf(Roo.get(el));
11265     },
11266
11267
11268     /**
11269     * Removes the specified element(s).
11270     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11271     * or an array of any of those.
11272     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11273     * @return {CompositeElement} this
11274     */
11275     removeElement : function(el, removeDom){
11276         if(el instanceof Array){
11277             for(var i = 0, len = el.length; i < len; i++){
11278                 this.removeElement(el[i]);
11279             }
11280             return this;
11281         }
11282         var index = typeof el == 'number' ? el : this.indexOf(el);
11283         if(index !== -1){
11284             if(removeDom){
11285                 var d = this.elements[index];
11286                 if(d.dom){
11287                     d.remove();
11288                 }else{
11289                     d.parentNode.removeChild(d);
11290                 }
11291             }
11292             this.elements.splice(index, 1);
11293         }
11294         return this;
11295     },
11296
11297     /**
11298     * Replaces the specified element with the passed element.
11299     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11300     * to replace.
11301     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11302     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11303     * @return {CompositeElement} this
11304     */
11305     replaceElement : function(el, replacement, domReplace){
11306         var index = typeof el == 'number' ? el : this.indexOf(el);
11307         if(index !== -1){
11308             if(domReplace){
11309                 this.elements[index].replaceWith(replacement);
11310             }else{
11311                 this.elements.splice(index, 1, Roo.get(replacement))
11312             }
11313         }
11314         return this;
11315     },
11316
11317     /**
11318      * Removes all elements.
11319      */
11320     clear : function(){
11321         this.elements = [];
11322     }
11323 };
11324 (function(){
11325     Roo.CompositeElement.createCall = function(proto, fnName){
11326         if(!proto[fnName]){
11327             proto[fnName] = function(){
11328                 return this.invoke(fnName, arguments);
11329             };
11330         }
11331     };
11332     for(var fnName in Roo.Element.prototype){
11333         if(typeof Roo.Element.prototype[fnName] == "function"){
11334             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11335         }
11336     };
11337 })();
11338 /*
11339  * Based on:
11340  * Ext JS Library 1.1.1
11341  * Copyright(c) 2006-2007, Ext JS, LLC.
11342  *
11343  * Originally Released Under LGPL - original licence link has changed is not relivant.
11344  *
11345  * Fork - LGPL
11346  * <script type="text/javascript">
11347  */
11348
11349 /**
11350  * @class Roo.CompositeElementLite
11351  * @extends Roo.CompositeElement
11352  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11353  <pre><code>
11354  var els = Roo.select("#some-el div.some-class");
11355  // or select directly from an existing element
11356  var el = Roo.get('some-el');
11357  el.select('div.some-class');
11358
11359  els.setWidth(100); // all elements become 100 width
11360  els.hide(true); // all elements fade out and hide
11361  // or
11362  els.setWidth(100).hide(true);
11363  </code></pre><br><br>
11364  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11365  * actions will be performed on all the elements in this collection.</b>
11366  */
11367 Roo.CompositeElementLite = function(els){
11368     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11369     this.el = new Roo.Element.Flyweight();
11370 };
11371 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11372     addElements : function(els){
11373         if(els){
11374             if(els instanceof Array){
11375                 this.elements = this.elements.concat(els);
11376             }else{
11377                 var yels = this.elements;
11378                 var index = yels.length-1;
11379                 for(var i = 0, len = els.length; i < len; i++) {
11380                     yels[++index] = els[i];
11381                 }
11382             }
11383         }
11384         return this;
11385     },
11386     invoke : function(fn, args){
11387         var els = this.elements;
11388         var el = this.el;
11389         for(var i = 0, len = els.length; i < len; i++) {
11390             el.dom = els[i];
11391                 Roo.Element.prototype[fn].apply(el, args);
11392         }
11393         return this;
11394     },
11395     /**
11396      * Returns a flyweight Element of the dom element object at the specified index
11397      * @param {Number} index
11398      * @return {Roo.Element}
11399      */
11400     item : function(index){
11401         if(!this.elements[index]){
11402             return null;
11403         }
11404         this.el.dom = this.elements[index];
11405         return this.el;
11406     },
11407
11408     // fixes scope with flyweight
11409     addListener : function(eventName, handler, scope, opt){
11410         var els = this.elements;
11411         for(var i = 0, len = els.length; i < len; i++) {
11412             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11413         }
11414         return this;
11415     },
11416
11417     /**
11418     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11419     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11420     * a reference to the dom node, use el.dom.</b>
11421     * @param {Function} fn The function to call
11422     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11423     * @return {CompositeElement} this
11424     */
11425     each : function(fn, scope){
11426         var els = this.elements;
11427         var el = this.el;
11428         for(var i = 0, len = els.length; i < len; i++){
11429             el.dom = els[i];
11430                 if(fn.call(scope || el, el, this, i) === false){
11431                 break;
11432             }
11433         }
11434         return this;
11435     },
11436
11437     indexOf : function(el){
11438         return this.elements.indexOf(Roo.getDom(el));
11439     },
11440
11441     replaceElement : function(el, replacement, domReplace){
11442         var index = typeof el == 'number' ? el : this.indexOf(el);
11443         if(index !== -1){
11444             replacement = Roo.getDom(replacement);
11445             if(domReplace){
11446                 var d = this.elements[index];
11447                 d.parentNode.insertBefore(replacement, d);
11448                 d.parentNode.removeChild(d);
11449             }
11450             this.elements.splice(index, 1, replacement);
11451         }
11452         return this;
11453     }
11454 });
11455 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11456
11457 /*
11458  * Based on:
11459  * Ext JS Library 1.1.1
11460  * Copyright(c) 2006-2007, Ext JS, LLC.
11461  *
11462  * Originally Released Under LGPL - original licence link has changed is not relivant.
11463  *
11464  * Fork - LGPL
11465  * <script type="text/javascript">
11466  */
11467
11468  
11469
11470 /**
11471  * @class Roo.data.Connection
11472  * @extends Roo.util.Observable
11473  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11474  * either to a configured URL, or to a URL specified at request time.<br><br>
11475  * <p>
11476  * Requests made by this class are asynchronous, and will return immediately. No data from
11477  * the server will be available to the statement immediately following the {@link #request} call.
11478  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11479  * <p>
11480  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11481  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11482  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11483  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11484  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11485  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11486  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11487  * standard DOM methods.
11488  * @constructor
11489  * @param {Object} config a configuration object.
11490  */
11491 Roo.data.Connection = function(config){
11492     Roo.apply(this, config);
11493     this.addEvents({
11494         /**
11495          * @event beforerequest
11496          * Fires before a network request is made to retrieve a data object.
11497          * @param {Connection} conn This Connection object.
11498          * @param {Object} options The options config object passed to the {@link #request} method.
11499          */
11500         "beforerequest" : true,
11501         /**
11502          * @event requestcomplete
11503          * Fires if the request was successfully completed.
11504          * @param {Connection} conn This Connection object.
11505          * @param {Object} response The XHR object containing the response data.
11506          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11507          * @param {Object} options The options config object passed to the {@link #request} method.
11508          */
11509         "requestcomplete" : true,
11510         /**
11511          * @event requestexception
11512          * Fires if an error HTTP status was returned from the server.
11513          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11514          * @param {Connection} conn This Connection object.
11515          * @param {Object} response The XHR object containing the response data.
11516          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11517          * @param {Object} options The options config object passed to the {@link #request} method.
11518          */
11519         "requestexception" : true
11520     });
11521     Roo.data.Connection.superclass.constructor.call(this);
11522 };
11523
11524 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11525     /**
11526      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11527      */
11528     /**
11529      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11530      * extra parameters to each request made by this object. (defaults to undefined)
11531      */
11532     /**
11533      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11534      *  to each request made by this object. (defaults to undefined)
11535      */
11536     /**
11537      * @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)
11538      */
11539     /**
11540      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11541      */
11542     timeout : 30000,
11543     /**
11544      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11545      * @type Boolean
11546      */
11547     autoAbort:false,
11548
11549     /**
11550      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11551      * @type Boolean
11552      */
11553     disableCaching: true,
11554
11555     /**
11556      * Sends an HTTP request to a remote server.
11557      * @param {Object} options An object which may contain the following properties:<ul>
11558      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11559      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11560      * request, a url encoded string or a function to call to get either.</li>
11561      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11562      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11563      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11564      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11565      * <li>options {Object} The parameter to the request call.</li>
11566      * <li>success {Boolean} True if the request succeeded.</li>
11567      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11568      * </ul></li>
11569      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11570      * The callback is passed the following parameters:<ul>
11571      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11572      * <li>options {Object} The parameter to the request call.</li>
11573      * </ul></li>
11574      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11575      * The callback is passed the following parameters:<ul>
11576      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11577      * <li>options {Object} The parameter to the request call.</li>
11578      * </ul></li>
11579      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11580      * for the callback function. Defaults to the browser window.</li>
11581      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11582      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11583      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11584      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11585      * params for the post data. Any params will be appended to the URL.</li>
11586      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11587      * </ul>
11588      * @return {Number} transactionId
11589      */
11590     request : function(o){
11591         if(this.fireEvent("beforerequest", this, o) !== false){
11592             var p = o.params;
11593
11594             if(typeof p == "function"){
11595                 p = p.call(o.scope||window, o);
11596             }
11597             if(typeof p == "object"){
11598                 p = Roo.urlEncode(o.params);
11599             }
11600             if(this.extraParams){
11601                 var extras = Roo.urlEncode(this.extraParams);
11602                 p = p ? (p + '&' + extras) : extras;
11603             }
11604
11605             var url = o.url || this.url;
11606             if(typeof url == 'function'){
11607                 url = url.call(o.scope||window, o);
11608             }
11609
11610             if(o.form){
11611                 var form = Roo.getDom(o.form);
11612                 url = url || form.action;
11613
11614                 var enctype = form.getAttribute("enctype");
11615                 
11616                 if (o.formData) {
11617                     return this.doFormDataUpload(o,p,url);
11618                 }
11619                 
11620                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11621                     return this.doFormUpload(o, p, url);
11622                 }
11623                 var f = Roo.lib.Ajax.serializeForm(form);
11624                 p = p ? (p + '&' + f) : f;
11625             }
11626
11627             var hs = o.headers;
11628             if(this.defaultHeaders){
11629                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11630                 if(!o.headers){
11631                     o.headers = hs;
11632                 }
11633             }
11634
11635             var cb = {
11636                 success: this.handleResponse,
11637                 failure: this.handleFailure,
11638                 scope: this,
11639                 argument: {options: o},
11640                 timeout : o.timeout || this.timeout
11641             };
11642
11643             var method = o.method||this.method||(p ? "POST" : "GET");
11644
11645             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11646                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11647             }
11648
11649             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11650                 if(o.autoAbort){
11651                     this.abort();
11652                 }
11653             }else if(this.autoAbort !== false){
11654                 this.abort();
11655             }
11656
11657             if((method == 'GET' && p) || o.xmlData){
11658                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11659                 p = '';
11660             }
11661             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11662             return this.transId;
11663         }else{
11664             Roo.callback(o.callback, o.scope, [o, null, null]);
11665             return null;
11666         }
11667     },
11668
11669     /**
11670      * Determine whether this object has a request outstanding.
11671      * @param {Number} transactionId (Optional) defaults to the last transaction
11672      * @return {Boolean} True if there is an outstanding request.
11673      */
11674     isLoading : function(transId){
11675         if(transId){
11676             return Roo.lib.Ajax.isCallInProgress(transId);
11677         }else{
11678             return this.transId ? true : false;
11679         }
11680     },
11681
11682     /**
11683      * Aborts any outstanding request.
11684      * @param {Number} transactionId (Optional) defaults to the last transaction
11685      */
11686     abort : function(transId){
11687         if(transId || this.isLoading()){
11688             Roo.lib.Ajax.abort(transId || this.transId);
11689         }
11690     },
11691
11692     // private
11693     handleResponse : function(response){
11694         this.transId = false;
11695         var options = response.argument.options;
11696         response.argument = options ? options.argument : null;
11697         this.fireEvent("requestcomplete", this, response, options);
11698         Roo.callback(options.success, options.scope, [response, options]);
11699         Roo.callback(options.callback, options.scope, [options, true, response]);
11700     },
11701
11702     // private
11703     handleFailure : function(response, e){
11704         this.transId = false;
11705         var options = response.argument.options;
11706         response.argument = options ? options.argument : null;
11707         this.fireEvent("requestexception", this, response, options, e);
11708         Roo.callback(options.failure, options.scope, [response, options]);
11709         Roo.callback(options.callback, options.scope, [options, false, response]);
11710     },
11711
11712     // private
11713     doFormUpload : function(o, ps, url){
11714         var id = Roo.id();
11715         var frame = document.createElement('iframe');
11716         frame.id = id;
11717         frame.name = id;
11718         frame.className = 'x-hidden';
11719         if(Roo.isIE){
11720             frame.src = Roo.SSL_SECURE_URL;
11721         }
11722         document.body.appendChild(frame);
11723
11724         if(Roo.isIE){
11725            document.frames[id].name = id;
11726         }
11727
11728         var form = Roo.getDom(o.form);
11729         form.target = id;
11730         form.method = 'POST';
11731         form.enctype = form.encoding = 'multipart/form-data';
11732         if(url){
11733             form.action = url;
11734         }
11735
11736         var hiddens, hd;
11737         if(ps){ // add dynamic params
11738             hiddens = [];
11739             ps = Roo.urlDecode(ps, false);
11740             for(var k in ps){
11741                 if(ps.hasOwnProperty(k)){
11742                     hd = document.createElement('input');
11743                     hd.type = 'hidden';
11744                     hd.name = k;
11745                     hd.value = ps[k];
11746                     form.appendChild(hd);
11747                     hiddens.push(hd);
11748                 }
11749             }
11750         }
11751
11752         function cb(){
11753             var r = {  // bogus response object
11754                 responseText : '',
11755                 responseXML : null
11756             };
11757
11758             r.argument = o ? o.argument : null;
11759
11760             try { //
11761                 var doc;
11762                 if(Roo.isIE){
11763                     doc = frame.contentWindow.document;
11764                 }else {
11765                     doc = (frame.contentDocument || window.frames[id].document);
11766                 }
11767                 if(doc && doc.body){
11768                     r.responseText = doc.body.innerHTML;
11769                 }
11770                 if(doc && doc.XMLDocument){
11771                     r.responseXML = doc.XMLDocument;
11772                 }else {
11773                     r.responseXML = doc;
11774                 }
11775             }
11776             catch(e) {
11777                 // ignore
11778             }
11779
11780             Roo.EventManager.removeListener(frame, 'load', cb, this);
11781
11782             this.fireEvent("requestcomplete", this, r, o);
11783             Roo.callback(o.success, o.scope, [r, o]);
11784             Roo.callback(o.callback, o.scope, [o, true, r]);
11785
11786             setTimeout(function(){document.body.removeChild(frame);}, 100);
11787         }
11788
11789         Roo.EventManager.on(frame, 'load', cb, this);
11790         form.submit();
11791
11792         if(hiddens){ // remove dynamic params
11793             for(var i = 0, len = hiddens.length; i < len; i++){
11794                 form.removeChild(hiddens[i]);
11795             }
11796         }
11797     },
11798     // this is a 'formdata version???'
11799     
11800     
11801     doFormDataUpload : function(o, ps, url)
11802     {
11803         var formData = o.formData === true ? new FormData(Roo.getDom(o.form)) : o.formData;
11804       
11805         var cb = {
11806             success: this.handleResponse,
11807             failure: this.handleFailure,
11808             scope: this,
11809             argument: {options: o},
11810             timeout : o.timeout || this.timeout
11811         };
11812  
11813         if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11814             if(o.autoAbort){
11815                 this.abort();
11816             }
11817         }else if(this.autoAbort !== false){
11818             this.abort();
11819         }
11820
11821        
11822         this.transId = Roo.lib.Ajax.request( "POST", url, cb, o.formData, o);
11823  
11824  
11825          
11826     }
11827     
11828 });
11829 /*
11830  * Based on:
11831  * Ext JS Library 1.1.1
11832  * Copyright(c) 2006-2007, Ext JS, LLC.
11833  *
11834  * Originally Released Under LGPL - original licence link has changed is not relivant.
11835  *
11836  * Fork - LGPL
11837  * <script type="text/javascript">
11838  */
11839  
11840 /**
11841  * Global Ajax request class.
11842  * 
11843  * @class Roo.Ajax
11844  * @extends Roo.data.Connection
11845  * @static
11846  * 
11847  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11848  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11849  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11850  * @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)
11851  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11852  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11853  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11854  */
11855 Roo.Ajax = new Roo.data.Connection({
11856     // fix up the docs
11857     /**
11858      * @scope Roo.Ajax
11859      * @type {Boolear} 
11860      */
11861     autoAbort : false,
11862
11863     /**
11864      * Serialize the passed form into a url encoded string
11865      * @scope Roo.Ajax
11866      * @param {String/HTMLElement} form
11867      * @return {String}
11868      */
11869     serializeForm : function(form){
11870         return Roo.lib.Ajax.serializeForm(form);
11871     }
11872 });/*
11873  * Based on:
11874  * Ext JS Library 1.1.1
11875  * Copyright(c) 2006-2007, Ext JS, LLC.
11876  *
11877  * Originally Released Under LGPL - original licence link has changed is not relivant.
11878  *
11879  * Fork - LGPL
11880  * <script type="text/javascript">
11881  */
11882
11883  
11884 /**
11885  * @class Roo.UpdateManager
11886  * @extends Roo.util.Observable
11887  * Provides AJAX-style update for Element object.<br><br>
11888  * Usage:<br>
11889  * <pre><code>
11890  * // Get it from a Roo.Element object
11891  * var el = Roo.get("foo");
11892  * var mgr = el.getUpdateManager();
11893  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11894  * ...
11895  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11896  * <br>
11897  * // or directly (returns the same UpdateManager instance)
11898  * var mgr = new Roo.UpdateManager("myElementId");
11899  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11900  * mgr.on("update", myFcnNeedsToKnow);
11901  * <br>
11902    // short handed call directly from the element object
11903    Roo.get("foo").load({
11904         url: "bar.php",
11905         scripts:true,
11906         params: "for=bar",
11907         text: "Loading Foo..."
11908    });
11909  * </code></pre>
11910  * @constructor
11911  * Create new UpdateManager directly.
11912  * @param {String/HTMLElement/Roo.Element} el The element to update
11913  * @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).
11914  */
11915 Roo.UpdateManager = function(el, forceNew){
11916     el = Roo.get(el);
11917     if(!forceNew && el.updateManager){
11918         return el.updateManager;
11919     }
11920     /**
11921      * The Element object
11922      * @type Roo.Element
11923      */
11924     this.el = el;
11925     /**
11926      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11927      * @type String
11928      */
11929     this.defaultUrl = null;
11930
11931     this.addEvents({
11932         /**
11933          * @event beforeupdate
11934          * Fired before an update is made, return false from your handler and the update is cancelled.
11935          * @param {Roo.Element} el
11936          * @param {String/Object/Function} url
11937          * @param {String/Object} params
11938          */
11939         "beforeupdate": true,
11940         /**
11941          * @event update
11942          * Fired after successful update is made.
11943          * @param {Roo.Element} el
11944          * @param {Object} oResponseObject The response Object
11945          */
11946         "update": true,
11947         /**
11948          * @event failure
11949          * Fired on update failure.
11950          * @param {Roo.Element} el
11951          * @param {Object} oResponseObject The response Object
11952          */
11953         "failure": true
11954     });
11955     var d = Roo.UpdateManager.defaults;
11956     /**
11957      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11958      * @type String
11959      */
11960     this.sslBlankUrl = d.sslBlankUrl;
11961     /**
11962      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11963      * @type Boolean
11964      */
11965     this.disableCaching = d.disableCaching;
11966     /**
11967      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11968      * @type String
11969      */
11970     this.indicatorText = d.indicatorText;
11971     /**
11972      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11973      * @type String
11974      */
11975     this.showLoadIndicator = d.showLoadIndicator;
11976     /**
11977      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11978      * @type Number
11979      */
11980     this.timeout = d.timeout;
11981
11982     /**
11983      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11984      * @type Boolean
11985      */
11986     this.loadScripts = d.loadScripts;
11987
11988     /**
11989      * Transaction object of current executing transaction
11990      */
11991     this.transaction = null;
11992
11993     /**
11994      * @private
11995      */
11996     this.autoRefreshProcId = null;
11997     /**
11998      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11999      * @type Function
12000      */
12001     this.refreshDelegate = this.refresh.createDelegate(this);
12002     /**
12003      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12004      * @type Function
12005      */
12006     this.updateDelegate = this.update.createDelegate(this);
12007     /**
12008      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12009      * @type Function
12010      */
12011     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12012     /**
12013      * @private
12014      */
12015     this.successDelegate = this.processSuccess.createDelegate(this);
12016     /**
12017      * @private
12018      */
12019     this.failureDelegate = this.processFailure.createDelegate(this);
12020
12021     if(!this.renderer){
12022      /**
12023       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12024       */
12025     this.renderer = new Roo.UpdateManager.BasicRenderer();
12026     }
12027     
12028     Roo.UpdateManager.superclass.constructor.call(this);
12029 };
12030
12031 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12032     /**
12033      * Get the Element this UpdateManager is bound to
12034      * @return {Roo.Element} The element
12035      */
12036     getEl : function(){
12037         return this.el;
12038     },
12039     /**
12040      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12041      * @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:
12042 <pre><code>
12043 um.update({<br/>
12044     url: "your-url.php",<br/>
12045     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12046     callback: yourFunction,<br/>
12047     scope: yourObject, //(optional scope)  <br/>
12048     discardUrl: false, <br/>
12049     nocache: false,<br/>
12050     text: "Loading...",<br/>
12051     timeout: 30,<br/>
12052     scripts: false<br/>
12053 });
12054 </code></pre>
12055      * The only required property is url. The optional properties nocache, text and scripts
12056      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12057      * @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}
12058      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12059      * @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.
12060      */
12061     update : function(url, params, callback, discardUrl){
12062         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12063             var method = this.method,
12064                 cfg;
12065             if(typeof url == "object"){ // must be config object
12066                 cfg = url;
12067                 url = cfg.url;
12068                 params = params || cfg.params;
12069                 callback = callback || cfg.callback;
12070                 discardUrl = discardUrl || cfg.discardUrl;
12071                 if(callback && cfg.scope){
12072                     callback = callback.createDelegate(cfg.scope);
12073                 }
12074                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12075                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12076                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12077                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12078                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12079             }
12080             this.showLoading();
12081             if(!discardUrl){
12082                 this.defaultUrl = url;
12083             }
12084             if(typeof url == "function"){
12085                 url = url.call(this);
12086             }
12087
12088             method = method || (params ? "POST" : "GET");
12089             if(method == "GET"){
12090                 url = this.prepareUrl(url);
12091             }
12092
12093             var o = Roo.apply(cfg ||{}, {
12094                 url : url,
12095                 params: params,
12096                 success: this.successDelegate,
12097                 failure: this.failureDelegate,
12098                 callback: undefined,
12099                 timeout: (this.timeout*1000),
12100                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12101             });
12102             Roo.log("updated manager called with timeout of " + o.timeout);
12103             this.transaction = Roo.Ajax.request(o);
12104         }
12105     },
12106
12107     /**
12108      * 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.
12109      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12110      * @param {String/HTMLElement} form The form Id or form element
12111      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12112      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12113      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12114      */
12115     formUpdate : function(form, url, reset, callback){
12116         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12117             if(typeof url == "function"){
12118                 url = url.call(this);
12119             }
12120             form = Roo.getDom(form);
12121             this.transaction = Roo.Ajax.request({
12122                 form: form,
12123                 url:url,
12124                 success: this.successDelegate,
12125                 failure: this.failureDelegate,
12126                 timeout: (this.timeout*1000),
12127                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12128             });
12129             this.showLoading.defer(1, this);
12130         }
12131     },
12132
12133     /**
12134      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12135      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12136      */
12137     refresh : function(callback){
12138         if(this.defaultUrl == null){
12139             return;
12140         }
12141         this.update(this.defaultUrl, null, callback, true);
12142     },
12143
12144     /**
12145      * Set this element to auto refresh.
12146      * @param {Number} interval How often to update (in seconds).
12147      * @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)
12148      * @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}
12149      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12150      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12151      */
12152     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12153         if(refreshNow){
12154             this.update(url || this.defaultUrl, params, callback, true);
12155         }
12156         if(this.autoRefreshProcId){
12157             clearInterval(this.autoRefreshProcId);
12158         }
12159         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12160     },
12161
12162     /**
12163      * Stop auto refresh on this element.
12164      */
12165      stopAutoRefresh : function(){
12166         if(this.autoRefreshProcId){
12167             clearInterval(this.autoRefreshProcId);
12168             delete this.autoRefreshProcId;
12169         }
12170     },
12171
12172     isAutoRefreshing : function(){
12173        return this.autoRefreshProcId ? true : false;
12174     },
12175     /**
12176      * Called to update the element to "Loading" state. Override to perform custom action.
12177      */
12178     showLoading : function(){
12179         if(this.showLoadIndicator){
12180             this.el.update(this.indicatorText);
12181         }
12182     },
12183
12184     /**
12185      * Adds unique parameter to query string if disableCaching = true
12186      * @private
12187      */
12188     prepareUrl : function(url){
12189         if(this.disableCaching){
12190             var append = "_dc=" + (new Date().getTime());
12191             if(url.indexOf("?") !== -1){
12192                 url += "&" + append;
12193             }else{
12194                 url += "?" + append;
12195             }
12196         }
12197         return url;
12198     },
12199
12200     /**
12201      * @private
12202      */
12203     processSuccess : function(response){
12204         this.transaction = null;
12205         if(response.argument.form && response.argument.reset){
12206             try{ // put in try/catch since some older FF releases had problems with this
12207                 response.argument.form.reset();
12208             }catch(e){}
12209         }
12210         if(this.loadScripts){
12211             this.renderer.render(this.el, response, this,
12212                 this.updateComplete.createDelegate(this, [response]));
12213         }else{
12214             this.renderer.render(this.el, response, this);
12215             this.updateComplete(response);
12216         }
12217     },
12218
12219     updateComplete : function(response){
12220         this.fireEvent("update", this.el, response);
12221         if(typeof response.argument.callback == "function"){
12222             response.argument.callback(this.el, true, response);
12223         }
12224     },
12225
12226     /**
12227      * @private
12228      */
12229     processFailure : function(response){
12230         this.transaction = null;
12231         this.fireEvent("failure", this.el, response);
12232         if(typeof response.argument.callback == "function"){
12233             response.argument.callback(this.el, false, response);
12234         }
12235     },
12236
12237     /**
12238      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12239      * @param {Object} renderer The object implementing the render() method
12240      */
12241     setRenderer : function(renderer){
12242         this.renderer = renderer;
12243     },
12244
12245     getRenderer : function(){
12246        return this.renderer;
12247     },
12248
12249     /**
12250      * Set the defaultUrl used for updates
12251      * @param {String/Function} defaultUrl The url or a function to call to get the url
12252      */
12253     setDefaultUrl : function(defaultUrl){
12254         this.defaultUrl = defaultUrl;
12255     },
12256
12257     /**
12258      * Aborts the executing transaction
12259      */
12260     abort : function(){
12261         if(this.transaction){
12262             Roo.Ajax.abort(this.transaction);
12263         }
12264     },
12265
12266     /**
12267      * Returns true if an update is in progress
12268      * @return {Boolean}
12269      */
12270     isUpdating : function(){
12271         if(this.transaction){
12272             return Roo.Ajax.isLoading(this.transaction);
12273         }
12274         return false;
12275     }
12276 });
12277
12278 /**
12279  * @class Roo.UpdateManager.defaults
12280  * @static (not really - but it helps the doc tool)
12281  * The defaults collection enables customizing the default properties of UpdateManager
12282  */
12283    Roo.UpdateManager.defaults = {
12284        /**
12285          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12286          * @type Number
12287          */
12288          timeout : 30,
12289
12290          /**
12291          * True to process scripts by default (Defaults to false).
12292          * @type Boolean
12293          */
12294         loadScripts : false,
12295
12296         /**
12297         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12298         * @type String
12299         */
12300         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12301         /**
12302          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12303          * @type Boolean
12304          */
12305         disableCaching : false,
12306         /**
12307          * Whether to show indicatorText when loading (Defaults to true).
12308          * @type Boolean
12309          */
12310         showLoadIndicator : true,
12311         /**
12312          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12313          * @type String
12314          */
12315         indicatorText : '<div class="loading-indicator">Loading...</div>'
12316    };
12317
12318 /**
12319  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12320  *Usage:
12321  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12322  * @param {String/HTMLElement/Roo.Element} el The element to update
12323  * @param {String} url The url
12324  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12325  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12326  * @static
12327  * @deprecated
12328  * @member Roo.UpdateManager
12329  */
12330 Roo.UpdateManager.updateElement = function(el, url, params, options){
12331     var um = Roo.get(el, true).getUpdateManager();
12332     Roo.apply(um, options);
12333     um.update(url, params, options ? options.callback : null);
12334 };
12335 // alias for backwards compat
12336 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12337 /**
12338  * @class Roo.UpdateManager.BasicRenderer
12339  * Default Content renderer. Updates the elements innerHTML with the responseText.
12340  */
12341 Roo.UpdateManager.BasicRenderer = function(){};
12342
12343 Roo.UpdateManager.BasicRenderer.prototype = {
12344     /**
12345      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12346      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12347      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12348      * @param {Roo.Element} el The element being rendered
12349      * @param {Object} response The YUI Connect response object
12350      * @param {UpdateManager} updateManager The calling update manager
12351      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12352      */
12353      render : function(el, response, updateManager, callback){
12354         el.update(response.responseText, updateManager.loadScripts, callback);
12355     }
12356 };
12357 /*
12358  * Based on:
12359  * Roo JS
12360  * (c)) Alan Knowles
12361  * Licence : LGPL
12362  */
12363
12364
12365 /**
12366  * @class Roo.DomTemplate
12367  * @extends Roo.Template
12368  * An effort at a dom based template engine..
12369  *
12370  * Similar to XTemplate, except it uses dom parsing to create the template..
12371  *
12372  * Supported features:
12373  *
12374  *  Tags:
12375
12376 <pre><code>
12377       {a_variable} - output encoded.
12378       {a_variable.format:("Y-m-d")} - call a method on the variable
12379       {a_variable:raw} - unencoded output
12380       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12381       {a_variable:this.method_on_template(...)} - call a method on the template object.
12382  
12383 </code></pre>
12384  *  The tpl tag:
12385 <pre><code>
12386         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12387         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12388         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12389         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12390   
12391 </code></pre>
12392  *      
12393  */
12394 Roo.DomTemplate = function()
12395 {
12396      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12397      if (this.html) {
12398         this.compile();
12399      }
12400 };
12401
12402
12403 Roo.extend(Roo.DomTemplate, Roo.Template, {
12404     /**
12405      * id counter for sub templates.
12406      */
12407     id : 0,
12408     /**
12409      * flag to indicate if dom parser is inside a pre,
12410      * it will strip whitespace if not.
12411      */
12412     inPre : false,
12413     
12414     /**
12415      * The various sub templates
12416      */
12417     tpls : false,
12418     
12419     
12420     
12421     /**
12422      *
12423      * basic tag replacing syntax
12424      * WORD:WORD()
12425      *
12426      * // you can fake an object call by doing this
12427      *  x.t:(test,tesT) 
12428      * 
12429      */
12430     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12431     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12432     
12433     iterChild : function (node, method) {
12434         
12435         var oldPre = this.inPre;
12436         if (node.tagName == 'PRE') {
12437             this.inPre = true;
12438         }
12439         for( var i = 0; i < node.childNodes.length; i++) {
12440             method.call(this, node.childNodes[i]);
12441         }
12442         this.inPre = oldPre;
12443     },
12444     
12445     
12446     
12447     /**
12448      * compile the template
12449      *
12450      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12451      *
12452      */
12453     compile: function()
12454     {
12455         var s = this.html;
12456         
12457         // covert the html into DOM...
12458         var doc = false;
12459         var div =false;
12460         try {
12461             doc = document.implementation.createHTMLDocument("");
12462             doc.documentElement.innerHTML =   this.html  ;
12463             div = doc.documentElement;
12464         } catch (e) {
12465             // old IE... - nasty -- it causes all sorts of issues.. with
12466             // images getting pulled from server..
12467             div = document.createElement('div');
12468             div.innerHTML = this.html;
12469         }
12470         //doc.documentElement.innerHTML = htmlBody
12471          
12472         
12473         
12474         this.tpls = [];
12475         var _t = this;
12476         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12477         
12478         var tpls = this.tpls;
12479         
12480         // create a top level template from the snippet..
12481         
12482         //Roo.log(div.innerHTML);
12483         
12484         var tpl = {
12485             uid : 'master',
12486             id : this.id++,
12487             attr : false,
12488             value : false,
12489             body : div.innerHTML,
12490             
12491             forCall : false,
12492             execCall : false,
12493             dom : div,
12494             isTop : true
12495             
12496         };
12497         tpls.unshift(tpl);
12498         
12499         
12500         // compile them...
12501         this.tpls = [];
12502         Roo.each(tpls, function(tp){
12503             this.compileTpl(tp);
12504             this.tpls[tp.id] = tp;
12505         }, this);
12506         
12507         this.master = tpls[0];
12508         return this;
12509         
12510         
12511     },
12512     
12513     compileNode : function(node, istop) {
12514         // test for
12515         //Roo.log(node);
12516         
12517         
12518         // skip anything not a tag..
12519         if (node.nodeType != 1) {
12520             if (node.nodeType == 3 && !this.inPre) {
12521                 // reduce white space..
12522                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12523                 
12524             }
12525             return;
12526         }
12527         
12528         var tpl = {
12529             uid : false,
12530             id : false,
12531             attr : false,
12532             value : false,
12533             body : '',
12534             
12535             forCall : false,
12536             execCall : false,
12537             dom : false,
12538             isTop : istop
12539             
12540             
12541         };
12542         
12543         
12544         switch(true) {
12545             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12546             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12547             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12548             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12549             // no default..
12550         }
12551         
12552         
12553         if (!tpl.attr) {
12554             // just itterate children..
12555             this.iterChild(node,this.compileNode);
12556             return;
12557         }
12558         tpl.uid = this.id++;
12559         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12560         node.removeAttribute('roo-'+ tpl.attr);
12561         if (tpl.attr != 'name') {
12562             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12563             node.parentNode.replaceChild(placeholder,  node);
12564         } else {
12565             
12566             var placeholder =  document.createElement('span');
12567             placeholder.className = 'roo-tpl-' + tpl.value;
12568             node.parentNode.replaceChild(placeholder,  node);
12569         }
12570         
12571         // parent now sees '{domtplXXXX}
12572         this.iterChild(node,this.compileNode);
12573         
12574         // we should now have node body...
12575         var div = document.createElement('div');
12576         div.appendChild(node);
12577         tpl.dom = node;
12578         // this has the unfortunate side effect of converting tagged attributes
12579         // eg. href="{...}" into %7C...%7D
12580         // this has been fixed by searching for those combo's although it's a bit hacky..
12581         
12582         
12583         tpl.body = div.innerHTML;
12584         
12585         
12586          
12587         tpl.id = tpl.uid;
12588         switch(tpl.attr) {
12589             case 'for' :
12590                 switch (tpl.value) {
12591                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12592                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12593                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12594                 }
12595                 break;
12596             
12597             case 'exec':
12598                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12599                 break;
12600             
12601             case 'if':     
12602                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12603                 break;
12604             
12605             case 'name':
12606                 tpl.id  = tpl.value; // replace non characters???
12607                 break;
12608             
12609         }
12610         
12611         
12612         this.tpls.push(tpl);
12613         
12614         
12615         
12616     },
12617     
12618     
12619     
12620     
12621     /**
12622      * Compile a segment of the template into a 'sub-template'
12623      *
12624      * 
12625      * 
12626      *
12627      */
12628     compileTpl : function(tpl)
12629     {
12630         var fm = Roo.util.Format;
12631         var useF = this.disableFormats !== true;
12632         
12633         var sep = Roo.isGecko ? "+\n" : ",\n";
12634         
12635         var undef = function(str) {
12636             Roo.debug && Roo.log("Property not found :"  + str);
12637             return '';
12638         };
12639           
12640         //Roo.log(tpl.body);
12641         
12642         
12643         
12644         var fn = function(m, lbrace, name, format, args)
12645         {
12646             //Roo.log("ARGS");
12647             //Roo.log(arguments);
12648             args = args ? args.replace(/\\'/g,"'") : args;
12649             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12650             if (typeof(format) == 'undefined') {
12651                 format =  'htmlEncode'; 
12652             }
12653             if (format == 'raw' ) {
12654                 format = false;
12655             }
12656             
12657             if(name.substr(0, 6) == 'domtpl'){
12658                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12659             }
12660             
12661             // build an array of options to determine if value is undefined..
12662             
12663             // basically get 'xxxx.yyyy' then do
12664             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12665             //    (function () { Roo.log("Property not found"); return ''; })() :
12666             //    ......
12667             
12668             var udef_ar = [];
12669             var lookfor = '';
12670             Roo.each(name.split('.'), function(st) {
12671                 lookfor += (lookfor.length ? '.': '') + st;
12672                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12673             });
12674             
12675             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12676             
12677             
12678             if(format && useF){
12679                 
12680                 args = args ? ',' + args : "";
12681                  
12682                 if(format.substr(0, 5) != "this."){
12683                     format = "fm." + format + '(';
12684                 }else{
12685                     format = 'this.call("'+ format.substr(5) + '", ';
12686                     args = ", values";
12687                 }
12688                 
12689                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12690             }
12691              
12692             if (args && args.length) {
12693                 // called with xxyx.yuu:(test,test)
12694                 // change to ()
12695                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12696             }
12697             // raw.. - :raw modifier..
12698             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12699             
12700         };
12701         var body;
12702         // branched to use + in gecko and [].join() in others
12703         if(Roo.isGecko){
12704             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12705                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12706                     "';};};";
12707         }else{
12708             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12709             body.push(tpl.body.replace(/(\r\n|\n)/g,
12710                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12711             body.push("'].join('');};};");
12712             body = body.join('');
12713         }
12714         
12715         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12716        
12717         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12718         eval(body);
12719         
12720         return this;
12721     },
12722      
12723     /**
12724      * same as applyTemplate, except it's done to one of the subTemplates
12725      * when using named templates, you can do:
12726      *
12727      * var str = pl.applySubTemplate('your-name', values);
12728      *
12729      * 
12730      * @param {Number} id of the template
12731      * @param {Object} values to apply to template
12732      * @param {Object} parent (normaly the instance of this object)
12733      */
12734     applySubTemplate : function(id, values, parent)
12735     {
12736         
12737         
12738         var t = this.tpls[id];
12739         
12740         
12741         try { 
12742             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12743                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12744                 return '';
12745             }
12746         } catch(e) {
12747             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12748             Roo.log(values);
12749           
12750             return '';
12751         }
12752         try { 
12753             
12754             if(t.execCall && t.execCall.call(this, values, parent)){
12755                 return '';
12756             }
12757         } catch(e) {
12758             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12759             Roo.log(values);
12760             return '';
12761         }
12762         
12763         try {
12764             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12765             parent = t.target ? values : parent;
12766             if(t.forCall && vs instanceof Array){
12767                 var buf = [];
12768                 for(var i = 0, len = vs.length; i < len; i++){
12769                     try {
12770                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12771                     } catch (e) {
12772                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12773                         Roo.log(e.body);
12774                         //Roo.log(t.compiled);
12775                         Roo.log(vs[i]);
12776                     }   
12777                 }
12778                 return buf.join('');
12779             }
12780         } catch (e) {
12781             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12782             Roo.log(values);
12783             return '';
12784         }
12785         try {
12786             return t.compiled.call(this, vs, parent);
12787         } catch (e) {
12788             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12789             Roo.log(e.body);
12790             //Roo.log(t.compiled);
12791             Roo.log(values);
12792             return '';
12793         }
12794     },
12795
12796    
12797
12798     applyTemplate : function(values){
12799         return this.master.compiled.call(this, values, {});
12800         //var s = this.subs;
12801     },
12802
12803     apply : function(){
12804         return this.applyTemplate.apply(this, arguments);
12805     }
12806
12807  });
12808
12809 Roo.DomTemplate.from = function(el){
12810     el = Roo.getDom(el);
12811     return new Roo.Domtemplate(el.value || el.innerHTML);
12812 };/*
12813  * Based on:
12814  * Ext JS Library 1.1.1
12815  * Copyright(c) 2006-2007, Ext JS, LLC.
12816  *
12817  * Originally Released Under LGPL - original licence link has changed is not relivant.
12818  *
12819  * Fork - LGPL
12820  * <script type="text/javascript">
12821  */
12822
12823 /**
12824  * @class Roo.util.DelayedTask
12825  * Provides a convenient method of performing setTimeout where a new
12826  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12827  * You can use this class to buffer
12828  * the keypress events for a certain number of milliseconds, and perform only if they stop
12829  * for that amount of time.
12830  * @constructor The parameters to this constructor serve as defaults and are not required.
12831  * @param {Function} fn (optional) The default function to timeout
12832  * @param {Object} scope (optional) The default scope of that timeout
12833  * @param {Array} args (optional) The default Array of arguments
12834  */
12835 Roo.util.DelayedTask = function(fn, scope, args){
12836     var id = null, d, t;
12837
12838     var call = function(){
12839         var now = new Date().getTime();
12840         if(now - t >= d){
12841             clearInterval(id);
12842             id = null;
12843             fn.apply(scope, args || []);
12844         }
12845     };
12846     /**
12847      * Cancels any pending timeout and queues a new one
12848      * @param {Number} delay The milliseconds to delay
12849      * @param {Function} newFn (optional) Overrides function passed to constructor
12850      * @param {Object} newScope (optional) Overrides scope passed to constructor
12851      * @param {Array} newArgs (optional) Overrides args passed to constructor
12852      */
12853     this.delay = function(delay, newFn, newScope, newArgs){
12854         if(id && delay != d){
12855             this.cancel();
12856         }
12857         d = delay;
12858         t = new Date().getTime();
12859         fn = newFn || fn;
12860         scope = newScope || scope;
12861         args = newArgs || args;
12862         if(!id){
12863             id = setInterval(call, d);
12864         }
12865     };
12866
12867     /**
12868      * Cancel the last queued timeout
12869      */
12870     this.cancel = function(){
12871         if(id){
12872             clearInterval(id);
12873             id = null;
12874         }
12875     };
12876 };/*
12877  * Based on:
12878  * Ext JS Library 1.1.1
12879  * Copyright(c) 2006-2007, Ext JS, LLC.
12880  *
12881  * Originally Released Under LGPL - original licence link has changed is not relivant.
12882  *
12883  * Fork - LGPL
12884  * <script type="text/javascript">
12885  */
12886  
12887  
12888 Roo.util.TaskRunner = function(interval){
12889     interval = interval || 10;
12890     var tasks = [], removeQueue = [];
12891     var id = 0;
12892     var running = false;
12893
12894     var stopThread = function(){
12895         running = false;
12896         clearInterval(id);
12897         id = 0;
12898     };
12899
12900     var startThread = function(){
12901         if(!running){
12902             running = true;
12903             id = setInterval(runTasks, interval);
12904         }
12905     };
12906
12907     var removeTask = function(task){
12908         removeQueue.push(task);
12909         if(task.onStop){
12910             task.onStop();
12911         }
12912     };
12913
12914     var runTasks = function(){
12915         if(removeQueue.length > 0){
12916             for(var i = 0, len = removeQueue.length; i < len; i++){
12917                 tasks.remove(removeQueue[i]);
12918             }
12919             removeQueue = [];
12920             if(tasks.length < 1){
12921                 stopThread();
12922                 return;
12923             }
12924         }
12925         var now = new Date().getTime();
12926         for(var i = 0, len = tasks.length; i < len; ++i){
12927             var t = tasks[i];
12928             var itime = now - t.taskRunTime;
12929             if(t.interval <= itime){
12930                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12931                 t.taskRunTime = now;
12932                 if(rt === false || t.taskRunCount === t.repeat){
12933                     removeTask(t);
12934                     return;
12935                 }
12936             }
12937             if(t.duration && t.duration <= (now - t.taskStartTime)){
12938                 removeTask(t);
12939             }
12940         }
12941     };
12942
12943     /**
12944      * Queues a new task.
12945      * @param {Object} task
12946      */
12947     this.start = function(task){
12948         tasks.push(task);
12949         task.taskStartTime = new Date().getTime();
12950         task.taskRunTime = 0;
12951         task.taskRunCount = 0;
12952         startThread();
12953         return task;
12954     };
12955
12956     this.stop = function(task){
12957         removeTask(task);
12958         return task;
12959     };
12960
12961     this.stopAll = function(){
12962         stopThread();
12963         for(var i = 0, len = tasks.length; i < len; i++){
12964             if(tasks[i].onStop){
12965                 tasks[i].onStop();
12966             }
12967         }
12968         tasks = [];
12969         removeQueue = [];
12970     };
12971 };
12972
12973 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12974  * Based on:
12975  * Ext JS Library 1.1.1
12976  * Copyright(c) 2006-2007, Ext JS, LLC.
12977  *
12978  * Originally Released Under LGPL - original licence link has changed is not relivant.
12979  *
12980  * Fork - LGPL
12981  * <script type="text/javascript">
12982  */
12983
12984  
12985 /**
12986  * @class Roo.util.MixedCollection
12987  * @extends Roo.util.Observable
12988  * A Collection class that maintains both numeric indexes and keys and exposes events.
12989  * @constructor
12990  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12991  * collection (defaults to false)
12992  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12993  * and return the key value for that item.  This is used when available to look up the key on items that
12994  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12995  * equivalent to providing an implementation for the {@link #getKey} method.
12996  */
12997 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12998     this.items = [];
12999     this.map = {};
13000     this.keys = [];
13001     this.length = 0;
13002     this.addEvents({
13003         /**
13004          * @event clear
13005          * Fires when the collection is cleared.
13006          */
13007         "clear" : true,
13008         /**
13009          * @event add
13010          * Fires when an item is added to the collection.
13011          * @param {Number} index The index at which the item was added.
13012          * @param {Object} o The item added.
13013          * @param {String} key The key associated with the added item.
13014          */
13015         "add" : true,
13016         /**
13017          * @event replace
13018          * Fires when an item is replaced in the collection.
13019          * @param {String} key he key associated with the new added.
13020          * @param {Object} old The item being replaced.
13021          * @param {Object} new The new item.
13022          */
13023         "replace" : true,
13024         /**
13025          * @event remove
13026          * Fires when an item is removed from the collection.
13027          * @param {Object} o The item being removed.
13028          * @param {String} key (optional) The key associated with the removed item.
13029          */
13030         "remove" : true,
13031         "sort" : true
13032     });
13033     this.allowFunctions = allowFunctions === true;
13034     if(keyFn){
13035         this.getKey = keyFn;
13036     }
13037     Roo.util.MixedCollection.superclass.constructor.call(this);
13038 };
13039
13040 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13041     allowFunctions : false,
13042     
13043 /**
13044  * Adds an item to the collection.
13045  * @param {String} key The key to associate with the item
13046  * @param {Object} o The item to add.
13047  * @return {Object} The item added.
13048  */
13049     add : function(key, o){
13050         if(arguments.length == 1){
13051             o = arguments[0];
13052             key = this.getKey(o);
13053         }
13054         if(typeof key == "undefined" || key === null){
13055             this.length++;
13056             this.items.push(o);
13057             this.keys.push(null);
13058         }else{
13059             var old = this.map[key];
13060             if(old){
13061                 return this.replace(key, o);
13062             }
13063             this.length++;
13064             this.items.push(o);
13065             this.map[key] = o;
13066             this.keys.push(key);
13067         }
13068         this.fireEvent("add", this.length-1, o, key);
13069         return o;
13070     },
13071        
13072 /**
13073   * MixedCollection has a generic way to fetch keys if you implement getKey.
13074 <pre><code>
13075 // normal way
13076 var mc = new Roo.util.MixedCollection();
13077 mc.add(someEl.dom.id, someEl);
13078 mc.add(otherEl.dom.id, otherEl);
13079 //and so on
13080
13081 // using getKey
13082 var mc = new Roo.util.MixedCollection();
13083 mc.getKey = function(el){
13084    return el.dom.id;
13085 };
13086 mc.add(someEl);
13087 mc.add(otherEl);
13088
13089 // or via the constructor
13090 var mc = new Roo.util.MixedCollection(false, function(el){
13091    return el.dom.id;
13092 });
13093 mc.add(someEl);
13094 mc.add(otherEl);
13095 </code></pre>
13096  * @param o {Object} The item for which to find the key.
13097  * @return {Object} The key for the passed item.
13098  */
13099     getKey : function(o){
13100          return o.id; 
13101     },
13102    
13103 /**
13104  * Replaces an item in the collection.
13105  * @param {String} key The key associated with the item to replace, or the item to replace.
13106  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13107  * @return {Object}  The new item.
13108  */
13109     replace : function(key, o){
13110         if(arguments.length == 1){
13111             o = arguments[0];
13112             key = this.getKey(o);
13113         }
13114         var old = this.item(key);
13115         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13116              return this.add(key, o);
13117         }
13118         var index = this.indexOfKey(key);
13119         this.items[index] = o;
13120         this.map[key] = o;
13121         this.fireEvent("replace", key, old, o);
13122         return o;
13123     },
13124    
13125 /**
13126  * Adds all elements of an Array or an Object to the collection.
13127  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13128  * an Array of values, each of which are added to the collection.
13129  */
13130     addAll : function(objs){
13131         if(arguments.length > 1 || objs instanceof Array){
13132             var args = arguments.length > 1 ? arguments : objs;
13133             for(var i = 0, len = args.length; i < len; i++){
13134                 this.add(args[i]);
13135             }
13136         }else{
13137             for(var key in objs){
13138                 if(this.allowFunctions || typeof objs[key] != "function"){
13139                     this.add(key, objs[key]);
13140                 }
13141             }
13142         }
13143     },
13144    
13145 /**
13146  * Executes the specified function once for every item in the collection, passing each
13147  * item as the first and only parameter. returning false from the function will stop the iteration.
13148  * @param {Function} fn The function to execute for each item.
13149  * @param {Object} scope (optional) The scope in which to execute the function.
13150  */
13151     each : function(fn, scope){
13152         var items = [].concat(this.items); // each safe for removal
13153         for(var i = 0, len = items.length; i < len; i++){
13154             if(fn.call(scope || items[i], items[i], i, len) === false){
13155                 break;
13156             }
13157         }
13158     },
13159    
13160 /**
13161  * Executes the specified function once for every key in the collection, passing each
13162  * key, and its associated item as the first two parameters.
13163  * @param {Function} fn The function to execute for each item.
13164  * @param {Object} scope (optional) The scope in which to execute the function.
13165  */
13166     eachKey : function(fn, scope){
13167         for(var i = 0, len = this.keys.length; i < len; i++){
13168             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13169         }
13170     },
13171    
13172 /**
13173  * Returns the first item in the collection which elicits a true return value from the
13174  * passed selection function.
13175  * @param {Function} fn The selection function to execute for each item.
13176  * @param {Object} scope (optional) The scope in which to execute the function.
13177  * @return {Object} The first item in the collection which returned true from the selection function.
13178  */
13179     find : function(fn, scope){
13180         for(var i = 0, len = this.items.length; i < len; i++){
13181             if(fn.call(scope || window, this.items[i], this.keys[i])){
13182                 return this.items[i];
13183             }
13184         }
13185         return null;
13186     },
13187    
13188 /**
13189  * Inserts an item at the specified index in the collection.
13190  * @param {Number} index The index to insert the item at.
13191  * @param {String} key The key to associate with the new item, or the item itself.
13192  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13193  * @return {Object} The item inserted.
13194  */
13195     insert : function(index, key, o){
13196         if(arguments.length == 2){
13197             o = arguments[1];
13198             key = this.getKey(o);
13199         }
13200         if(index >= this.length){
13201             return this.add(key, o);
13202         }
13203         this.length++;
13204         this.items.splice(index, 0, o);
13205         if(typeof key != "undefined" && key != null){
13206             this.map[key] = o;
13207         }
13208         this.keys.splice(index, 0, key);
13209         this.fireEvent("add", index, o, key);
13210         return o;
13211     },
13212    
13213 /**
13214  * Removed an item from the collection.
13215  * @param {Object} o The item to remove.
13216  * @return {Object} The item removed.
13217  */
13218     remove : function(o){
13219         return this.removeAt(this.indexOf(o));
13220     },
13221    
13222 /**
13223  * Remove an item from a specified index in the collection.
13224  * @param {Number} index The index within the collection of the item to remove.
13225  */
13226     removeAt : function(index){
13227         if(index < this.length && index >= 0){
13228             this.length--;
13229             var o = this.items[index];
13230             this.items.splice(index, 1);
13231             var key = this.keys[index];
13232             if(typeof key != "undefined"){
13233                 delete this.map[key];
13234             }
13235             this.keys.splice(index, 1);
13236             this.fireEvent("remove", o, key);
13237         }
13238     },
13239    
13240 /**
13241  * Removed an item associated with the passed key fom the collection.
13242  * @param {String} key The key of the item to remove.
13243  */
13244     removeKey : function(key){
13245         return this.removeAt(this.indexOfKey(key));
13246     },
13247    
13248 /**
13249  * Returns the number of items in the collection.
13250  * @return {Number} the number of items in the collection.
13251  */
13252     getCount : function(){
13253         return this.length; 
13254     },
13255    
13256 /**
13257  * Returns index within the collection of the passed Object.
13258  * @param {Object} o The item to find the index of.
13259  * @return {Number} index of the item.
13260  */
13261     indexOf : function(o){
13262         if(!this.items.indexOf){
13263             for(var i = 0, len = this.items.length; i < len; i++){
13264                 if(this.items[i] == o) {
13265                     return i;
13266                 }
13267             }
13268             return -1;
13269         }else{
13270             return this.items.indexOf(o);
13271         }
13272     },
13273    
13274 /**
13275  * Returns index within the collection of the passed key.
13276  * @param {String} key The key to find the index of.
13277  * @return {Number} index of the key.
13278  */
13279     indexOfKey : function(key){
13280         if(!this.keys.indexOf){
13281             for(var i = 0, len = this.keys.length; i < len; i++){
13282                 if(this.keys[i] == key) {
13283                     return i;
13284                 }
13285             }
13286             return -1;
13287         }else{
13288             return this.keys.indexOf(key);
13289         }
13290     },
13291    
13292 /**
13293  * Returns the item associated with the passed key OR index. Key has priority over index.
13294  * @param {String/Number} key The key or index of the item.
13295  * @return {Object} The item associated with the passed key.
13296  */
13297     item : function(key){
13298         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13299         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13300     },
13301     
13302 /**
13303  * Returns the item at the specified index.
13304  * @param {Number} index The index of the item.
13305  * @return {Object}
13306  */
13307     itemAt : function(index){
13308         return this.items[index];
13309     },
13310     
13311 /**
13312  * Returns the item associated with the passed key.
13313  * @param {String/Number} key The key of the item.
13314  * @return {Object} The item associated with the passed key.
13315  */
13316     key : function(key){
13317         return this.map[key];
13318     },
13319    
13320 /**
13321  * Returns true if the collection contains the passed Object as an item.
13322  * @param {Object} o  The Object to look for in the collection.
13323  * @return {Boolean} True if the collection contains the Object as an item.
13324  */
13325     contains : function(o){
13326         return this.indexOf(o) != -1;
13327     },
13328    
13329 /**
13330  * Returns true if the collection contains the passed Object as a key.
13331  * @param {String} key The key to look for in the collection.
13332  * @return {Boolean} True if the collection contains the Object as a key.
13333  */
13334     containsKey : function(key){
13335         return typeof this.map[key] != "undefined";
13336     },
13337    
13338 /**
13339  * Removes all items from the collection.
13340  */
13341     clear : function(){
13342         this.length = 0;
13343         this.items = [];
13344         this.keys = [];
13345         this.map = {};
13346         this.fireEvent("clear");
13347     },
13348    
13349 /**
13350  * Returns the first item in the collection.
13351  * @return {Object} the first item in the collection..
13352  */
13353     first : function(){
13354         return this.items[0]; 
13355     },
13356    
13357 /**
13358  * Returns the last item in the collection.
13359  * @return {Object} the last item in the collection..
13360  */
13361     last : function(){
13362         return this.items[this.length-1];   
13363     },
13364     
13365     _sort : function(property, dir, fn){
13366         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13367         fn = fn || function(a, b){
13368             return a-b;
13369         };
13370         var c = [], k = this.keys, items = this.items;
13371         for(var i = 0, len = items.length; i < len; i++){
13372             c[c.length] = {key: k[i], value: items[i], index: i};
13373         }
13374         c.sort(function(a, b){
13375             var v = fn(a[property], b[property]) * dsc;
13376             if(v == 0){
13377                 v = (a.index < b.index ? -1 : 1);
13378             }
13379             return v;
13380         });
13381         for(var i = 0, len = c.length; i < len; i++){
13382             items[i] = c[i].value;
13383             k[i] = c[i].key;
13384         }
13385         this.fireEvent("sort", this);
13386     },
13387     
13388     /**
13389      * Sorts this collection with the passed comparison function
13390      * @param {String} direction (optional) "ASC" or "DESC"
13391      * @param {Function} fn (optional) comparison function
13392      */
13393     sort : function(dir, fn){
13394         this._sort("value", dir, fn);
13395     },
13396     
13397     /**
13398      * Sorts this collection by keys
13399      * @param {String} direction (optional) "ASC" or "DESC"
13400      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13401      */
13402     keySort : function(dir, fn){
13403         this._sort("key", dir, fn || function(a, b){
13404             return String(a).toUpperCase()-String(b).toUpperCase();
13405         });
13406     },
13407     
13408     /**
13409      * Returns a range of items in this collection
13410      * @param {Number} startIndex (optional) defaults to 0
13411      * @param {Number} endIndex (optional) default to the last item
13412      * @return {Array} An array of items
13413      */
13414     getRange : function(start, end){
13415         var items = this.items;
13416         if(items.length < 1){
13417             return [];
13418         }
13419         start = start || 0;
13420         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13421         var r = [];
13422         if(start <= end){
13423             for(var i = start; i <= end; i++) {
13424                     r[r.length] = items[i];
13425             }
13426         }else{
13427             for(var i = start; i >= end; i--) {
13428                     r[r.length] = items[i];
13429             }
13430         }
13431         return r;
13432     },
13433         
13434     /**
13435      * Filter the <i>objects</i> in this collection by a specific property. 
13436      * Returns a new collection that has been filtered.
13437      * @param {String} property A property on your objects
13438      * @param {String/RegExp} value Either string that the property values 
13439      * should start with or a RegExp to test against the property
13440      * @return {MixedCollection} The new filtered collection
13441      */
13442     filter : function(property, value){
13443         if(!value.exec){ // not a regex
13444             value = String(value);
13445             if(value.length == 0){
13446                 return this.clone();
13447             }
13448             value = new RegExp("^" + Roo.escapeRe(value), "i");
13449         }
13450         return this.filterBy(function(o){
13451             return o && value.test(o[property]);
13452         });
13453         },
13454     
13455     /**
13456      * Filter by a function. * Returns a new collection that has been filtered.
13457      * The passed function will be called with each 
13458      * object in the collection. If the function returns true, the value is included 
13459      * otherwise it is filtered.
13460      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13461      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13462      * @return {MixedCollection} The new filtered collection
13463      */
13464     filterBy : function(fn, scope){
13465         var r = new Roo.util.MixedCollection();
13466         r.getKey = this.getKey;
13467         var k = this.keys, it = this.items;
13468         for(var i = 0, len = it.length; i < len; i++){
13469             if(fn.call(scope||this, it[i], k[i])){
13470                                 r.add(k[i], it[i]);
13471                         }
13472         }
13473         return r;
13474     },
13475     
13476     /**
13477      * Creates a duplicate of this collection
13478      * @return {MixedCollection}
13479      */
13480     clone : function(){
13481         var r = new Roo.util.MixedCollection();
13482         var k = this.keys, it = this.items;
13483         for(var i = 0, len = it.length; i < len; i++){
13484             r.add(k[i], it[i]);
13485         }
13486         r.getKey = this.getKey;
13487         return r;
13488     }
13489 });
13490 /**
13491  * Returns the item associated with the passed key or index.
13492  * @method
13493  * @param {String/Number} key The key or index of the item.
13494  * @return {Object} The item associated with the passed key.
13495  */
13496 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13497  * Based on:
13498  * Ext JS Library 1.1.1
13499  * Copyright(c) 2006-2007, Ext JS, LLC.
13500  *
13501  * Originally Released Under LGPL - original licence link has changed is not relivant.
13502  *
13503  * Fork - LGPL
13504  * <script type="text/javascript">
13505  */
13506 /**
13507  * @class Roo.util.JSON
13508  * Modified version of Douglas Crockford"s json.js that doesn"t
13509  * mess with the Object prototype 
13510  * http://www.json.org/js.html
13511  * @singleton
13512  */
13513 Roo.util.JSON = new (function(){
13514     var useHasOwn = {}.hasOwnProperty ? true : false;
13515     
13516     // crashes Safari in some instances
13517     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13518     
13519     var pad = function(n) {
13520         return n < 10 ? "0" + n : n;
13521     };
13522     
13523     var m = {
13524         "\b": '\\b',
13525         "\t": '\\t',
13526         "\n": '\\n',
13527         "\f": '\\f',
13528         "\r": '\\r',
13529         '"' : '\\"',
13530         "\\": '\\\\'
13531     };
13532
13533     var encodeString = function(s){
13534         if (/["\\\x00-\x1f]/.test(s)) {
13535             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13536                 var c = m[b];
13537                 if(c){
13538                     return c;
13539                 }
13540                 c = b.charCodeAt();
13541                 return "\\u00" +
13542                     Math.floor(c / 16).toString(16) +
13543                     (c % 16).toString(16);
13544             }) + '"';
13545         }
13546         return '"' + s + '"';
13547     };
13548     
13549     var encodeArray = function(o){
13550         var a = ["["], b, i, l = o.length, v;
13551             for (i = 0; i < l; i += 1) {
13552                 v = o[i];
13553                 switch (typeof v) {
13554                     case "undefined":
13555                     case "function":
13556                     case "unknown":
13557                         break;
13558                     default:
13559                         if (b) {
13560                             a.push(',');
13561                         }
13562                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13563                         b = true;
13564                 }
13565             }
13566             a.push("]");
13567             return a.join("");
13568     };
13569     
13570     var encodeDate = function(o){
13571         return '"' + o.getFullYear() + "-" +
13572                 pad(o.getMonth() + 1) + "-" +
13573                 pad(o.getDate()) + "T" +
13574                 pad(o.getHours()) + ":" +
13575                 pad(o.getMinutes()) + ":" +
13576                 pad(o.getSeconds()) + '"';
13577     };
13578     
13579     /**
13580      * Encodes an Object, Array or other value
13581      * @param {Mixed} o The variable to encode
13582      * @return {String} The JSON string
13583      */
13584     this.encode = function(o)
13585     {
13586         // should this be extended to fully wrap stringify..
13587         
13588         if(typeof o == "undefined" || o === null){
13589             return "null";
13590         }else if(o instanceof Array){
13591             return encodeArray(o);
13592         }else if(o instanceof Date){
13593             return encodeDate(o);
13594         }else if(typeof o == "string"){
13595             return encodeString(o);
13596         }else if(typeof o == "number"){
13597             return isFinite(o) ? String(o) : "null";
13598         }else if(typeof o == "boolean"){
13599             return String(o);
13600         }else {
13601             var a = ["{"], b, i, v;
13602             for (i in o) {
13603                 if(!useHasOwn || o.hasOwnProperty(i)) {
13604                     v = o[i];
13605                     switch (typeof v) {
13606                     case "undefined":
13607                     case "function":
13608                     case "unknown":
13609                         break;
13610                     default:
13611                         if(b){
13612                             a.push(',');
13613                         }
13614                         a.push(this.encode(i), ":",
13615                                 v === null ? "null" : this.encode(v));
13616                         b = true;
13617                     }
13618                 }
13619             }
13620             a.push("}");
13621             return a.join("");
13622         }
13623     };
13624     
13625     /**
13626      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13627      * @param {String} json The JSON string
13628      * @return {Object} The resulting object
13629      */
13630     this.decode = function(json){
13631         
13632         return  /** eval:var:json */ eval("(" + json + ')');
13633     };
13634 })();
13635 /** 
13636  * Shorthand for {@link Roo.util.JSON#encode}
13637  * @member Roo encode 
13638  * @method */
13639 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13640 /** 
13641  * Shorthand for {@link Roo.util.JSON#decode}
13642  * @member Roo decode 
13643  * @method */
13644 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13645 /*
13646  * Based on:
13647  * Ext JS Library 1.1.1
13648  * Copyright(c) 2006-2007, Ext JS, LLC.
13649  *
13650  * Originally Released Under LGPL - original licence link has changed is not relivant.
13651  *
13652  * Fork - LGPL
13653  * <script type="text/javascript">
13654  */
13655  
13656 /**
13657  * @class Roo.util.Format
13658  * Reusable data formatting functions
13659  * @singleton
13660  */
13661 Roo.util.Format = function(){
13662     var trimRe = /^\s+|\s+$/g;
13663     return {
13664         /**
13665          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13666          * @param {String} value The string to truncate
13667          * @param {Number} length The maximum length to allow before truncating
13668          * @return {String} The converted text
13669          */
13670         ellipsis : function(value, len){
13671             if(value && value.length > len){
13672                 return value.substr(0, len-3)+"...";
13673             }
13674             return value;
13675         },
13676
13677         /**
13678          * Checks a reference and converts it to empty string if it is undefined
13679          * @param {Mixed} value Reference to check
13680          * @return {Mixed} Empty string if converted, otherwise the original value
13681          */
13682         undef : function(value){
13683             return typeof value != "undefined" ? value : "";
13684         },
13685
13686         /**
13687          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13688          * @param {String} value The string to encode
13689          * @return {String} The encoded text
13690          */
13691         htmlEncode : function(value){
13692             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13693         },
13694
13695         /**
13696          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13697          * @param {String} value The string to decode
13698          * @return {String} The decoded text
13699          */
13700         htmlDecode : function(value){
13701             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13702         },
13703
13704         /**
13705          * Trims any whitespace from either side of a string
13706          * @param {String} value The text to trim
13707          * @return {String} The trimmed text
13708          */
13709         trim : function(value){
13710             return String(value).replace(trimRe, "");
13711         },
13712
13713         /**
13714          * Returns a substring from within an original string
13715          * @param {String} value The original text
13716          * @param {Number} start The start index of the substring
13717          * @param {Number} length The length of the substring
13718          * @return {String} The substring
13719          */
13720         substr : function(value, start, length){
13721             return String(value).substr(start, length);
13722         },
13723
13724         /**
13725          * Converts a string to all lower case letters
13726          * @param {String} value The text to convert
13727          * @return {String} The converted text
13728          */
13729         lowercase : function(value){
13730             return String(value).toLowerCase();
13731         },
13732
13733         /**
13734          * Converts a string to all upper case letters
13735          * @param {String} value The text to convert
13736          * @return {String} The converted text
13737          */
13738         uppercase : function(value){
13739             return String(value).toUpperCase();
13740         },
13741
13742         /**
13743          * Converts the first character only of a string to upper case
13744          * @param {String} value The text to convert
13745          * @return {String} The converted text
13746          */
13747         capitalize : function(value){
13748             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13749         },
13750
13751         // private
13752         call : function(value, fn){
13753             if(arguments.length > 2){
13754                 var args = Array.prototype.slice.call(arguments, 2);
13755                 args.unshift(value);
13756                  
13757                 return /** eval:var:value */  eval(fn).apply(window, args);
13758             }else{
13759                 /** eval:var:value */
13760                 return /** eval:var:value */ eval(fn).call(window, value);
13761             }
13762         },
13763
13764        
13765         /**
13766          * safer version of Math.toFixed..??/
13767          * @param {Number/String} value The numeric value to format
13768          * @param {Number/String} value Decimal places 
13769          * @return {String} The formatted currency string
13770          */
13771         toFixed : function(v, n)
13772         {
13773             // why not use to fixed - precision is buggered???
13774             if (!n) {
13775                 return Math.round(v-0);
13776             }
13777             var fact = Math.pow(10,n+1);
13778             v = (Math.round((v-0)*fact))/fact;
13779             var z = (''+fact).substring(2);
13780             if (v == Math.floor(v)) {
13781                 return Math.floor(v) + '.' + z;
13782             }
13783             
13784             // now just padd decimals..
13785             var ps = String(v).split('.');
13786             var fd = (ps[1] + z);
13787             var r = fd.substring(0,n); 
13788             var rm = fd.substring(n); 
13789             if (rm < 5) {
13790                 return ps[0] + '.' + r;
13791             }
13792             r*=1; // turn it into a number;
13793             r++;
13794             if (String(r).length != n) {
13795                 ps[0]*=1;
13796                 ps[0]++;
13797                 r = String(r).substring(1); // chop the end off.
13798             }
13799             
13800             return ps[0] + '.' + r;
13801              
13802         },
13803         
13804         /**
13805          * Format a number as US currency
13806          * @param {Number/String} value The numeric value to format
13807          * @return {String} The formatted currency string
13808          */
13809         usMoney : function(v){
13810             return '$' + Roo.util.Format.number(v);
13811         },
13812         
13813         /**
13814          * Format a number
13815          * eventually this should probably emulate php's number_format
13816          * @param {Number/String} value The numeric value to format
13817          * @param {Number} decimals number of decimal places
13818          * @param {String} delimiter for thousands (default comma)
13819          * @return {String} The formatted currency string
13820          */
13821         number : function(v, decimals, thousandsDelimiter)
13822         {
13823             // multiply and round.
13824             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13825             thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13826             
13827             var mul = Math.pow(10, decimals);
13828             var zero = String(mul).substring(1);
13829             v = (Math.round((v-0)*mul))/mul;
13830             
13831             // if it's '0' number.. then
13832             
13833             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13834             v = String(v);
13835             var ps = v.split('.');
13836             var whole = ps[0];
13837             
13838             var r = /(\d+)(\d{3})/;
13839             // add comma's
13840             
13841             if(thousandsDelimiter.length != 0) {
13842                 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13843             } 
13844             
13845             var sub = ps[1] ?
13846                     // has decimals..
13847                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13848                     // does not have decimals
13849                     (decimals ? ('.' + zero) : '');
13850             
13851             
13852             return whole + sub ;
13853         },
13854         
13855         /**
13856          * Parse a value into a formatted date using the specified format pattern.
13857          * @param {Mixed} value The value to format
13858          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13859          * @return {String} The formatted date string
13860          */
13861         date : function(v, format){
13862             if(!v){
13863                 return "";
13864             }
13865             if(!(v instanceof Date)){
13866                 v = new Date(Date.parse(v));
13867             }
13868             return v.dateFormat(format || Roo.util.Format.defaults.date);
13869         },
13870
13871         /**
13872          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13873          * @param {String} format Any valid date format string
13874          * @return {Function} The date formatting function
13875          */
13876         dateRenderer : function(format){
13877             return function(v){
13878                 return Roo.util.Format.date(v, format);  
13879             };
13880         },
13881
13882         // private
13883         stripTagsRE : /<\/?[^>]+>/gi,
13884         
13885         /**
13886          * Strips all HTML tags
13887          * @param {Mixed} value The text from which to strip tags
13888          * @return {String} The stripped text
13889          */
13890         stripTags : function(v){
13891             return !v ? v : String(v).replace(this.stripTagsRE, "");
13892         }
13893     };
13894 }();
13895 Roo.util.Format.defaults = {
13896     date : 'd/M/Y'
13897 };/*
13898  * Based on:
13899  * Ext JS Library 1.1.1
13900  * Copyright(c) 2006-2007, Ext JS, LLC.
13901  *
13902  * Originally Released Under LGPL - original licence link has changed is not relivant.
13903  *
13904  * Fork - LGPL
13905  * <script type="text/javascript">
13906  */
13907
13908
13909  
13910
13911 /**
13912  * @class Roo.MasterTemplate
13913  * @extends Roo.Template
13914  * Provides a template that can have child templates. The syntax is:
13915 <pre><code>
13916 var t = new Roo.MasterTemplate(
13917         '&lt;select name="{name}"&gt;',
13918                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13919         '&lt;/select&gt;'
13920 );
13921 t.add('options', {value: 'foo', text: 'bar'});
13922 // or you can add multiple child elements in one shot
13923 t.addAll('options', [
13924     {value: 'foo', text: 'bar'},
13925     {value: 'foo2', text: 'bar2'},
13926     {value: 'foo3', text: 'bar3'}
13927 ]);
13928 // then append, applying the master template values
13929 t.append('my-form', {name: 'my-select'});
13930 </code></pre>
13931 * A name attribute for the child template is not required if you have only one child
13932 * template or you want to refer to them by index.
13933  */
13934 Roo.MasterTemplate = function(){
13935     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13936     this.originalHtml = this.html;
13937     var st = {};
13938     var m, re = this.subTemplateRe;
13939     re.lastIndex = 0;
13940     var subIndex = 0;
13941     while(m = re.exec(this.html)){
13942         var name = m[1], content = m[2];
13943         st[subIndex] = {
13944             name: name,
13945             index: subIndex,
13946             buffer: [],
13947             tpl : new Roo.Template(content)
13948         };
13949         if(name){
13950             st[name] = st[subIndex];
13951         }
13952         st[subIndex].tpl.compile();
13953         st[subIndex].tpl.call = this.call.createDelegate(this);
13954         subIndex++;
13955     }
13956     this.subCount = subIndex;
13957     this.subs = st;
13958 };
13959 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13960     /**
13961     * The regular expression used to match sub templates
13962     * @type RegExp
13963     * @property
13964     */
13965     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13966
13967     /**
13968      * Applies the passed values to a child template.
13969      * @param {String/Number} name (optional) The name or index of the child template
13970      * @param {Array/Object} values The values to be applied to the template
13971      * @return {MasterTemplate} this
13972      */
13973      add : function(name, values){
13974         if(arguments.length == 1){
13975             values = arguments[0];
13976             name = 0;
13977         }
13978         var s = this.subs[name];
13979         s.buffer[s.buffer.length] = s.tpl.apply(values);
13980         return this;
13981     },
13982
13983     /**
13984      * Applies all the passed values to a child template.
13985      * @param {String/Number} name (optional) The name or index of the child template
13986      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13987      * @param {Boolean} reset (optional) True to reset the template first
13988      * @return {MasterTemplate} this
13989      */
13990     fill : function(name, values, reset){
13991         var a = arguments;
13992         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13993             values = a[0];
13994             name = 0;
13995             reset = a[1];
13996         }
13997         if(reset){
13998             this.reset();
13999         }
14000         for(var i = 0, len = values.length; i < len; i++){
14001             this.add(name, values[i]);
14002         }
14003         return this;
14004     },
14005
14006     /**
14007      * Resets the template for reuse
14008      * @return {MasterTemplate} this
14009      */
14010      reset : function(){
14011         var s = this.subs;
14012         for(var i = 0; i < this.subCount; i++){
14013             s[i].buffer = [];
14014         }
14015         return this;
14016     },
14017
14018     applyTemplate : function(values){
14019         var s = this.subs;
14020         var replaceIndex = -1;
14021         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14022             return s[++replaceIndex].buffer.join("");
14023         });
14024         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14025     },
14026
14027     apply : function(){
14028         return this.applyTemplate.apply(this, arguments);
14029     },
14030
14031     compile : function(){return this;}
14032 });
14033
14034 /**
14035  * Alias for fill().
14036  * @method
14037  */
14038 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14039  /**
14040  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14041  * var tpl = Roo.MasterTemplate.from('element-id');
14042  * @param {String/HTMLElement} el
14043  * @param {Object} config
14044  * @static
14045  */
14046 Roo.MasterTemplate.from = function(el, config){
14047     el = Roo.getDom(el);
14048     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14049 };/*
14050  * Based on:
14051  * Ext JS Library 1.1.1
14052  * Copyright(c) 2006-2007, Ext JS, LLC.
14053  *
14054  * Originally Released Under LGPL - original licence link has changed is not relivant.
14055  *
14056  * Fork - LGPL
14057  * <script type="text/javascript">
14058  */
14059
14060  
14061 /**
14062  * @class Roo.util.CSS
14063  * Utility class for manipulating CSS rules
14064  * @singleton
14065  */
14066 Roo.util.CSS = function(){
14067         var rules = null;
14068         var doc = document;
14069
14070     var camelRe = /(-[a-z])/gi;
14071     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14072
14073    return {
14074    /**
14075     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14076     * tag and appended to the HEAD of the document.
14077     * @param {String|Object} cssText The text containing the css rules
14078     * @param {String} id An id to add to the stylesheet for later removal
14079     * @return {StyleSheet}
14080     */
14081     createStyleSheet : function(cssText, id){
14082         var ss;
14083         var head = doc.getElementsByTagName("head")[0];
14084         var nrules = doc.createElement("style");
14085         nrules.setAttribute("type", "text/css");
14086         if(id){
14087             nrules.setAttribute("id", id);
14088         }
14089         if (typeof(cssText) != 'string') {
14090             // support object maps..
14091             // not sure if this a good idea.. 
14092             // perhaps it should be merged with the general css handling
14093             // and handle js style props.
14094             var cssTextNew = [];
14095             for(var n in cssText) {
14096                 var citems = [];
14097                 for(var k in cssText[n]) {
14098                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14099                 }
14100                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14101                 
14102             }
14103             cssText = cssTextNew.join("\n");
14104             
14105         }
14106        
14107        
14108        if(Roo.isIE){
14109            head.appendChild(nrules);
14110            ss = nrules.styleSheet;
14111            ss.cssText = cssText;
14112        }else{
14113            try{
14114                 nrules.appendChild(doc.createTextNode(cssText));
14115            }catch(e){
14116                nrules.cssText = cssText; 
14117            }
14118            head.appendChild(nrules);
14119            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14120        }
14121        this.cacheStyleSheet(ss);
14122        return ss;
14123    },
14124
14125    /**
14126     * Removes a style or link tag by id
14127     * @param {String} id The id of the tag
14128     */
14129    removeStyleSheet : function(id){
14130        var existing = doc.getElementById(id);
14131        if(existing){
14132            existing.parentNode.removeChild(existing);
14133        }
14134    },
14135
14136    /**
14137     * Dynamically swaps an existing stylesheet reference for a new one
14138     * @param {String} id The id of an existing link tag to remove
14139     * @param {String} url The href of the new stylesheet to include
14140     */
14141    swapStyleSheet : function(id, url){
14142        this.removeStyleSheet(id);
14143        var ss = doc.createElement("link");
14144        ss.setAttribute("rel", "stylesheet");
14145        ss.setAttribute("type", "text/css");
14146        ss.setAttribute("id", id);
14147        ss.setAttribute("href", url);
14148        doc.getElementsByTagName("head")[0].appendChild(ss);
14149    },
14150    
14151    /**
14152     * Refresh the rule cache if you have dynamically added stylesheets
14153     * @return {Object} An object (hash) of rules indexed by selector
14154     */
14155    refreshCache : function(){
14156        return this.getRules(true);
14157    },
14158
14159    // private
14160    cacheStyleSheet : function(stylesheet){
14161        if(!rules){
14162            rules = {};
14163        }
14164        try{// try catch for cross domain access issue
14165            var ssRules = stylesheet.cssRules || stylesheet.rules;
14166            for(var j = ssRules.length-1; j >= 0; --j){
14167                rules[ssRules[j].selectorText] = ssRules[j];
14168            }
14169        }catch(e){}
14170    },
14171    
14172    /**
14173     * Gets all css rules for the document
14174     * @param {Boolean} refreshCache true to refresh the internal cache
14175     * @return {Object} An object (hash) of rules indexed by selector
14176     */
14177    getRules : function(refreshCache){
14178                 if(rules == null || refreshCache){
14179                         rules = {};
14180                         var ds = doc.styleSheets;
14181                         for(var i =0, len = ds.length; i < len; i++){
14182                             try{
14183                         this.cacheStyleSheet(ds[i]);
14184                     }catch(e){} 
14185                 }
14186                 }
14187                 return rules;
14188         },
14189         
14190         /**
14191     * Gets an an individual CSS rule by selector(s)
14192     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14193     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14194     * @return {CSSRule} The CSS rule or null if one is not found
14195     */
14196    getRule : function(selector, refreshCache){
14197                 var rs = this.getRules(refreshCache);
14198                 if(!(selector instanceof Array)){
14199                     return rs[selector];
14200                 }
14201                 for(var i = 0; i < selector.length; i++){
14202                         if(rs[selector[i]]){
14203                                 return rs[selector[i]];
14204                         }
14205                 }
14206                 return null;
14207         },
14208         
14209         
14210         /**
14211     * Updates a rule property
14212     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14213     * @param {String} property The css property
14214     * @param {String} value The new value for the property
14215     * @return {Boolean} true If a rule was found and updated
14216     */
14217    updateRule : function(selector, property, value){
14218                 if(!(selector instanceof Array)){
14219                         var rule = this.getRule(selector);
14220                         if(rule){
14221                                 rule.style[property.replace(camelRe, camelFn)] = value;
14222                                 return true;
14223                         }
14224                 }else{
14225                         for(var i = 0; i < selector.length; i++){
14226                                 if(this.updateRule(selector[i], property, value)){
14227                                         return true;
14228                                 }
14229                         }
14230                 }
14231                 return false;
14232         }
14233    };   
14234 }();/*
14235  * Based on:
14236  * Ext JS Library 1.1.1
14237  * Copyright(c) 2006-2007, Ext JS, LLC.
14238  *
14239  * Originally Released Under LGPL - original licence link has changed is not relivant.
14240  *
14241  * Fork - LGPL
14242  * <script type="text/javascript">
14243  */
14244
14245  
14246
14247 /**
14248  * @class Roo.util.ClickRepeater
14249  * @extends Roo.util.Observable
14250  * 
14251  * A wrapper class which can be applied to any element. Fires a "click" event while the
14252  * mouse is pressed. The interval between firings may be specified in the config but
14253  * defaults to 10 milliseconds.
14254  * 
14255  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14256  * 
14257  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14258  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14259  * Similar to an autorepeat key delay.
14260  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14261  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14262  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14263  *           "interval" and "delay" are ignored. "immediate" is honored.
14264  * @cfg {Boolean} preventDefault True to prevent the default click event
14265  * @cfg {Boolean} stopDefault True to stop the default click event
14266  * 
14267  * @history
14268  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14269  *     2007-02-02 jvs Renamed to ClickRepeater
14270  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14271  *
14272  *  @constructor
14273  * @param {String/HTMLElement/Element} el The element to listen on
14274  * @param {Object} config
14275  **/
14276 Roo.util.ClickRepeater = function(el, config)
14277 {
14278     this.el = Roo.get(el);
14279     this.el.unselectable();
14280
14281     Roo.apply(this, config);
14282
14283     this.addEvents({
14284     /**
14285      * @event mousedown
14286      * Fires when the mouse button is depressed.
14287      * @param {Roo.util.ClickRepeater} this
14288      */
14289         "mousedown" : true,
14290     /**
14291      * @event click
14292      * Fires on a specified interval during the time the element is pressed.
14293      * @param {Roo.util.ClickRepeater} this
14294      */
14295         "click" : true,
14296     /**
14297      * @event mouseup
14298      * Fires when the mouse key is released.
14299      * @param {Roo.util.ClickRepeater} this
14300      */
14301         "mouseup" : true
14302     });
14303
14304     this.el.on("mousedown", this.handleMouseDown, this);
14305     if(this.preventDefault || this.stopDefault){
14306         this.el.on("click", function(e){
14307             if(this.preventDefault){
14308                 e.preventDefault();
14309             }
14310             if(this.stopDefault){
14311                 e.stopEvent();
14312             }
14313         }, this);
14314     }
14315
14316     // allow inline handler
14317     if(this.handler){
14318         this.on("click", this.handler,  this.scope || this);
14319     }
14320
14321     Roo.util.ClickRepeater.superclass.constructor.call(this);
14322 };
14323
14324 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14325     interval : 20,
14326     delay: 250,
14327     preventDefault : true,
14328     stopDefault : false,
14329     timer : 0,
14330
14331     // private
14332     handleMouseDown : function(){
14333         clearTimeout(this.timer);
14334         this.el.blur();
14335         if(this.pressClass){
14336             this.el.addClass(this.pressClass);
14337         }
14338         this.mousedownTime = new Date();
14339
14340         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14341         this.el.on("mouseout", this.handleMouseOut, this);
14342
14343         this.fireEvent("mousedown", this);
14344         this.fireEvent("click", this);
14345         
14346         this.timer = this.click.defer(this.delay || this.interval, this);
14347     },
14348
14349     // private
14350     click : function(){
14351         this.fireEvent("click", this);
14352         this.timer = this.click.defer(this.getInterval(), this);
14353     },
14354
14355     // private
14356     getInterval: function(){
14357         if(!this.accelerate){
14358             return this.interval;
14359         }
14360         var pressTime = this.mousedownTime.getElapsed();
14361         if(pressTime < 500){
14362             return 400;
14363         }else if(pressTime < 1700){
14364             return 320;
14365         }else if(pressTime < 2600){
14366             return 250;
14367         }else if(pressTime < 3500){
14368             return 180;
14369         }else if(pressTime < 4400){
14370             return 140;
14371         }else if(pressTime < 5300){
14372             return 80;
14373         }else if(pressTime < 6200){
14374             return 50;
14375         }else{
14376             return 10;
14377         }
14378     },
14379
14380     // private
14381     handleMouseOut : function(){
14382         clearTimeout(this.timer);
14383         if(this.pressClass){
14384             this.el.removeClass(this.pressClass);
14385         }
14386         this.el.on("mouseover", this.handleMouseReturn, this);
14387     },
14388
14389     // private
14390     handleMouseReturn : function(){
14391         this.el.un("mouseover", this.handleMouseReturn);
14392         if(this.pressClass){
14393             this.el.addClass(this.pressClass);
14394         }
14395         this.click();
14396     },
14397
14398     // private
14399     handleMouseUp : function(){
14400         clearTimeout(this.timer);
14401         this.el.un("mouseover", this.handleMouseReturn);
14402         this.el.un("mouseout", this.handleMouseOut);
14403         Roo.get(document).un("mouseup", this.handleMouseUp);
14404         this.el.removeClass(this.pressClass);
14405         this.fireEvent("mouseup", this);
14406     }
14407 });/*
14408  * Based on:
14409  * Ext JS Library 1.1.1
14410  * Copyright(c) 2006-2007, Ext JS, LLC.
14411  *
14412  * Originally Released Under LGPL - original licence link has changed is not relivant.
14413  *
14414  * Fork - LGPL
14415  * <script type="text/javascript">
14416  */
14417
14418  
14419 /**
14420  * @class Roo.KeyNav
14421  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14422  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14423  * way to implement custom navigation schemes for any UI component.</p>
14424  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14425  * pageUp, pageDown, del, home, end.  Usage:</p>
14426  <pre><code>
14427 var nav = new Roo.KeyNav("my-element", {
14428     "left" : function(e){
14429         this.moveLeft(e.ctrlKey);
14430     },
14431     "right" : function(e){
14432         this.moveRight(e.ctrlKey);
14433     },
14434     "enter" : function(e){
14435         this.save();
14436     },
14437     scope : this
14438 });
14439 </code></pre>
14440  * @constructor
14441  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14442  * @param {Object} config The config
14443  */
14444 Roo.KeyNav = function(el, config){
14445     this.el = Roo.get(el);
14446     Roo.apply(this, config);
14447     if(!this.disabled){
14448         this.disabled = true;
14449         this.enable();
14450     }
14451 };
14452
14453 Roo.KeyNav.prototype = {
14454     /**
14455      * @cfg {Boolean} disabled
14456      * True to disable this KeyNav instance (defaults to false)
14457      */
14458     disabled : false,
14459     /**
14460      * @cfg {String} defaultEventAction
14461      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14462      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14463      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14464      */
14465     defaultEventAction: "stopEvent",
14466     /**
14467      * @cfg {Boolean} forceKeyDown
14468      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14469      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14470      * handle keydown instead of keypress.
14471      */
14472     forceKeyDown : false,
14473
14474     // private
14475     prepareEvent : function(e){
14476         var k = e.getKey();
14477         var h = this.keyToHandler[k];
14478         //if(h && this[h]){
14479         //    e.stopPropagation();
14480         //}
14481         if(Roo.isSafari && h && k >= 37 && k <= 40){
14482             e.stopEvent();
14483         }
14484     },
14485
14486     // private
14487     relay : function(e){
14488         var k = e.getKey();
14489         var h = this.keyToHandler[k];
14490         if(h && this[h]){
14491             if(this.doRelay(e, this[h], h) !== true){
14492                 e[this.defaultEventAction]();
14493             }
14494         }
14495     },
14496
14497     // private
14498     doRelay : function(e, h, hname){
14499         return h.call(this.scope || this, e);
14500     },
14501
14502     // possible handlers
14503     enter : false,
14504     left : false,
14505     right : false,
14506     up : false,
14507     down : false,
14508     tab : false,
14509     esc : false,
14510     pageUp : false,
14511     pageDown : false,
14512     del : false,
14513     home : false,
14514     end : false,
14515
14516     // quick lookup hash
14517     keyToHandler : {
14518         37 : "left",
14519         39 : "right",
14520         38 : "up",
14521         40 : "down",
14522         33 : "pageUp",
14523         34 : "pageDown",
14524         46 : "del",
14525         36 : "home",
14526         35 : "end",
14527         13 : "enter",
14528         27 : "esc",
14529         9  : "tab"
14530     },
14531
14532         /**
14533          * Enable this KeyNav
14534          */
14535         enable: function(){
14536                 if(this.disabled){
14537             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14538             // the EventObject will normalize Safari automatically
14539             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14540                 this.el.on("keydown", this.relay,  this);
14541             }else{
14542                 this.el.on("keydown", this.prepareEvent,  this);
14543                 this.el.on("keypress", this.relay,  this);
14544             }
14545                     this.disabled = false;
14546                 }
14547         },
14548
14549         /**
14550          * Disable this KeyNav
14551          */
14552         disable: function(){
14553                 if(!this.disabled){
14554                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14555                 this.el.un("keydown", this.relay);
14556             }else{
14557                 this.el.un("keydown", this.prepareEvent);
14558                 this.el.un("keypress", this.relay);
14559             }
14560                     this.disabled = true;
14561                 }
14562         }
14563 };/*
14564  * Based on:
14565  * Ext JS Library 1.1.1
14566  * Copyright(c) 2006-2007, Ext JS, LLC.
14567  *
14568  * Originally Released Under LGPL - original licence link has changed is not relivant.
14569  *
14570  * Fork - LGPL
14571  * <script type="text/javascript">
14572  */
14573
14574  
14575 /**
14576  * @class Roo.KeyMap
14577  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14578  * The constructor accepts the same config object as defined by {@link #addBinding}.
14579  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14580  * combination it will call the function with this signature (if the match is a multi-key
14581  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14582  * A KeyMap can also handle a string representation of keys.<br />
14583  * Usage:
14584  <pre><code>
14585 // map one key by key code
14586 var map = new Roo.KeyMap("my-element", {
14587     key: 13, // or Roo.EventObject.ENTER
14588     fn: myHandler,
14589     scope: myObject
14590 });
14591
14592 // map multiple keys to one action by string
14593 var map = new Roo.KeyMap("my-element", {
14594     key: "a\r\n\t",
14595     fn: myHandler,
14596     scope: myObject
14597 });
14598
14599 // map multiple keys to multiple actions by strings and array of codes
14600 var map = new Roo.KeyMap("my-element", [
14601     {
14602         key: [10,13],
14603         fn: function(){ alert("Return was pressed"); }
14604     }, {
14605         key: "abc",
14606         fn: function(){ alert('a, b or c was pressed'); }
14607     }, {
14608         key: "\t",
14609         ctrl:true,
14610         shift:true,
14611         fn: function(){ alert('Control + shift + tab was pressed.'); }
14612     }
14613 ]);
14614 </code></pre>
14615  * <b>Note: A KeyMap starts enabled</b>
14616  * @constructor
14617  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14618  * @param {Object} config The config (see {@link #addBinding})
14619  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14620  */
14621 Roo.KeyMap = function(el, config, eventName){
14622     this.el  = Roo.get(el);
14623     this.eventName = eventName || "keydown";
14624     this.bindings = [];
14625     if(config){
14626         this.addBinding(config);
14627     }
14628     this.enable();
14629 };
14630
14631 Roo.KeyMap.prototype = {
14632     /**
14633      * True to stop the event from bubbling and prevent the default browser action if the
14634      * key was handled by the KeyMap (defaults to false)
14635      * @type Boolean
14636      */
14637     stopEvent : false,
14638
14639     /**
14640      * Add a new binding to this KeyMap. The following config object properties are supported:
14641      * <pre>
14642 Property    Type             Description
14643 ----------  ---------------  ----------------------------------------------------------------------
14644 key         String/Array     A single keycode or an array of keycodes to handle
14645 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14646 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14647 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14648 fn          Function         The function to call when KeyMap finds the expected key combination
14649 scope       Object           The scope of the callback function
14650 </pre>
14651      *
14652      * Usage:
14653      * <pre><code>
14654 // Create a KeyMap
14655 var map = new Roo.KeyMap(document, {
14656     key: Roo.EventObject.ENTER,
14657     fn: handleKey,
14658     scope: this
14659 });
14660
14661 //Add a new binding to the existing KeyMap later
14662 map.addBinding({
14663     key: 'abc',
14664     shift: true,
14665     fn: handleKey,
14666     scope: this
14667 });
14668 </code></pre>
14669      * @param {Object/Array} config A single KeyMap config or an array of configs
14670      */
14671         addBinding : function(config){
14672         if(config instanceof Array){
14673             for(var i = 0, len = config.length; i < len; i++){
14674                 this.addBinding(config[i]);
14675             }
14676             return;
14677         }
14678         var keyCode = config.key,
14679             shift = config.shift, 
14680             ctrl = config.ctrl, 
14681             alt = config.alt,
14682             fn = config.fn,
14683             scope = config.scope;
14684         if(typeof keyCode == "string"){
14685             var ks = [];
14686             var keyString = keyCode.toUpperCase();
14687             for(var j = 0, len = keyString.length; j < len; j++){
14688                 ks.push(keyString.charCodeAt(j));
14689             }
14690             keyCode = ks;
14691         }
14692         var keyArray = keyCode instanceof Array;
14693         var handler = function(e){
14694             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14695                 var k = e.getKey();
14696                 if(keyArray){
14697                     for(var i = 0, len = keyCode.length; i < len; i++){
14698                         if(keyCode[i] == k){
14699                           if(this.stopEvent){
14700                               e.stopEvent();
14701                           }
14702                           fn.call(scope || window, k, e);
14703                           return;
14704                         }
14705                     }
14706                 }else{
14707                     if(k == keyCode){
14708                         if(this.stopEvent){
14709                            e.stopEvent();
14710                         }
14711                         fn.call(scope || window, k, e);
14712                     }
14713                 }
14714             }
14715         };
14716         this.bindings.push(handler);  
14717         },
14718
14719     /**
14720      * Shorthand for adding a single key listener
14721      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14722      * following options:
14723      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14724      * @param {Function} fn The function to call
14725      * @param {Object} scope (optional) The scope of the function
14726      */
14727     on : function(key, fn, scope){
14728         var keyCode, shift, ctrl, alt;
14729         if(typeof key == "object" && !(key instanceof Array)){
14730             keyCode = key.key;
14731             shift = key.shift;
14732             ctrl = key.ctrl;
14733             alt = key.alt;
14734         }else{
14735             keyCode = key;
14736         }
14737         this.addBinding({
14738             key: keyCode,
14739             shift: shift,
14740             ctrl: ctrl,
14741             alt: alt,
14742             fn: fn,
14743             scope: scope
14744         })
14745     },
14746
14747     // private
14748     handleKeyDown : function(e){
14749             if(this.enabled){ //just in case
14750             var b = this.bindings;
14751             for(var i = 0, len = b.length; i < len; i++){
14752                 b[i].call(this, e);
14753             }
14754             }
14755         },
14756         
14757         /**
14758          * Returns true if this KeyMap is enabled
14759          * @return {Boolean} 
14760          */
14761         isEnabled : function(){
14762             return this.enabled;  
14763         },
14764         
14765         /**
14766          * Enables this KeyMap
14767          */
14768         enable: function(){
14769                 if(!this.enabled){
14770                     this.el.on(this.eventName, this.handleKeyDown, this);
14771                     this.enabled = true;
14772                 }
14773         },
14774
14775         /**
14776          * Disable this KeyMap
14777          */
14778         disable: function(){
14779                 if(this.enabled){
14780                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14781                     this.enabled = false;
14782                 }
14783         }
14784 };/*
14785  * Based on:
14786  * Ext JS Library 1.1.1
14787  * Copyright(c) 2006-2007, Ext JS, LLC.
14788  *
14789  * Originally Released Under LGPL - original licence link has changed is not relivant.
14790  *
14791  * Fork - LGPL
14792  * <script type="text/javascript">
14793  */
14794
14795  
14796 /**
14797  * @class Roo.util.TextMetrics
14798  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14799  * wide, in pixels, a given block of text will be.
14800  * @singleton
14801  */
14802 Roo.util.TextMetrics = function(){
14803     var shared;
14804     return {
14805         /**
14806          * Measures the size of the specified text
14807          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14808          * that can affect the size of the rendered text
14809          * @param {String} text The text to measure
14810          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14811          * in order to accurately measure the text height
14812          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14813          */
14814         measure : function(el, text, fixedWidth){
14815             if(!shared){
14816                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14817             }
14818             shared.bind(el);
14819             shared.setFixedWidth(fixedWidth || 'auto');
14820             return shared.getSize(text);
14821         },
14822
14823         /**
14824          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14825          * the overhead of multiple calls to initialize the style properties on each measurement.
14826          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14827          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14828          * in order to accurately measure the text height
14829          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14830          */
14831         createInstance : function(el, fixedWidth){
14832             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14833         }
14834     };
14835 }();
14836
14837  
14838
14839 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14840     var ml = new Roo.Element(document.createElement('div'));
14841     document.body.appendChild(ml.dom);
14842     ml.position('absolute');
14843     ml.setLeftTop(-1000, -1000);
14844     ml.hide();
14845
14846     if(fixedWidth){
14847         ml.setWidth(fixedWidth);
14848     }
14849      
14850     var instance = {
14851         /**
14852          * Returns the size of the specified text based on the internal element's style and width properties
14853          * @memberOf Roo.util.TextMetrics.Instance#
14854          * @param {String} text The text to measure
14855          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14856          */
14857         getSize : function(text){
14858             ml.update(text);
14859             var s = ml.getSize();
14860             ml.update('');
14861             return s;
14862         },
14863
14864         /**
14865          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14866          * that can affect the size of the rendered text
14867          * @memberOf Roo.util.TextMetrics.Instance#
14868          * @param {String/HTMLElement} el The element, dom node or id
14869          */
14870         bind : function(el){
14871             ml.setStyle(
14872                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14873             );
14874         },
14875
14876         /**
14877          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14878          * to set a fixed width in order to accurately measure the text height.
14879          * @memberOf Roo.util.TextMetrics.Instance#
14880          * @param {Number} width The width to set on the element
14881          */
14882         setFixedWidth : function(width){
14883             ml.setWidth(width);
14884         },
14885
14886         /**
14887          * Returns the measured width of the specified text
14888          * @memberOf Roo.util.TextMetrics.Instance#
14889          * @param {String} text The text to measure
14890          * @return {Number} width The width in pixels
14891          */
14892         getWidth : function(text){
14893             ml.dom.style.width = 'auto';
14894             return this.getSize(text).width;
14895         },
14896
14897         /**
14898          * Returns the measured height of the specified text.  For multiline text, be sure to call
14899          * {@link #setFixedWidth} if necessary.
14900          * @memberOf Roo.util.TextMetrics.Instance#
14901          * @param {String} text The text to measure
14902          * @return {Number} height The height in pixels
14903          */
14904         getHeight : function(text){
14905             return this.getSize(text).height;
14906         }
14907     };
14908
14909     instance.bind(bindTo);
14910
14911     return instance;
14912 };
14913
14914 // backwards compat
14915 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14916  * Based on:
14917  * Ext JS Library 1.1.1
14918  * Copyright(c) 2006-2007, Ext JS, LLC.
14919  *
14920  * Originally Released Under LGPL - original licence link has changed is not relivant.
14921  *
14922  * Fork - LGPL
14923  * <script type="text/javascript">
14924  */
14925
14926 /**
14927  * @class Roo.state.Provider
14928  * Abstract base class for state provider implementations. This class provides methods
14929  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14930  * Provider interface.
14931  */
14932 Roo.state.Provider = function(){
14933     /**
14934      * @event statechange
14935      * Fires when a state change occurs.
14936      * @param {Provider} this This state provider
14937      * @param {String} key The state key which was changed
14938      * @param {String} value The encoded value for the state
14939      */
14940     this.addEvents({
14941         "statechange": true
14942     });
14943     this.state = {};
14944     Roo.state.Provider.superclass.constructor.call(this);
14945 };
14946 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14947     /**
14948      * Returns the current value for a key
14949      * @param {String} name The key name
14950      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14951      * @return {Mixed} The state data
14952      */
14953     get : function(name, defaultValue){
14954         return typeof this.state[name] == "undefined" ?
14955             defaultValue : this.state[name];
14956     },
14957     
14958     /**
14959      * Clears a value from the state
14960      * @param {String} name The key name
14961      */
14962     clear : function(name){
14963         delete this.state[name];
14964         this.fireEvent("statechange", this, name, null);
14965     },
14966     
14967     /**
14968      * Sets the value for a key
14969      * @param {String} name The key name
14970      * @param {Mixed} value The value to set
14971      */
14972     set : function(name, value){
14973         this.state[name] = value;
14974         this.fireEvent("statechange", this, name, value);
14975     },
14976     
14977     /**
14978      * Decodes a string previously encoded with {@link #encodeValue}.
14979      * @param {String} value The value to decode
14980      * @return {Mixed} The decoded value
14981      */
14982     decodeValue : function(cookie){
14983         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14984         var matches = re.exec(unescape(cookie));
14985         if(!matches || !matches[1]) {
14986             return; // non state cookie
14987         }
14988         var type = matches[1];
14989         var v = matches[2];
14990         switch(type){
14991             case "n":
14992                 return parseFloat(v);
14993             case "d":
14994                 return new Date(Date.parse(v));
14995             case "b":
14996                 return (v == "1");
14997             case "a":
14998                 var all = [];
14999                 var values = v.split("^");
15000                 for(var i = 0, len = values.length; i < len; i++){
15001                     all.push(this.decodeValue(values[i]));
15002                 }
15003                 return all;
15004            case "o":
15005                 var all = {};
15006                 var values = v.split("^");
15007                 for(var i = 0, len = values.length; i < len; i++){
15008                     var kv = values[i].split("=");
15009                     all[kv[0]] = this.decodeValue(kv[1]);
15010                 }
15011                 return all;
15012            default:
15013                 return v;
15014         }
15015     },
15016     
15017     /**
15018      * Encodes a value including type information.  Decode with {@link #decodeValue}.
15019      * @param {Mixed} value The value to encode
15020      * @return {String} The encoded value
15021      */
15022     encodeValue : function(v){
15023         var enc;
15024         if(typeof v == "number"){
15025             enc = "n:" + v;
15026         }else if(typeof v == "boolean"){
15027             enc = "b:" + (v ? "1" : "0");
15028         }else if(v instanceof Date){
15029             enc = "d:" + v.toGMTString();
15030         }else if(v instanceof Array){
15031             var flat = "";
15032             for(var i = 0, len = v.length; i < len; i++){
15033                 flat += this.encodeValue(v[i]);
15034                 if(i != len-1) {
15035                     flat += "^";
15036                 }
15037             }
15038             enc = "a:" + flat;
15039         }else if(typeof v == "object"){
15040             var flat = "";
15041             for(var key in v){
15042                 if(typeof v[key] != "function"){
15043                     flat += key + "=" + this.encodeValue(v[key]) + "^";
15044                 }
15045             }
15046             enc = "o:" + flat.substring(0, flat.length-1);
15047         }else{
15048             enc = "s:" + v;
15049         }
15050         return escape(enc);        
15051     }
15052 });
15053
15054 /*
15055  * Based on:
15056  * Ext JS Library 1.1.1
15057  * Copyright(c) 2006-2007, Ext JS, LLC.
15058  *
15059  * Originally Released Under LGPL - original licence link has changed is not relivant.
15060  *
15061  * Fork - LGPL
15062  * <script type="text/javascript">
15063  */
15064 /**
15065  * @class Roo.state.Manager
15066  * This is the global state manager. By default all components that are "state aware" check this class
15067  * for state information if you don't pass them a custom state provider. In order for this class
15068  * to be useful, it must be initialized with a provider when your application initializes.
15069  <pre><code>
15070 // in your initialization function
15071 init : function(){
15072    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15073    ...
15074    // supposed you have a {@link Roo.BorderLayout}
15075    var layout = new Roo.BorderLayout(...);
15076    layout.restoreState();
15077    // or a {Roo.BasicDialog}
15078    var dialog = new Roo.BasicDialog(...);
15079    dialog.restoreState();
15080  </code></pre>
15081  * @singleton
15082  */
15083 Roo.state.Manager = function(){
15084     var provider = new Roo.state.Provider();
15085     
15086     return {
15087         /**
15088          * Configures the default state provider for your application
15089          * @param {Provider} stateProvider The state provider to set
15090          */
15091         setProvider : function(stateProvider){
15092             provider = stateProvider;
15093         },
15094         
15095         /**
15096          * Returns the current value for a key
15097          * @param {String} name The key name
15098          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15099          * @return {Mixed} The state data
15100          */
15101         get : function(key, defaultValue){
15102             return provider.get(key, defaultValue);
15103         },
15104         
15105         /**
15106          * Sets the value for a key
15107          * @param {String} name The key name
15108          * @param {Mixed} value The state data
15109          */
15110          set : function(key, value){
15111             provider.set(key, value);
15112         },
15113         
15114         /**
15115          * Clears a value from the state
15116          * @param {String} name The key name
15117          */
15118         clear : function(key){
15119             provider.clear(key);
15120         },
15121         
15122         /**
15123          * Gets the currently configured state provider
15124          * @return {Provider} The state provider
15125          */
15126         getProvider : function(){
15127             return provider;
15128         }
15129     };
15130 }();
15131 /*
15132  * Based on:
15133  * Ext JS Library 1.1.1
15134  * Copyright(c) 2006-2007, Ext JS, LLC.
15135  *
15136  * Originally Released Under LGPL - original licence link has changed is not relivant.
15137  *
15138  * Fork - LGPL
15139  * <script type="text/javascript">
15140  */
15141 /**
15142  * @class Roo.state.CookieProvider
15143  * @extends Roo.state.Provider
15144  * The default Provider implementation which saves state via cookies.
15145  * <br />Usage:
15146  <pre><code>
15147    var cp = new Roo.state.CookieProvider({
15148        path: "/cgi-bin/",
15149        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15150        domain: "roojs.com"
15151    })
15152    Roo.state.Manager.setProvider(cp);
15153  </code></pre>
15154  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15155  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15156  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15157  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15158  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15159  * domain the page is running on including the 'www' like 'www.roojs.com')
15160  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15161  * @constructor
15162  * Create a new CookieProvider
15163  * @param {Object} config The configuration object
15164  */
15165 Roo.state.CookieProvider = function(config){
15166     Roo.state.CookieProvider.superclass.constructor.call(this);
15167     this.path = "/";
15168     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15169     this.domain = null;
15170     this.secure = false;
15171     Roo.apply(this, config);
15172     this.state = this.readCookies();
15173 };
15174
15175 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15176     // private
15177     set : function(name, value){
15178         if(typeof value == "undefined" || value === null){
15179             this.clear(name);
15180             return;
15181         }
15182         this.setCookie(name, value);
15183         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15184     },
15185
15186     // private
15187     clear : function(name){
15188         this.clearCookie(name);
15189         Roo.state.CookieProvider.superclass.clear.call(this, name);
15190     },
15191
15192     // private
15193     readCookies : function(){
15194         var cookies = {};
15195         var c = document.cookie + ";";
15196         var re = /\s?(.*?)=(.*?);/g;
15197         var matches;
15198         while((matches = re.exec(c)) != null){
15199             var name = matches[1];
15200             var value = matches[2];
15201             if(name && name.substring(0,3) == "ys-"){
15202                 cookies[name.substr(3)] = this.decodeValue(value);
15203             }
15204         }
15205         return cookies;
15206     },
15207
15208     // private
15209     setCookie : function(name, value){
15210         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15211            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15212            ((this.path == null) ? "" : ("; path=" + this.path)) +
15213            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15214            ((this.secure == true) ? "; secure" : "");
15215     },
15216
15217     // private
15218     clearCookie : function(name){
15219         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15220            ((this.path == null) ? "" : ("; path=" + this.path)) +
15221            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15222            ((this.secure == true) ? "; secure" : "");
15223     }
15224 });/*
15225  * Based on:
15226  * Ext JS Library 1.1.1
15227  * Copyright(c) 2006-2007, Ext JS, LLC.
15228  *
15229  * Originally Released Under LGPL - original licence link has changed is not relivant.
15230  *
15231  * Fork - LGPL
15232  * <script type="text/javascript">
15233  */
15234  
15235
15236 /**
15237  * @class Roo.ComponentMgr
15238  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15239  * @singleton
15240  */
15241 Roo.ComponentMgr = function(){
15242     var all = new Roo.util.MixedCollection();
15243
15244     return {
15245         /**
15246          * Registers a component.
15247          * @param {Roo.Component} c The component
15248          */
15249         register : function(c){
15250             all.add(c);
15251         },
15252
15253         /**
15254          * Unregisters a component.
15255          * @param {Roo.Component} c The component
15256          */
15257         unregister : function(c){
15258             all.remove(c);
15259         },
15260
15261         /**
15262          * Returns a component by id
15263          * @param {String} id The component id
15264          */
15265         get : function(id){
15266             return all.get(id);
15267         },
15268
15269         /**
15270          * Registers a function that will be called when a specified component is added to ComponentMgr
15271          * @param {String} id The component id
15272          * @param {Funtction} fn The callback function
15273          * @param {Object} scope The scope of the callback
15274          */
15275         onAvailable : function(id, fn, scope){
15276             all.on("add", function(index, o){
15277                 if(o.id == id){
15278                     fn.call(scope || o, o);
15279                     all.un("add", fn, scope);
15280                 }
15281             });
15282         }
15283     };
15284 }();/*
15285  * Based on:
15286  * Ext JS Library 1.1.1
15287  * Copyright(c) 2006-2007, Ext JS, LLC.
15288  *
15289  * Originally Released Under LGPL - original licence link has changed is not relivant.
15290  *
15291  * Fork - LGPL
15292  * <script type="text/javascript">
15293  */
15294  
15295 /**
15296  * @class Roo.Component
15297  * @extends Roo.util.Observable
15298  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15299  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15300  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15301  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15302  * All visual components (widgets) that require rendering into a layout should subclass Component.
15303  * @constructor
15304  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15305  * 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
15306  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15307  */
15308 Roo.Component = function(config){
15309     config = config || {};
15310     if(config.tagName || config.dom || typeof config == "string"){ // element object
15311         config = {el: config, id: config.id || config};
15312     }
15313     this.initialConfig = config;
15314
15315     Roo.apply(this, config);
15316     this.addEvents({
15317         /**
15318          * @event disable
15319          * Fires after the component is disabled.
15320              * @param {Roo.Component} this
15321              */
15322         disable : true,
15323         /**
15324          * @event enable
15325          * Fires after the component is enabled.
15326              * @param {Roo.Component} this
15327              */
15328         enable : true,
15329         /**
15330          * @event beforeshow
15331          * Fires before the component is shown.  Return false to stop the show.
15332              * @param {Roo.Component} this
15333              */
15334         beforeshow : true,
15335         /**
15336          * @event show
15337          * Fires after the component is shown.
15338              * @param {Roo.Component} this
15339              */
15340         show : true,
15341         /**
15342          * @event beforehide
15343          * Fires before the component is hidden. Return false to stop the hide.
15344              * @param {Roo.Component} this
15345              */
15346         beforehide : true,
15347         /**
15348          * @event hide
15349          * Fires after the component is hidden.
15350              * @param {Roo.Component} this
15351              */
15352         hide : true,
15353         /**
15354          * @event beforerender
15355          * Fires before the component is rendered. Return false to stop the render.
15356              * @param {Roo.Component} this
15357              */
15358         beforerender : true,
15359         /**
15360          * @event render
15361          * Fires after the component is rendered.
15362              * @param {Roo.Component} this
15363              */
15364         render : true,
15365         /**
15366          * @event beforedestroy
15367          * Fires before the component is destroyed. Return false to stop the destroy.
15368              * @param {Roo.Component} this
15369              */
15370         beforedestroy : true,
15371         /**
15372          * @event destroy
15373          * Fires after the component is destroyed.
15374              * @param {Roo.Component} this
15375              */
15376         destroy : true
15377     });
15378     if(!this.id){
15379         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15380     }
15381     Roo.ComponentMgr.register(this);
15382     Roo.Component.superclass.constructor.call(this);
15383     this.initComponent();
15384     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15385         this.render(this.renderTo);
15386         delete this.renderTo;
15387     }
15388 };
15389
15390 /** @private */
15391 Roo.Component.AUTO_ID = 1000;
15392
15393 Roo.extend(Roo.Component, Roo.util.Observable, {
15394     /**
15395      * @scope Roo.Component.prototype
15396      * @type {Boolean}
15397      * true if this component is hidden. Read-only.
15398      */
15399     hidden : false,
15400     /**
15401      * @type {Boolean}
15402      * true if this component is disabled. Read-only.
15403      */
15404     disabled : false,
15405     /**
15406      * @type {Boolean}
15407      * true if this component has been rendered. Read-only.
15408      */
15409     rendered : false,
15410     
15411     /** @cfg {String} disableClass
15412      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15413      */
15414     disabledClass : "x-item-disabled",
15415         /** @cfg {Boolean} allowDomMove
15416          * Whether the component can move the Dom node when rendering (defaults to true).
15417          */
15418     allowDomMove : true,
15419     /** @cfg {String} hideMode (display|visibility)
15420      * How this component should hidden. Supported values are
15421      * "visibility" (css visibility), "offsets" (negative offset position) and
15422      * "display" (css display) - defaults to "display".
15423      */
15424     hideMode: 'display',
15425
15426     /** @private */
15427     ctype : "Roo.Component",
15428
15429     /**
15430      * @cfg {String} actionMode 
15431      * which property holds the element that used for  hide() / show() / disable() / enable()
15432      * default is 'el' 
15433      */
15434     actionMode : "el",
15435
15436     /** @private */
15437     getActionEl : function(){
15438         return this[this.actionMode];
15439     },
15440
15441     initComponent : Roo.emptyFn,
15442     /**
15443      * If this is a lazy rendering component, render it to its container element.
15444      * @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.
15445      */
15446     render : function(container, position){
15447         
15448         if(this.rendered){
15449             return this;
15450         }
15451         
15452         if(this.fireEvent("beforerender", this) === false){
15453             return false;
15454         }
15455         
15456         if(!container && this.el){
15457             this.el = Roo.get(this.el);
15458             container = this.el.dom.parentNode;
15459             this.allowDomMove = false;
15460         }
15461         this.container = Roo.get(container);
15462         this.rendered = true;
15463         if(position !== undefined){
15464             if(typeof position == 'number'){
15465                 position = this.container.dom.childNodes[position];
15466             }else{
15467                 position = Roo.getDom(position);
15468             }
15469         }
15470         this.onRender(this.container, position || null);
15471         if(this.cls){
15472             this.el.addClass(this.cls);
15473             delete this.cls;
15474         }
15475         if(this.style){
15476             this.el.applyStyles(this.style);
15477             delete this.style;
15478         }
15479         this.fireEvent("render", this);
15480         this.afterRender(this.container);
15481         if(this.hidden){
15482             this.hide();
15483         }
15484         if(this.disabled){
15485             this.disable();
15486         }
15487
15488         return this;
15489         
15490     },
15491
15492     /** @private */
15493     // default function is not really useful
15494     onRender : function(ct, position){
15495         if(this.el){
15496             this.el = Roo.get(this.el);
15497             if(this.allowDomMove !== false){
15498                 ct.dom.insertBefore(this.el.dom, position);
15499             }
15500         }
15501     },
15502
15503     /** @private */
15504     getAutoCreate : function(){
15505         var cfg = typeof this.autoCreate == "object" ?
15506                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15507         if(this.id && !cfg.id){
15508             cfg.id = this.id;
15509         }
15510         return cfg;
15511     },
15512
15513     /** @private */
15514     afterRender : Roo.emptyFn,
15515
15516     /**
15517      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15518      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15519      */
15520     destroy : function(){
15521         if(this.fireEvent("beforedestroy", this) !== false){
15522             this.purgeListeners();
15523             this.beforeDestroy();
15524             if(this.rendered){
15525                 this.el.removeAllListeners();
15526                 this.el.remove();
15527                 if(this.actionMode == "container"){
15528                     this.container.remove();
15529                 }
15530             }
15531             this.onDestroy();
15532             Roo.ComponentMgr.unregister(this);
15533             this.fireEvent("destroy", this);
15534         }
15535     },
15536
15537         /** @private */
15538     beforeDestroy : function(){
15539
15540     },
15541
15542         /** @private */
15543         onDestroy : function(){
15544
15545     },
15546
15547     /**
15548      * Returns the underlying {@link Roo.Element}.
15549      * @return {Roo.Element} The element
15550      */
15551     getEl : function(){
15552         return this.el;
15553     },
15554
15555     /**
15556      * Returns the id of this component.
15557      * @return {String}
15558      */
15559     getId : function(){
15560         return this.id;
15561     },
15562
15563     /**
15564      * Try to focus this component.
15565      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15566      * @return {Roo.Component} this
15567      */
15568     focus : function(selectText){
15569         if(this.rendered){
15570             this.el.focus();
15571             if(selectText === true){
15572                 this.el.dom.select();
15573             }
15574         }
15575         return this;
15576     },
15577
15578     /** @private */
15579     blur : function(){
15580         if(this.rendered){
15581             this.el.blur();
15582         }
15583         return this;
15584     },
15585
15586     /**
15587      * Disable this component.
15588      * @return {Roo.Component} this
15589      */
15590     disable : function(){
15591         if(this.rendered){
15592             this.onDisable();
15593         }
15594         this.disabled = true;
15595         this.fireEvent("disable", this);
15596         return this;
15597     },
15598
15599         // private
15600     onDisable : function(){
15601         this.getActionEl().addClass(this.disabledClass);
15602         this.el.dom.disabled = true;
15603     },
15604
15605     /**
15606      * Enable this component.
15607      * @return {Roo.Component} this
15608      */
15609     enable : function(){
15610         if(this.rendered){
15611             this.onEnable();
15612         }
15613         this.disabled = false;
15614         this.fireEvent("enable", this);
15615         return this;
15616     },
15617
15618         // private
15619     onEnable : function(){
15620         this.getActionEl().removeClass(this.disabledClass);
15621         this.el.dom.disabled = false;
15622     },
15623
15624     /**
15625      * Convenience function for setting disabled/enabled by boolean.
15626      * @param {Boolean} disabled
15627      */
15628     setDisabled : function(disabled){
15629         this[disabled ? "disable" : "enable"]();
15630     },
15631
15632     /**
15633      * Show this component.
15634      * @return {Roo.Component} this
15635      */
15636     show: function(){
15637         if(this.fireEvent("beforeshow", this) !== false){
15638             this.hidden = false;
15639             if(this.rendered){
15640                 this.onShow();
15641             }
15642             this.fireEvent("show", this);
15643         }
15644         return this;
15645     },
15646
15647     // private
15648     onShow : function(){
15649         var ae = this.getActionEl();
15650         if(this.hideMode == 'visibility'){
15651             ae.dom.style.visibility = "visible";
15652         }else if(this.hideMode == 'offsets'){
15653             ae.removeClass('x-hidden');
15654         }else{
15655             ae.dom.style.display = "";
15656         }
15657     },
15658
15659     /**
15660      * Hide this component.
15661      * @return {Roo.Component} this
15662      */
15663     hide: function(){
15664         if(this.fireEvent("beforehide", this) !== false){
15665             this.hidden = true;
15666             if(this.rendered){
15667                 this.onHide();
15668             }
15669             this.fireEvent("hide", this);
15670         }
15671         return this;
15672     },
15673
15674     // private
15675     onHide : function(){
15676         var ae = this.getActionEl();
15677         if(this.hideMode == 'visibility'){
15678             ae.dom.style.visibility = "hidden";
15679         }else if(this.hideMode == 'offsets'){
15680             ae.addClass('x-hidden');
15681         }else{
15682             ae.dom.style.display = "none";
15683         }
15684     },
15685
15686     /**
15687      * Convenience function to hide or show this component by boolean.
15688      * @param {Boolean} visible True to show, false to hide
15689      * @return {Roo.Component} this
15690      */
15691     setVisible: function(visible){
15692         if(visible) {
15693             this.show();
15694         }else{
15695             this.hide();
15696         }
15697         return this;
15698     },
15699
15700     /**
15701      * Returns true if this component is visible.
15702      */
15703     isVisible : function(){
15704         return this.getActionEl().isVisible();
15705     },
15706
15707     cloneConfig : function(overrides){
15708         overrides = overrides || {};
15709         var id = overrides.id || Roo.id();
15710         var cfg = Roo.applyIf(overrides, this.initialConfig);
15711         cfg.id = id; // prevent dup id
15712         return new this.constructor(cfg);
15713     }
15714 });/*
15715  * Based on:
15716  * Ext JS Library 1.1.1
15717  * Copyright(c) 2006-2007, Ext JS, LLC.
15718  *
15719  * Originally Released Under LGPL - original licence link has changed is not relivant.
15720  *
15721  * Fork - LGPL
15722  * <script type="text/javascript">
15723  */
15724
15725 /**
15726  * @class Roo.BoxComponent
15727  * @extends Roo.Component
15728  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15729  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15730  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15731  * layout containers.
15732  * @constructor
15733  * @param {Roo.Element/String/Object} config The configuration options.
15734  */
15735 Roo.BoxComponent = function(config){
15736     Roo.Component.call(this, config);
15737     this.addEvents({
15738         /**
15739          * @event resize
15740          * Fires after the component is resized.
15741              * @param {Roo.Component} this
15742              * @param {Number} adjWidth The box-adjusted width that was set
15743              * @param {Number} adjHeight The box-adjusted height that was set
15744              * @param {Number} rawWidth The width that was originally specified
15745              * @param {Number} rawHeight The height that was originally specified
15746              */
15747         resize : true,
15748         /**
15749          * @event move
15750          * Fires after the component is moved.
15751              * @param {Roo.Component} this
15752              * @param {Number} x The new x position
15753              * @param {Number} y The new y position
15754              */
15755         move : true
15756     });
15757 };
15758
15759 Roo.extend(Roo.BoxComponent, Roo.Component, {
15760     // private, set in afterRender to signify that the component has been rendered
15761     boxReady : false,
15762     // private, used to defer height settings to subclasses
15763     deferHeight: false,
15764     /** @cfg {Number} width
15765      * width (optional) size of component
15766      */
15767      /** @cfg {Number} height
15768      * height (optional) size of component
15769      */
15770      
15771     /**
15772      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15773      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15774      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15775      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15776      * @return {Roo.BoxComponent} this
15777      */
15778     setSize : function(w, h){
15779         // support for standard size objects
15780         if(typeof w == 'object'){
15781             h = w.height;
15782             w = w.width;
15783         }
15784         // not rendered
15785         if(!this.boxReady){
15786             this.width = w;
15787             this.height = h;
15788             return this;
15789         }
15790
15791         // prevent recalcs when not needed
15792         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15793             return this;
15794         }
15795         this.lastSize = {width: w, height: h};
15796
15797         var adj = this.adjustSize(w, h);
15798         var aw = adj.width, ah = adj.height;
15799         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15800             var rz = this.getResizeEl();
15801             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15802                 rz.setSize(aw, ah);
15803             }else if(!this.deferHeight && ah !== undefined){
15804                 rz.setHeight(ah);
15805             }else if(aw !== undefined){
15806                 rz.setWidth(aw);
15807             }
15808             this.onResize(aw, ah, w, h);
15809             this.fireEvent('resize', this, aw, ah, w, h);
15810         }
15811         return this;
15812     },
15813
15814     /**
15815      * Gets the current size of the component's underlying element.
15816      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15817      */
15818     getSize : function(){
15819         return this.el.getSize();
15820     },
15821
15822     /**
15823      * Gets the current XY position of the component's underlying element.
15824      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15825      * @return {Array} The XY position of the element (e.g., [100, 200])
15826      */
15827     getPosition : function(local){
15828         if(local === true){
15829             return [this.el.getLeft(true), this.el.getTop(true)];
15830         }
15831         return this.xy || this.el.getXY();
15832     },
15833
15834     /**
15835      * Gets the current box measurements of the component's underlying element.
15836      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15837      * @returns {Object} box An object in the format {x, y, width, height}
15838      */
15839     getBox : function(local){
15840         var s = this.el.getSize();
15841         if(local){
15842             s.x = this.el.getLeft(true);
15843             s.y = this.el.getTop(true);
15844         }else{
15845             var xy = this.xy || this.el.getXY();
15846             s.x = xy[0];
15847             s.y = xy[1];
15848         }
15849         return s;
15850     },
15851
15852     /**
15853      * Sets the current box measurements of the component's underlying element.
15854      * @param {Object} box An object in the format {x, y, width, height}
15855      * @returns {Roo.BoxComponent} this
15856      */
15857     updateBox : function(box){
15858         this.setSize(box.width, box.height);
15859         this.setPagePosition(box.x, box.y);
15860         return this;
15861     },
15862
15863     // protected
15864     getResizeEl : function(){
15865         return this.resizeEl || this.el;
15866     },
15867
15868     // protected
15869     getPositionEl : function(){
15870         return this.positionEl || this.el;
15871     },
15872
15873     /**
15874      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15875      * This method fires the move event.
15876      * @param {Number} left The new left
15877      * @param {Number} top The new top
15878      * @returns {Roo.BoxComponent} this
15879      */
15880     setPosition : function(x, y){
15881         this.x = x;
15882         this.y = y;
15883         if(!this.boxReady){
15884             return this;
15885         }
15886         var adj = this.adjustPosition(x, y);
15887         var ax = adj.x, ay = adj.y;
15888
15889         var el = this.getPositionEl();
15890         if(ax !== undefined || ay !== undefined){
15891             if(ax !== undefined && ay !== undefined){
15892                 el.setLeftTop(ax, ay);
15893             }else if(ax !== undefined){
15894                 el.setLeft(ax);
15895             }else if(ay !== undefined){
15896                 el.setTop(ay);
15897             }
15898             this.onPosition(ax, ay);
15899             this.fireEvent('move', this, ax, ay);
15900         }
15901         return this;
15902     },
15903
15904     /**
15905      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15906      * This method fires the move event.
15907      * @param {Number} x The new x position
15908      * @param {Number} y The new y position
15909      * @returns {Roo.BoxComponent} this
15910      */
15911     setPagePosition : function(x, y){
15912         this.pageX = x;
15913         this.pageY = y;
15914         if(!this.boxReady){
15915             return;
15916         }
15917         if(x === undefined || y === undefined){ // cannot translate undefined points
15918             return;
15919         }
15920         var p = this.el.translatePoints(x, y);
15921         this.setPosition(p.left, p.top);
15922         return this;
15923     },
15924
15925     // private
15926     onRender : function(ct, position){
15927         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15928         if(this.resizeEl){
15929             this.resizeEl = Roo.get(this.resizeEl);
15930         }
15931         if(this.positionEl){
15932             this.positionEl = Roo.get(this.positionEl);
15933         }
15934     },
15935
15936     // private
15937     afterRender : function(){
15938         Roo.BoxComponent.superclass.afterRender.call(this);
15939         this.boxReady = true;
15940         this.setSize(this.width, this.height);
15941         if(this.x || this.y){
15942             this.setPosition(this.x, this.y);
15943         }
15944         if(this.pageX || this.pageY){
15945             this.setPagePosition(this.pageX, this.pageY);
15946         }
15947     },
15948
15949     /**
15950      * Force the component's size to recalculate based on the underlying element's current height and width.
15951      * @returns {Roo.BoxComponent} this
15952      */
15953     syncSize : function(){
15954         delete this.lastSize;
15955         this.setSize(this.el.getWidth(), this.el.getHeight());
15956         return this;
15957     },
15958
15959     /**
15960      * Called after the component is resized, this method is empty by default but can be implemented by any
15961      * subclass that needs to perform custom logic after a resize occurs.
15962      * @param {Number} adjWidth The box-adjusted width that was set
15963      * @param {Number} adjHeight The box-adjusted height that was set
15964      * @param {Number} rawWidth The width that was originally specified
15965      * @param {Number} rawHeight The height that was originally specified
15966      */
15967     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15968
15969     },
15970
15971     /**
15972      * Called after the component is moved, this method is empty by default but can be implemented by any
15973      * subclass that needs to perform custom logic after a move occurs.
15974      * @param {Number} x The new x position
15975      * @param {Number} y The new y position
15976      */
15977     onPosition : function(x, y){
15978
15979     },
15980
15981     // private
15982     adjustSize : function(w, h){
15983         if(this.autoWidth){
15984             w = 'auto';
15985         }
15986         if(this.autoHeight){
15987             h = 'auto';
15988         }
15989         return {width : w, height: h};
15990     },
15991
15992     // private
15993     adjustPosition : function(x, y){
15994         return {x : x, y: y};
15995     }
15996 });/*
15997  * Original code for Roojs - LGPL
15998  * <script type="text/javascript">
15999  */
16000  
16001 /**
16002  * @class Roo.XComponent
16003  * A delayed Element creator...
16004  * Or a way to group chunks of interface together.
16005  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16006  *  used in conjunction with XComponent.build() it will create an instance of each element,
16007  *  then call addxtype() to build the User interface.
16008  * 
16009  * Mypart.xyx = new Roo.XComponent({
16010
16011     parent : 'Mypart.xyz', // empty == document.element.!!
16012     order : '001',
16013     name : 'xxxx'
16014     region : 'xxxx'
16015     disabled : function() {} 
16016      
16017     tree : function() { // return an tree of xtype declared components
16018         var MODULE = this;
16019         return 
16020         {
16021             xtype : 'NestedLayoutPanel',
16022             // technicall
16023         }
16024      ]
16025  *})
16026  *
16027  *
16028  * It can be used to build a big heiracy, with parent etc.
16029  * or you can just use this to render a single compoent to a dom element
16030  * MYPART.render(Roo.Element | String(id) | dom_element )
16031  *
16032  *
16033  * Usage patterns.
16034  *
16035  * Classic Roo
16036  *
16037  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16038  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16039  *
16040  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16041  *
16042  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16043  * - if mulitple topModules exist, the last one is defined as the top module.
16044  *
16045  * Embeded Roo
16046  * 
16047  * When the top level or multiple modules are to embedded into a existing HTML page,
16048  * the parent element can container '#id' of the element where the module will be drawn.
16049  *
16050  * Bootstrap Roo
16051  *
16052  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16053  * it relies more on a include mechanism, where sub modules are included into an outer page.
16054  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16055  * 
16056  * Bootstrap Roo Included elements
16057  *
16058  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16059  * hence confusing the component builder as it thinks there are multiple top level elements. 
16060  *
16061  * String Over-ride & Translations
16062  *
16063  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16064  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16065  * are needed. @see Roo.XComponent.overlayString  
16066  * 
16067  * 
16068  * 
16069  * @extends Roo.util.Observable
16070  * @constructor
16071  * @param cfg {Object} configuration of component
16072  * 
16073  */
16074 Roo.XComponent = function(cfg) {
16075     Roo.apply(this, cfg);
16076     this.addEvents({ 
16077         /**
16078              * @event built
16079              * Fires when this the componnt is built
16080              * @param {Roo.XComponent} c the component
16081              */
16082         'built' : true
16083         
16084     });
16085     this.region = this.region || 'center'; // default..
16086     Roo.XComponent.register(this);
16087     this.modules = false;
16088     this.el = false; // where the layout goes..
16089     
16090     
16091 }
16092 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16093     /**
16094      * @property el
16095      * The created element (with Roo.factory())
16096      * @type {Roo.Layout}
16097      */
16098     el  : false,
16099     
16100     /**
16101      * @property el
16102      * for BC  - use el in new code
16103      * @type {Roo.Layout}
16104      */
16105     panel : false,
16106     
16107     /**
16108      * @property layout
16109      * for BC  - use el in new code
16110      * @type {Roo.Layout}
16111      */
16112     layout : false,
16113     
16114      /**
16115      * @cfg {Function|boolean} disabled
16116      * If this module is disabled by some rule, return true from the funtion
16117      */
16118     disabled : false,
16119     
16120     /**
16121      * @cfg {String} parent 
16122      * Name of parent element which it get xtype added to..
16123      */
16124     parent: false,
16125     
16126     /**
16127      * @cfg {String} order
16128      * Used to set the order in which elements are created (usefull for multiple tabs)
16129      */
16130     
16131     order : false,
16132     /**
16133      * @cfg {String} name
16134      * String to display while loading.
16135      */
16136     name : false,
16137     /**
16138      * @cfg {String} region
16139      * Region to render component to (defaults to center)
16140      */
16141     region : 'center',
16142     
16143     /**
16144      * @cfg {Array} items
16145      * A single item array - the first element is the root of the tree..
16146      * It's done this way to stay compatible with the Xtype system...
16147      */
16148     items : false,
16149     
16150     /**
16151      * @property _tree
16152      * The method that retuns the tree of parts that make up this compoennt 
16153      * @type {function}
16154      */
16155     _tree  : false,
16156     
16157      /**
16158      * render
16159      * render element to dom or tree
16160      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16161      */
16162     
16163     render : function(el)
16164     {
16165         
16166         el = el || false;
16167         var hp = this.parent ? 1 : 0;
16168         Roo.debug &&  Roo.log(this);
16169         
16170         var tree = this._tree ? this._tree() : this.tree();
16171
16172         
16173         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16174             // if parent is a '#.....' string, then let's use that..
16175             var ename = this.parent.substr(1);
16176             this.parent = false;
16177             Roo.debug && Roo.log(ename);
16178             switch (ename) {
16179                 case 'bootstrap-body':
16180                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16181                         // this is the BorderLayout standard?
16182                        this.parent = { el : true };
16183                        break;
16184                     }
16185                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16186                         // need to insert stuff...
16187                         this.parent =  {
16188                              el : new Roo.bootstrap.layout.Border({
16189                                  el : document.body, 
16190                      
16191                                  center: {
16192                                     titlebar: false,
16193                                     autoScroll:false,
16194                                     closeOnTab: true,
16195                                     tabPosition: 'top',
16196                                       //resizeTabs: true,
16197                                     alwaysShowTabs: true,
16198                                     hideTabs: false
16199                                      //minTabWidth: 140
16200                                  }
16201                              })
16202                         
16203                          };
16204                          break;
16205                     }
16206                          
16207                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16208                         this.parent = { el :  new  Roo.bootstrap.Body() };
16209                         Roo.debug && Roo.log("setting el to doc body");
16210                          
16211                     } else {
16212                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16213                     }
16214                     break;
16215                 case 'bootstrap':
16216                     this.parent = { el : true};
16217                     // fall through
16218                 default:
16219                     el = Roo.get(ename);
16220                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16221                         this.parent = { el : true};
16222                     }
16223                     
16224                     break;
16225             }
16226                 
16227             
16228             if (!el && !this.parent) {
16229                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16230                 return;
16231             }
16232         }
16233         
16234         Roo.debug && Roo.log("EL:");
16235         Roo.debug && Roo.log(el);
16236         Roo.debug && Roo.log("this.parent.el:");
16237         Roo.debug && Roo.log(this.parent.el);
16238         
16239
16240         // altertive root elements ??? - we need a better way to indicate these.
16241         var is_alt = Roo.XComponent.is_alt ||
16242                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16243                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16244                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16245         
16246         
16247         
16248         if (!this.parent && is_alt) {
16249             //el = Roo.get(document.body);
16250             this.parent = { el : true };
16251         }
16252             
16253             
16254         
16255         if (!this.parent) {
16256             
16257             Roo.debug && Roo.log("no parent - creating one");
16258             
16259             el = el ? Roo.get(el) : false;      
16260             
16261             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16262                 
16263                 this.parent =  {
16264                     el : new Roo.bootstrap.layout.Border({
16265                         el: el || document.body,
16266                     
16267                         center: {
16268                             titlebar: false,
16269                             autoScroll:false,
16270                             closeOnTab: true,
16271                             tabPosition: 'top',
16272                              //resizeTabs: true,
16273                             alwaysShowTabs: false,
16274                             hideTabs: true,
16275                             minTabWidth: 140,
16276                             overflow: 'visible'
16277                          }
16278                      })
16279                 };
16280             } else {
16281             
16282                 // it's a top level one..
16283                 this.parent =  {
16284                     el : new Roo.BorderLayout(el || document.body, {
16285                         center: {
16286                             titlebar: false,
16287                             autoScroll:false,
16288                             closeOnTab: true,
16289                             tabPosition: 'top',
16290                              //resizeTabs: true,
16291                             alwaysShowTabs: el && hp? false :  true,
16292                             hideTabs: el || !hp ? true :  false,
16293                             minTabWidth: 140
16294                          }
16295                     })
16296                 };
16297             }
16298         }
16299         
16300         if (!this.parent.el) {
16301                 // probably an old style ctor, which has been disabled.
16302                 return;
16303
16304         }
16305                 // The 'tree' method is  '_tree now' 
16306             
16307         tree.region = tree.region || this.region;
16308         var is_body = false;
16309         if (this.parent.el === true) {
16310             // bootstrap... - body..
16311             if (el) {
16312                 tree.el = el;
16313             }
16314             this.parent.el = Roo.factory(tree);
16315             is_body = true;
16316         }
16317         
16318         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16319         this.fireEvent('built', this);
16320         
16321         this.panel = this.el;
16322         this.layout = this.panel.layout;
16323         this.parentLayout = this.parent.layout  || false;  
16324          
16325     }
16326     
16327 });
16328
16329 Roo.apply(Roo.XComponent, {
16330     /**
16331      * @property  hideProgress
16332      * true to disable the building progress bar.. usefull on single page renders.
16333      * @type Boolean
16334      */
16335     hideProgress : false,
16336     /**
16337      * @property  buildCompleted
16338      * True when the builder has completed building the interface.
16339      * @type Boolean
16340      */
16341     buildCompleted : false,
16342      
16343     /**
16344      * @property  topModule
16345      * the upper most module - uses document.element as it's constructor.
16346      * @type Object
16347      */
16348      
16349     topModule  : false,
16350       
16351     /**
16352      * @property  modules
16353      * array of modules to be created by registration system.
16354      * @type {Array} of Roo.XComponent
16355      */
16356     
16357     modules : [],
16358     /**
16359      * @property  elmodules
16360      * array of modules to be created by which use #ID 
16361      * @type {Array} of Roo.XComponent
16362      */
16363      
16364     elmodules : [],
16365
16366      /**
16367      * @property  is_alt
16368      * Is an alternative Root - normally used by bootstrap or other systems,
16369      *    where the top element in the tree can wrap 'body' 
16370      * @type {boolean}  (default false)
16371      */
16372      
16373     is_alt : false,
16374     /**
16375      * @property  build_from_html
16376      * Build elements from html - used by bootstrap HTML stuff 
16377      *    - this is cleared after build is completed
16378      * @type {boolean}    (default false)
16379      */
16380      
16381     build_from_html : false,
16382     /**
16383      * Register components to be built later.
16384      *
16385      * This solves the following issues
16386      * - Building is not done on page load, but after an authentication process has occured.
16387      * - Interface elements are registered on page load
16388      * - Parent Interface elements may not be loaded before child, so this handles that..
16389      * 
16390      *
16391      * example:
16392      * 
16393      * MyApp.register({
16394           order : '000001',
16395           module : 'Pman.Tab.projectMgr',
16396           region : 'center',
16397           parent : 'Pman.layout',
16398           disabled : false,  // or use a function..
16399         })
16400      
16401      * * @param {Object} details about module
16402      */
16403     register : function(obj) {
16404                 
16405         Roo.XComponent.event.fireEvent('register', obj);
16406         switch(typeof(obj.disabled) ) {
16407                 
16408             case 'undefined':
16409                 break;
16410             
16411             case 'function':
16412                 if ( obj.disabled() ) {
16413                         return;
16414                 }
16415                 break;
16416             
16417             default:
16418                 if (obj.disabled) {
16419                         return;
16420                 }
16421                 break;
16422         }
16423                 
16424         this.modules.push(obj);
16425          
16426     },
16427     /**
16428      * convert a string to an object..
16429      * eg. 'AAA.BBB' -> finds AAA.BBB
16430
16431      */
16432     
16433     toObject : function(str)
16434     {
16435         if (!str || typeof(str) == 'object') {
16436             return str;
16437         }
16438         if (str.substring(0,1) == '#') {
16439             return str;
16440         }
16441
16442         var ar = str.split('.');
16443         var rt, o;
16444         rt = ar.shift();
16445             /** eval:var:o */
16446         try {
16447             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16448         } catch (e) {
16449             throw "Module not found : " + str;
16450         }
16451         
16452         if (o === false) {
16453             throw "Module not found : " + str;
16454         }
16455         Roo.each(ar, function(e) {
16456             if (typeof(o[e]) == 'undefined') {
16457                 throw "Module not found : " + str;
16458             }
16459             o = o[e];
16460         });
16461         
16462         return o;
16463         
16464     },
16465     
16466     
16467     /**
16468      * move modules into their correct place in the tree..
16469      * 
16470      */
16471     preBuild : function ()
16472     {
16473         var _t = this;
16474         Roo.each(this.modules , function (obj)
16475         {
16476             Roo.XComponent.event.fireEvent('beforebuild', obj);
16477             
16478             var opar = obj.parent;
16479             try { 
16480                 obj.parent = this.toObject(opar);
16481             } catch(e) {
16482                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16483                 return;
16484             }
16485             
16486             if (!obj.parent) {
16487                 Roo.debug && Roo.log("GOT top level module");
16488                 Roo.debug && Roo.log(obj);
16489                 obj.modules = new Roo.util.MixedCollection(false, 
16490                     function(o) { return o.order + '' }
16491                 );
16492                 this.topModule = obj;
16493                 return;
16494             }
16495                         // parent is a string (usually a dom element name..)
16496             if (typeof(obj.parent) == 'string') {
16497                 this.elmodules.push(obj);
16498                 return;
16499             }
16500             if (obj.parent.constructor != Roo.XComponent) {
16501                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16502             }
16503             if (!obj.parent.modules) {
16504                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16505                     function(o) { return o.order + '' }
16506                 );
16507             }
16508             if (obj.parent.disabled) {
16509                 obj.disabled = true;
16510             }
16511             obj.parent.modules.add(obj);
16512         }, this);
16513     },
16514     
16515      /**
16516      * make a list of modules to build.
16517      * @return {Array} list of modules. 
16518      */ 
16519     
16520     buildOrder : function()
16521     {
16522         var _this = this;
16523         var cmp = function(a,b) {   
16524             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16525         };
16526         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16527             throw "No top level modules to build";
16528         }
16529         
16530         // make a flat list in order of modules to build.
16531         var mods = this.topModule ? [ this.topModule ] : [];
16532                 
16533         
16534         // elmodules (is a list of DOM based modules )
16535         Roo.each(this.elmodules, function(e) {
16536             mods.push(e);
16537             if (!this.topModule &&
16538                 typeof(e.parent) == 'string' &&
16539                 e.parent.substring(0,1) == '#' &&
16540                 Roo.get(e.parent.substr(1))
16541                ) {
16542                 
16543                 _this.topModule = e;
16544             }
16545             
16546         });
16547
16548         
16549         // add modules to their parents..
16550         var addMod = function(m) {
16551             Roo.debug && Roo.log("build Order: add: " + m.name);
16552                 
16553             mods.push(m);
16554             if (m.modules && !m.disabled) {
16555                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16556                 m.modules.keySort('ASC',  cmp );
16557                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16558     
16559                 m.modules.each(addMod);
16560             } else {
16561                 Roo.debug && Roo.log("build Order: no child modules");
16562             }
16563             // not sure if this is used any more..
16564             if (m.finalize) {
16565                 m.finalize.name = m.name + " (clean up) ";
16566                 mods.push(m.finalize);
16567             }
16568             
16569         }
16570         if (this.topModule && this.topModule.modules) { 
16571             this.topModule.modules.keySort('ASC',  cmp );
16572             this.topModule.modules.each(addMod);
16573         } 
16574         return mods;
16575     },
16576     
16577      /**
16578      * Build the registered modules.
16579      * @param {Object} parent element.
16580      * @param {Function} optional method to call after module has been added.
16581      * 
16582      */ 
16583    
16584     build : function(opts) 
16585     {
16586         
16587         if (typeof(opts) != 'undefined') {
16588             Roo.apply(this,opts);
16589         }
16590         
16591         this.preBuild();
16592         var mods = this.buildOrder();
16593       
16594         //this.allmods = mods;
16595         //Roo.debug && Roo.log(mods);
16596         //return;
16597         if (!mods.length) { // should not happen
16598             throw "NO modules!!!";
16599         }
16600         
16601         
16602         var msg = "Building Interface...";
16603         // flash it up as modal - so we store the mask!?
16604         if (!this.hideProgress && Roo.MessageBox) {
16605             Roo.MessageBox.show({ title: 'loading' });
16606             Roo.MessageBox.show({
16607                title: "Please wait...",
16608                msg: msg,
16609                width:450,
16610                progress:true,
16611                buttons : false,
16612                closable:false,
16613                modal: false
16614               
16615             });
16616         }
16617         var total = mods.length;
16618         
16619         var _this = this;
16620         var progressRun = function() {
16621             if (!mods.length) {
16622                 Roo.debug && Roo.log('hide?');
16623                 if (!this.hideProgress && Roo.MessageBox) {
16624                     Roo.MessageBox.hide();
16625                 }
16626                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16627                 
16628                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16629                 
16630                 // THE END...
16631                 return false;   
16632             }
16633             
16634             var m = mods.shift();
16635             
16636             
16637             Roo.debug && Roo.log(m);
16638             // not sure if this is supported any more.. - modules that are are just function
16639             if (typeof(m) == 'function') { 
16640                 m.call(this);
16641                 return progressRun.defer(10, _this);
16642             } 
16643             
16644             
16645             msg = "Building Interface " + (total  - mods.length) + 
16646                     " of " + total + 
16647                     (m.name ? (' - ' + m.name) : '');
16648                         Roo.debug && Roo.log(msg);
16649             if (!_this.hideProgress &&  Roo.MessageBox) { 
16650                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16651             }
16652             
16653          
16654             // is the module disabled?
16655             var disabled = (typeof(m.disabled) == 'function') ?
16656                 m.disabled.call(m.module.disabled) : m.disabled;    
16657             
16658             
16659             if (disabled) {
16660                 return progressRun(); // we do not update the display!
16661             }
16662             
16663             // now build 
16664             
16665                         
16666                         
16667             m.render();
16668             // it's 10 on top level, and 1 on others??? why...
16669             return progressRun.defer(10, _this);
16670              
16671         }
16672         progressRun.defer(1, _this);
16673      
16674         
16675         
16676     },
16677     /**
16678      * Overlay a set of modified strings onto a component
16679      * This is dependant on our builder exporting the strings and 'named strings' elements.
16680      * 
16681      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
16682      * @param {Object} associative array of 'named' string and it's new value.
16683      * 
16684      */
16685         overlayStrings : function( component, strings )
16686     {
16687         if (typeof(component['_named_strings']) == 'undefined') {
16688             throw "ERROR: component does not have _named_strings";
16689         }
16690         for ( var k in strings ) {
16691             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
16692             if (md !== false) {
16693                 component['_strings'][md] = strings[k];
16694             } else {
16695                 Roo.log('could not find named string: ' + k + ' in');
16696                 Roo.log(component);
16697             }
16698             
16699         }
16700         
16701     },
16702     
16703         
16704         /**
16705          * Event Object.
16706          *
16707          *
16708          */
16709         event: false, 
16710     /**
16711          * wrapper for event.on - aliased later..  
16712          * Typically use to register a event handler for register:
16713          *
16714          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16715          *
16716          */
16717     on : false
16718    
16719     
16720     
16721 });
16722
16723 Roo.XComponent.event = new Roo.util.Observable({
16724                 events : { 
16725                         /**
16726                          * @event register
16727                          * Fires when an Component is registered,
16728                          * set the disable property on the Component to stop registration.
16729                          * @param {Roo.XComponent} c the component being registerd.
16730                          * 
16731                          */
16732                         'register' : true,
16733             /**
16734                          * @event beforebuild
16735                          * Fires before each Component is built
16736                          * can be used to apply permissions.
16737                          * @param {Roo.XComponent} c the component being registerd.
16738                          * 
16739                          */
16740                         'beforebuild' : true,
16741                         /**
16742                          * @event buildcomplete
16743                          * Fires on the top level element when all elements have been built
16744                          * @param {Roo.XComponent} the top level component.
16745                          */
16746                         'buildcomplete' : true
16747                         
16748                 }
16749 });
16750
16751 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16752  //
16753  /**
16754  * marked - a markdown parser
16755  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16756  * https://github.com/chjj/marked
16757  */
16758
16759
16760 /**
16761  *
16762  * Roo.Markdown - is a very crude wrapper around marked..
16763  *
16764  * usage:
16765  * 
16766  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16767  * 
16768  * Note: move the sample code to the bottom of this
16769  * file before uncommenting it.
16770  *
16771  */
16772
16773 Roo.Markdown = {};
16774 Roo.Markdown.toHtml = function(text) {
16775     
16776     var c = new Roo.Markdown.marked.setOptions({
16777             renderer: new Roo.Markdown.marked.Renderer(),
16778             gfm: true,
16779             tables: true,
16780             breaks: false,
16781             pedantic: false,
16782             sanitize: false,
16783             smartLists: true,
16784             smartypants: false
16785           });
16786     // A FEW HACKS!!?
16787     
16788     text = text.replace(/\\\n/g,' ');
16789     return Roo.Markdown.marked(text);
16790 };
16791 //
16792 // converter
16793 //
16794 // Wraps all "globals" so that the only thing
16795 // exposed is makeHtml().
16796 //
16797 (function() {
16798     
16799     /**
16800      * Block-Level Grammar
16801      */
16802     
16803     var block = {
16804       newline: /^\n+/,
16805       code: /^( {4}[^\n]+\n*)+/,
16806       fences: noop,
16807       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16808       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16809       nptable: noop,
16810       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16811       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16812       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16813       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16814       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16815       table: noop,
16816       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16817       text: /^[^\n]+/
16818     };
16819     
16820     block.bullet = /(?:[*+-]|\d+\.)/;
16821     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16822     block.item = replace(block.item, 'gm')
16823       (/bull/g, block.bullet)
16824       ();
16825     
16826     block.list = replace(block.list)
16827       (/bull/g, block.bullet)
16828       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16829       ('def', '\\n+(?=' + block.def.source + ')')
16830       ();
16831     
16832     block.blockquote = replace(block.blockquote)
16833       ('def', block.def)
16834       ();
16835     
16836     block._tag = '(?!(?:'
16837       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16838       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16839       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16840     
16841     block.html = replace(block.html)
16842       ('comment', /<!--[\s\S]*?-->/)
16843       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16844       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16845       (/tag/g, block._tag)
16846       ();
16847     
16848     block.paragraph = replace(block.paragraph)
16849       ('hr', block.hr)
16850       ('heading', block.heading)
16851       ('lheading', block.lheading)
16852       ('blockquote', block.blockquote)
16853       ('tag', '<' + block._tag)
16854       ('def', block.def)
16855       ();
16856     
16857     /**
16858      * Normal Block Grammar
16859      */
16860     
16861     block.normal = merge({}, block);
16862     
16863     /**
16864      * GFM Block Grammar
16865      */
16866     
16867     block.gfm = merge({}, block.normal, {
16868       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16869       paragraph: /^/,
16870       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16871     });
16872     
16873     block.gfm.paragraph = replace(block.paragraph)
16874       ('(?!', '(?!'
16875         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16876         + block.list.source.replace('\\1', '\\3') + '|')
16877       ();
16878     
16879     /**
16880      * GFM + Tables Block Grammar
16881      */
16882     
16883     block.tables = merge({}, block.gfm, {
16884       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16885       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16886     });
16887     
16888     /**
16889      * Block Lexer
16890      */
16891     
16892     function Lexer(options) {
16893       this.tokens = [];
16894       this.tokens.links = {};
16895       this.options = options || marked.defaults;
16896       this.rules = block.normal;
16897     
16898       if (this.options.gfm) {
16899         if (this.options.tables) {
16900           this.rules = block.tables;
16901         } else {
16902           this.rules = block.gfm;
16903         }
16904       }
16905     }
16906     
16907     /**
16908      * Expose Block Rules
16909      */
16910     
16911     Lexer.rules = block;
16912     
16913     /**
16914      * Static Lex Method
16915      */
16916     
16917     Lexer.lex = function(src, options) {
16918       var lexer = new Lexer(options);
16919       return lexer.lex(src);
16920     };
16921     
16922     /**
16923      * Preprocessing
16924      */
16925     
16926     Lexer.prototype.lex = function(src) {
16927       src = src
16928         .replace(/\r\n|\r/g, '\n')
16929         .replace(/\t/g, '    ')
16930         .replace(/\u00a0/g, ' ')
16931         .replace(/\u2424/g, '\n');
16932     
16933       return this.token(src, true);
16934     };
16935     
16936     /**
16937      * Lexing
16938      */
16939     
16940     Lexer.prototype.token = function(src, top, bq) {
16941       var src = src.replace(/^ +$/gm, '')
16942         , next
16943         , loose
16944         , cap
16945         , bull
16946         , b
16947         , item
16948         , space
16949         , i
16950         , l;
16951     
16952       while (src) {
16953         // newline
16954         if (cap = this.rules.newline.exec(src)) {
16955           src = src.substring(cap[0].length);
16956           if (cap[0].length > 1) {
16957             this.tokens.push({
16958               type: 'space'
16959             });
16960           }
16961         }
16962     
16963         // code
16964         if (cap = this.rules.code.exec(src)) {
16965           src = src.substring(cap[0].length);
16966           cap = cap[0].replace(/^ {4}/gm, '');
16967           this.tokens.push({
16968             type: 'code',
16969             text: !this.options.pedantic
16970               ? cap.replace(/\n+$/, '')
16971               : cap
16972           });
16973           continue;
16974         }
16975     
16976         // fences (gfm)
16977         if (cap = this.rules.fences.exec(src)) {
16978           src = src.substring(cap[0].length);
16979           this.tokens.push({
16980             type: 'code',
16981             lang: cap[2],
16982             text: cap[3] || ''
16983           });
16984           continue;
16985         }
16986     
16987         // heading
16988         if (cap = this.rules.heading.exec(src)) {
16989           src = src.substring(cap[0].length);
16990           this.tokens.push({
16991             type: 'heading',
16992             depth: cap[1].length,
16993             text: cap[2]
16994           });
16995           continue;
16996         }
16997     
16998         // table no leading pipe (gfm)
16999         if (top && (cap = this.rules.nptable.exec(src))) {
17000           src = src.substring(cap[0].length);
17001     
17002           item = {
17003             type: 'table',
17004             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17005             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17006             cells: cap[3].replace(/\n$/, '').split('\n')
17007           };
17008     
17009           for (i = 0; i < item.align.length; i++) {
17010             if (/^ *-+: *$/.test(item.align[i])) {
17011               item.align[i] = 'right';
17012             } else if (/^ *:-+: *$/.test(item.align[i])) {
17013               item.align[i] = 'center';
17014             } else if (/^ *:-+ *$/.test(item.align[i])) {
17015               item.align[i] = 'left';
17016             } else {
17017               item.align[i] = null;
17018             }
17019           }
17020     
17021           for (i = 0; i < item.cells.length; i++) {
17022             item.cells[i] = item.cells[i].split(/ *\| */);
17023           }
17024     
17025           this.tokens.push(item);
17026     
17027           continue;
17028         }
17029     
17030         // lheading
17031         if (cap = this.rules.lheading.exec(src)) {
17032           src = src.substring(cap[0].length);
17033           this.tokens.push({
17034             type: 'heading',
17035             depth: cap[2] === '=' ? 1 : 2,
17036             text: cap[1]
17037           });
17038           continue;
17039         }
17040     
17041         // hr
17042         if (cap = this.rules.hr.exec(src)) {
17043           src = src.substring(cap[0].length);
17044           this.tokens.push({
17045             type: 'hr'
17046           });
17047           continue;
17048         }
17049     
17050         // blockquote
17051         if (cap = this.rules.blockquote.exec(src)) {
17052           src = src.substring(cap[0].length);
17053     
17054           this.tokens.push({
17055             type: 'blockquote_start'
17056           });
17057     
17058           cap = cap[0].replace(/^ *> ?/gm, '');
17059     
17060           // Pass `top` to keep the current
17061           // "toplevel" state. This is exactly
17062           // how markdown.pl works.
17063           this.token(cap, top, true);
17064     
17065           this.tokens.push({
17066             type: 'blockquote_end'
17067           });
17068     
17069           continue;
17070         }
17071     
17072         // list
17073         if (cap = this.rules.list.exec(src)) {
17074           src = src.substring(cap[0].length);
17075           bull = cap[2];
17076     
17077           this.tokens.push({
17078             type: 'list_start',
17079             ordered: bull.length > 1
17080           });
17081     
17082           // Get each top-level item.
17083           cap = cap[0].match(this.rules.item);
17084     
17085           next = false;
17086           l = cap.length;
17087           i = 0;
17088     
17089           for (; i < l; i++) {
17090             item = cap[i];
17091     
17092             // Remove the list item's bullet
17093             // so it is seen as the next token.
17094             space = item.length;
17095             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17096     
17097             // Outdent whatever the
17098             // list item contains. Hacky.
17099             if (~item.indexOf('\n ')) {
17100               space -= item.length;
17101               item = !this.options.pedantic
17102                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17103                 : item.replace(/^ {1,4}/gm, '');
17104             }
17105     
17106             // Determine whether the next list item belongs here.
17107             // Backpedal if it does not belong in this list.
17108             if (this.options.smartLists && i !== l - 1) {
17109               b = block.bullet.exec(cap[i + 1])[0];
17110               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17111                 src = cap.slice(i + 1).join('\n') + src;
17112                 i = l - 1;
17113               }
17114             }
17115     
17116             // Determine whether item is loose or not.
17117             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17118             // for discount behavior.
17119             loose = next || /\n\n(?!\s*$)/.test(item);
17120             if (i !== l - 1) {
17121               next = item.charAt(item.length - 1) === '\n';
17122               if (!loose) { loose = next; }
17123             }
17124     
17125             this.tokens.push({
17126               type: loose
17127                 ? 'loose_item_start'
17128                 : 'list_item_start'
17129             });
17130     
17131             // Recurse.
17132             this.token(item, false, bq);
17133     
17134             this.tokens.push({
17135               type: 'list_item_end'
17136             });
17137           }
17138     
17139           this.tokens.push({
17140             type: 'list_end'
17141           });
17142     
17143           continue;
17144         }
17145     
17146         // html
17147         if (cap = this.rules.html.exec(src)) {
17148           src = src.substring(cap[0].length);
17149           this.tokens.push({
17150             type: this.options.sanitize
17151               ? 'paragraph'
17152               : 'html',
17153             pre: !this.options.sanitizer
17154               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17155             text: cap[0]
17156           });
17157           continue;
17158         }
17159     
17160         // def
17161         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17162           src = src.substring(cap[0].length);
17163           this.tokens.links[cap[1].toLowerCase()] = {
17164             href: cap[2],
17165             title: cap[3]
17166           };
17167           continue;
17168         }
17169     
17170         // table (gfm)
17171         if (top && (cap = this.rules.table.exec(src))) {
17172           src = src.substring(cap[0].length);
17173     
17174           item = {
17175             type: 'table',
17176             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17177             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17178             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17179           };
17180     
17181           for (i = 0; i < item.align.length; i++) {
17182             if (/^ *-+: *$/.test(item.align[i])) {
17183               item.align[i] = 'right';
17184             } else if (/^ *:-+: *$/.test(item.align[i])) {
17185               item.align[i] = 'center';
17186             } else if (/^ *:-+ *$/.test(item.align[i])) {
17187               item.align[i] = 'left';
17188             } else {
17189               item.align[i] = null;
17190             }
17191           }
17192     
17193           for (i = 0; i < item.cells.length; i++) {
17194             item.cells[i] = item.cells[i]
17195               .replace(/^ *\| *| *\| *$/g, '')
17196               .split(/ *\| */);
17197           }
17198     
17199           this.tokens.push(item);
17200     
17201           continue;
17202         }
17203     
17204         // top-level paragraph
17205         if (top && (cap = this.rules.paragraph.exec(src))) {
17206           src = src.substring(cap[0].length);
17207           this.tokens.push({
17208             type: 'paragraph',
17209             text: cap[1].charAt(cap[1].length - 1) === '\n'
17210               ? cap[1].slice(0, -1)
17211               : cap[1]
17212           });
17213           continue;
17214         }
17215     
17216         // text
17217         if (cap = this.rules.text.exec(src)) {
17218           // Top-level should never reach here.
17219           src = src.substring(cap[0].length);
17220           this.tokens.push({
17221             type: 'text',
17222             text: cap[0]
17223           });
17224           continue;
17225         }
17226     
17227         if (src) {
17228           throw new
17229             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17230         }
17231       }
17232     
17233       return this.tokens;
17234     };
17235     
17236     /**
17237      * Inline-Level Grammar
17238      */
17239     
17240     var inline = {
17241       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17242       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17243       url: noop,
17244       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17245       link: /^!?\[(inside)\]\(href\)/,
17246       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17247       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17248       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17249       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17250       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17251       br: /^ {2,}\n(?!\s*$)/,
17252       del: noop,
17253       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17254     };
17255     
17256     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17257     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17258     
17259     inline.link = replace(inline.link)
17260       ('inside', inline._inside)
17261       ('href', inline._href)
17262       ();
17263     
17264     inline.reflink = replace(inline.reflink)
17265       ('inside', inline._inside)
17266       ();
17267     
17268     /**
17269      * Normal Inline Grammar
17270      */
17271     
17272     inline.normal = merge({}, inline);
17273     
17274     /**
17275      * Pedantic Inline Grammar
17276      */
17277     
17278     inline.pedantic = merge({}, inline.normal, {
17279       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17280       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17281     });
17282     
17283     /**
17284      * GFM Inline Grammar
17285      */
17286     
17287     inline.gfm = merge({}, inline.normal, {
17288       escape: replace(inline.escape)('])', '~|])')(),
17289       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17290       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17291       text: replace(inline.text)
17292         (']|', '~]|')
17293         ('|', '|https?://|')
17294         ()
17295     });
17296     
17297     /**
17298      * GFM + Line Breaks Inline Grammar
17299      */
17300     
17301     inline.breaks = merge({}, inline.gfm, {
17302       br: replace(inline.br)('{2,}', '*')(),
17303       text: replace(inline.gfm.text)('{2,}', '*')()
17304     });
17305     
17306     /**
17307      * Inline Lexer & Compiler
17308      */
17309     
17310     function InlineLexer(links, options) {
17311       this.options = options || marked.defaults;
17312       this.links = links;
17313       this.rules = inline.normal;
17314       this.renderer = this.options.renderer || new Renderer;
17315       this.renderer.options = this.options;
17316     
17317       if (!this.links) {
17318         throw new
17319           Error('Tokens array requires a `links` property.');
17320       }
17321     
17322       if (this.options.gfm) {
17323         if (this.options.breaks) {
17324           this.rules = inline.breaks;
17325         } else {
17326           this.rules = inline.gfm;
17327         }
17328       } else if (this.options.pedantic) {
17329         this.rules = inline.pedantic;
17330       }
17331     }
17332     
17333     /**
17334      * Expose Inline Rules
17335      */
17336     
17337     InlineLexer.rules = inline;
17338     
17339     /**
17340      * Static Lexing/Compiling Method
17341      */
17342     
17343     InlineLexer.output = function(src, links, options) {
17344       var inline = new InlineLexer(links, options);
17345       return inline.output(src);
17346     };
17347     
17348     /**
17349      * Lexing/Compiling
17350      */
17351     
17352     InlineLexer.prototype.output = function(src) {
17353       var out = ''
17354         , link
17355         , text
17356         , href
17357         , cap;
17358     
17359       while (src) {
17360         // escape
17361         if (cap = this.rules.escape.exec(src)) {
17362           src = src.substring(cap[0].length);
17363           out += cap[1];
17364           continue;
17365         }
17366     
17367         // autolink
17368         if (cap = this.rules.autolink.exec(src)) {
17369           src = src.substring(cap[0].length);
17370           if (cap[2] === '@') {
17371             text = cap[1].charAt(6) === ':'
17372               ? this.mangle(cap[1].substring(7))
17373               : this.mangle(cap[1]);
17374             href = this.mangle('mailto:') + text;
17375           } else {
17376             text = escape(cap[1]);
17377             href = text;
17378           }
17379           out += this.renderer.link(href, null, text);
17380           continue;
17381         }
17382     
17383         // url (gfm)
17384         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17385           src = src.substring(cap[0].length);
17386           text = escape(cap[1]);
17387           href = text;
17388           out += this.renderer.link(href, null, text);
17389           continue;
17390         }
17391     
17392         // tag
17393         if (cap = this.rules.tag.exec(src)) {
17394           if (!this.inLink && /^<a /i.test(cap[0])) {
17395             this.inLink = true;
17396           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17397             this.inLink = false;
17398           }
17399           src = src.substring(cap[0].length);
17400           out += this.options.sanitize
17401             ? this.options.sanitizer
17402               ? this.options.sanitizer(cap[0])
17403               : escape(cap[0])
17404             : cap[0];
17405           continue;
17406         }
17407     
17408         // link
17409         if (cap = this.rules.link.exec(src)) {
17410           src = src.substring(cap[0].length);
17411           this.inLink = true;
17412           out += this.outputLink(cap, {
17413             href: cap[2],
17414             title: cap[3]
17415           });
17416           this.inLink = false;
17417           continue;
17418         }
17419     
17420         // reflink, nolink
17421         if ((cap = this.rules.reflink.exec(src))
17422             || (cap = this.rules.nolink.exec(src))) {
17423           src = src.substring(cap[0].length);
17424           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17425           link = this.links[link.toLowerCase()];
17426           if (!link || !link.href) {
17427             out += cap[0].charAt(0);
17428             src = cap[0].substring(1) + src;
17429             continue;
17430           }
17431           this.inLink = true;
17432           out += this.outputLink(cap, link);
17433           this.inLink = false;
17434           continue;
17435         }
17436     
17437         // strong
17438         if (cap = this.rules.strong.exec(src)) {
17439           src = src.substring(cap[0].length);
17440           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17441           continue;
17442         }
17443     
17444         // em
17445         if (cap = this.rules.em.exec(src)) {
17446           src = src.substring(cap[0].length);
17447           out += this.renderer.em(this.output(cap[2] || cap[1]));
17448           continue;
17449         }
17450     
17451         // code
17452         if (cap = this.rules.code.exec(src)) {
17453           src = src.substring(cap[0].length);
17454           out += this.renderer.codespan(escape(cap[2], true));
17455           continue;
17456         }
17457     
17458         // br
17459         if (cap = this.rules.br.exec(src)) {
17460           src = src.substring(cap[0].length);
17461           out += this.renderer.br();
17462           continue;
17463         }
17464     
17465         // del (gfm)
17466         if (cap = this.rules.del.exec(src)) {
17467           src = src.substring(cap[0].length);
17468           out += this.renderer.del(this.output(cap[1]));
17469           continue;
17470         }
17471     
17472         // text
17473         if (cap = this.rules.text.exec(src)) {
17474           src = src.substring(cap[0].length);
17475           out += this.renderer.text(escape(this.smartypants(cap[0])));
17476           continue;
17477         }
17478     
17479         if (src) {
17480           throw new
17481             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17482         }
17483       }
17484     
17485       return out;
17486     };
17487     
17488     /**
17489      * Compile Link
17490      */
17491     
17492     InlineLexer.prototype.outputLink = function(cap, link) {
17493       var href = escape(link.href)
17494         , title = link.title ? escape(link.title) : null;
17495     
17496       return cap[0].charAt(0) !== '!'
17497         ? this.renderer.link(href, title, this.output(cap[1]))
17498         : this.renderer.image(href, title, escape(cap[1]));
17499     };
17500     
17501     /**
17502      * Smartypants Transformations
17503      */
17504     
17505     InlineLexer.prototype.smartypants = function(text) {
17506       if (!this.options.smartypants)  { return text; }
17507       return text
17508         // em-dashes
17509         .replace(/---/g, '\u2014')
17510         // en-dashes
17511         .replace(/--/g, '\u2013')
17512         // opening singles
17513         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17514         // closing singles & apostrophes
17515         .replace(/'/g, '\u2019')
17516         // opening doubles
17517         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17518         // closing doubles
17519         .replace(/"/g, '\u201d')
17520         // ellipses
17521         .replace(/\.{3}/g, '\u2026');
17522     };
17523     
17524     /**
17525      * Mangle Links
17526      */
17527     
17528     InlineLexer.prototype.mangle = function(text) {
17529       if (!this.options.mangle) { return text; }
17530       var out = ''
17531         , l = text.length
17532         , i = 0
17533         , ch;
17534     
17535       for (; i < l; i++) {
17536         ch = text.charCodeAt(i);
17537         if (Math.random() > 0.5) {
17538           ch = 'x' + ch.toString(16);
17539         }
17540         out += '&#' + ch + ';';
17541       }
17542     
17543       return out;
17544     };
17545     
17546     /**
17547      * Renderer
17548      */
17549     
17550     function Renderer(options) {
17551       this.options = options || {};
17552     }
17553     
17554     Renderer.prototype.code = function(code, lang, escaped) {
17555       if (this.options.highlight) {
17556         var out = this.options.highlight(code, lang);
17557         if (out != null && out !== code) {
17558           escaped = true;
17559           code = out;
17560         }
17561       } else {
17562             // hack!!! - it's already escapeD?
17563             escaped = true;
17564       }
17565     
17566       if (!lang) {
17567         return '<pre><code>'
17568           + (escaped ? code : escape(code, true))
17569           + '\n</code></pre>';
17570       }
17571     
17572       return '<pre><code class="'
17573         + this.options.langPrefix
17574         + escape(lang, true)
17575         + '">'
17576         + (escaped ? code : escape(code, true))
17577         + '\n</code></pre>\n';
17578     };
17579     
17580     Renderer.prototype.blockquote = function(quote) {
17581       return '<blockquote>\n' + quote + '</blockquote>\n';
17582     };
17583     
17584     Renderer.prototype.html = function(html) {
17585       return html;
17586     };
17587     
17588     Renderer.prototype.heading = function(text, level, raw) {
17589       return '<h'
17590         + level
17591         + ' id="'
17592         + this.options.headerPrefix
17593         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17594         + '">'
17595         + text
17596         + '</h'
17597         + level
17598         + '>\n';
17599     };
17600     
17601     Renderer.prototype.hr = function() {
17602       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17603     };
17604     
17605     Renderer.prototype.list = function(body, ordered) {
17606       var type = ordered ? 'ol' : 'ul';
17607       return '<' + type + '>\n' + body + '</' + type + '>\n';
17608     };
17609     
17610     Renderer.prototype.listitem = function(text) {
17611       return '<li>' + text + '</li>\n';
17612     };
17613     
17614     Renderer.prototype.paragraph = function(text) {
17615       return '<p>' + text + '</p>\n';
17616     };
17617     
17618     Renderer.prototype.table = function(header, body) {
17619       return '<table class="table table-striped">\n'
17620         + '<thead>\n'
17621         + header
17622         + '</thead>\n'
17623         + '<tbody>\n'
17624         + body
17625         + '</tbody>\n'
17626         + '</table>\n';
17627     };
17628     
17629     Renderer.prototype.tablerow = function(content) {
17630       return '<tr>\n' + content + '</tr>\n';
17631     };
17632     
17633     Renderer.prototype.tablecell = function(content, flags) {
17634       var type = flags.header ? 'th' : 'td';
17635       var tag = flags.align
17636         ? '<' + type + ' style="text-align:' + flags.align + '">'
17637         : '<' + type + '>';
17638       return tag + content + '</' + type + '>\n';
17639     };
17640     
17641     // span level renderer
17642     Renderer.prototype.strong = function(text) {
17643       return '<strong>' + text + '</strong>';
17644     };
17645     
17646     Renderer.prototype.em = function(text) {
17647       return '<em>' + text + '</em>';
17648     };
17649     
17650     Renderer.prototype.codespan = function(text) {
17651       return '<code>' + text + '</code>';
17652     };
17653     
17654     Renderer.prototype.br = function() {
17655       return this.options.xhtml ? '<br/>' : '<br>';
17656     };
17657     
17658     Renderer.prototype.del = function(text) {
17659       return '<del>' + text + '</del>';
17660     };
17661     
17662     Renderer.prototype.link = function(href, title, text) {
17663       if (this.options.sanitize) {
17664         try {
17665           var prot = decodeURIComponent(unescape(href))
17666             .replace(/[^\w:]/g, '')
17667             .toLowerCase();
17668         } catch (e) {
17669           return '';
17670         }
17671         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17672           return '';
17673         }
17674       }
17675       var out = '<a href="' + href + '"';
17676       if (title) {
17677         out += ' title="' + title + '"';
17678       }
17679       out += '>' + text + '</a>';
17680       return out;
17681     };
17682     
17683     Renderer.prototype.image = function(href, title, text) {
17684       var out = '<img src="' + href + '" alt="' + text + '"';
17685       if (title) {
17686         out += ' title="' + title + '"';
17687       }
17688       out += this.options.xhtml ? '/>' : '>';
17689       return out;
17690     };
17691     
17692     Renderer.prototype.text = function(text) {
17693       return text;
17694     };
17695     
17696     /**
17697      * Parsing & Compiling
17698      */
17699     
17700     function Parser(options) {
17701       this.tokens = [];
17702       this.token = null;
17703       this.options = options || marked.defaults;
17704       this.options.renderer = this.options.renderer || new Renderer;
17705       this.renderer = this.options.renderer;
17706       this.renderer.options = this.options;
17707     }
17708     
17709     /**
17710      * Static Parse Method
17711      */
17712     
17713     Parser.parse = function(src, options, renderer) {
17714       var parser = new Parser(options, renderer);
17715       return parser.parse(src);
17716     };
17717     
17718     /**
17719      * Parse Loop
17720      */
17721     
17722     Parser.prototype.parse = function(src) {
17723       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17724       this.tokens = src.reverse();
17725     
17726       var out = '';
17727       while (this.next()) {
17728         out += this.tok();
17729       }
17730     
17731       return out;
17732     };
17733     
17734     /**
17735      * Next Token
17736      */
17737     
17738     Parser.prototype.next = function() {
17739       return this.token = this.tokens.pop();
17740     };
17741     
17742     /**
17743      * Preview Next Token
17744      */
17745     
17746     Parser.prototype.peek = function() {
17747       return this.tokens[this.tokens.length - 1] || 0;
17748     };
17749     
17750     /**
17751      * Parse Text Tokens
17752      */
17753     
17754     Parser.prototype.parseText = function() {
17755       var body = this.token.text;
17756     
17757       while (this.peek().type === 'text') {
17758         body += '\n' + this.next().text;
17759       }
17760     
17761       return this.inline.output(body);
17762     };
17763     
17764     /**
17765      * Parse Current Token
17766      */
17767     
17768     Parser.prototype.tok = function() {
17769       switch (this.token.type) {
17770         case 'space': {
17771           return '';
17772         }
17773         case 'hr': {
17774           return this.renderer.hr();
17775         }
17776         case 'heading': {
17777           return this.renderer.heading(
17778             this.inline.output(this.token.text),
17779             this.token.depth,
17780             this.token.text);
17781         }
17782         case 'code': {
17783           return this.renderer.code(this.token.text,
17784             this.token.lang,
17785             this.token.escaped);
17786         }
17787         case 'table': {
17788           var header = ''
17789             , body = ''
17790             , i
17791             , row
17792             , cell
17793             , flags
17794             , j;
17795     
17796           // header
17797           cell = '';
17798           for (i = 0; i < this.token.header.length; i++) {
17799             flags = { header: true, align: this.token.align[i] };
17800             cell += this.renderer.tablecell(
17801               this.inline.output(this.token.header[i]),
17802               { header: true, align: this.token.align[i] }
17803             );
17804           }
17805           header += this.renderer.tablerow(cell);
17806     
17807           for (i = 0; i < this.token.cells.length; i++) {
17808             row = this.token.cells[i];
17809     
17810             cell = '';
17811             for (j = 0; j < row.length; j++) {
17812               cell += this.renderer.tablecell(
17813                 this.inline.output(row[j]),
17814                 { header: false, align: this.token.align[j] }
17815               );
17816             }
17817     
17818             body += this.renderer.tablerow(cell);
17819           }
17820           return this.renderer.table(header, body);
17821         }
17822         case 'blockquote_start': {
17823           var body = '';
17824     
17825           while (this.next().type !== 'blockquote_end') {
17826             body += this.tok();
17827           }
17828     
17829           return this.renderer.blockquote(body);
17830         }
17831         case 'list_start': {
17832           var body = ''
17833             , ordered = this.token.ordered;
17834     
17835           while (this.next().type !== 'list_end') {
17836             body += this.tok();
17837           }
17838     
17839           return this.renderer.list(body, ordered);
17840         }
17841         case 'list_item_start': {
17842           var body = '';
17843     
17844           while (this.next().type !== 'list_item_end') {
17845             body += this.token.type === 'text'
17846               ? this.parseText()
17847               : this.tok();
17848           }
17849     
17850           return this.renderer.listitem(body);
17851         }
17852         case 'loose_item_start': {
17853           var body = '';
17854     
17855           while (this.next().type !== 'list_item_end') {
17856             body += this.tok();
17857           }
17858     
17859           return this.renderer.listitem(body);
17860         }
17861         case 'html': {
17862           var html = !this.token.pre && !this.options.pedantic
17863             ? this.inline.output(this.token.text)
17864             : this.token.text;
17865           return this.renderer.html(html);
17866         }
17867         case 'paragraph': {
17868           return this.renderer.paragraph(this.inline.output(this.token.text));
17869         }
17870         case 'text': {
17871           return this.renderer.paragraph(this.parseText());
17872         }
17873       }
17874     };
17875     
17876     /**
17877      * Helpers
17878      */
17879     
17880     function escape(html, encode) {
17881       return html
17882         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17883         .replace(/</g, '&lt;')
17884         .replace(/>/g, '&gt;')
17885         .replace(/"/g, '&quot;')
17886         .replace(/'/g, '&#39;');
17887     }
17888     
17889     function unescape(html) {
17890         // explicitly match decimal, hex, and named HTML entities 
17891       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17892         n = n.toLowerCase();
17893         if (n === 'colon') { return ':'; }
17894         if (n.charAt(0) === '#') {
17895           return n.charAt(1) === 'x'
17896             ? String.fromCharCode(parseInt(n.substring(2), 16))
17897             : String.fromCharCode(+n.substring(1));
17898         }
17899         return '';
17900       });
17901     }
17902     
17903     function replace(regex, opt) {
17904       regex = regex.source;
17905       opt = opt || '';
17906       return function self(name, val) {
17907         if (!name) { return new RegExp(regex, opt); }
17908         val = val.source || val;
17909         val = val.replace(/(^|[^\[])\^/g, '$1');
17910         regex = regex.replace(name, val);
17911         return self;
17912       };
17913     }
17914     
17915     function noop() {}
17916     noop.exec = noop;
17917     
17918     function merge(obj) {
17919       var i = 1
17920         , target
17921         , key;
17922     
17923       for (; i < arguments.length; i++) {
17924         target = arguments[i];
17925         for (key in target) {
17926           if (Object.prototype.hasOwnProperty.call(target, key)) {
17927             obj[key] = target[key];
17928           }
17929         }
17930       }
17931     
17932       return obj;
17933     }
17934     
17935     
17936     /**
17937      * Marked
17938      */
17939     
17940     function marked(src, opt, callback) {
17941       if (callback || typeof opt === 'function') {
17942         if (!callback) {
17943           callback = opt;
17944           opt = null;
17945         }
17946     
17947         opt = merge({}, marked.defaults, opt || {});
17948     
17949         var highlight = opt.highlight
17950           , tokens
17951           , pending
17952           , i = 0;
17953     
17954         try {
17955           tokens = Lexer.lex(src, opt)
17956         } catch (e) {
17957           return callback(e);
17958         }
17959     
17960         pending = tokens.length;
17961     
17962         var done = function(err) {
17963           if (err) {
17964             opt.highlight = highlight;
17965             return callback(err);
17966           }
17967     
17968           var out;
17969     
17970           try {
17971             out = Parser.parse(tokens, opt);
17972           } catch (e) {
17973             err = e;
17974           }
17975     
17976           opt.highlight = highlight;
17977     
17978           return err
17979             ? callback(err)
17980             : callback(null, out);
17981         };
17982     
17983         if (!highlight || highlight.length < 3) {
17984           return done();
17985         }
17986     
17987         delete opt.highlight;
17988     
17989         if (!pending) { return done(); }
17990     
17991         for (; i < tokens.length; i++) {
17992           (function(token) {
17993             if (token.type !== 'code') {
17994               return --pending || done();
17995             }
17996             return highlight(token.text, token.lang, function(err, code) {
17997               if (err) { return done(err); }
17998               if (code == null || code === token.text) {
17999                 return --pending || done();
18000               }
18001               token.text = code;
18002               token.escaped = true;
18003               --pending || done();
18004             });
18005           })(tokens[i]);
18006         }
18007     
18008         return;
18009       }
18010       try {
18011         if (opt) { opt = merge({}, marked.defaults, opt); }
18012         return Parser.parse(Lexer.lex(src, opt), opt);
18013       } catch (e) {
18014         e.message += '\nPlease report this to https://github.com/chjj/marked.';
18015         if ((opt || marked.defaults).silent) {
18016           return '<p>An error occured:</p><pre>'
18017             + escape(e.message + '', true)
18018             + '</pre>';
18019         }
18020         throw e;
18021       }
18022     }
18023     
18024     /**
18025      * Options
18026      */
18027     
18028     marked.options =
18029     marked.setOptions = function(opt) {
18030       merge(marked.defaults, opt);
18031       return marked;
18032     };
18033     
18034     marked.defaults = {
18035       gfm: true,
18036       tables: true,
18037       breaks: false,
18038       pedantic: false,
18039       sanitize: false,
18040       sanitizer: null,
18041       mangle: true,
18042       smartLists: false,
18043       silent: false,
18044       highlight: null,
18045       langPrefix: 'lang-',
18046       smartypants: false,
18047       headerPrefix: '',
18048       renderer: new Renderer,
18049       xhtml: false
18050     };
18051     
18052     /**
18053      * Expose
18054      */
18055     
18056     marked.Parser = Parser;
18057     marked.parser = Parser.parse;
18058     
18059     marked.Renderer = Renderer;
18060     
18061     marked.Lexer = Lexer;
18062     marked.lexer = Lexer.lex;
18063     
18064     marked.InlineLexer = InlineLexer;
18065     marked.inlineLexer = InlineLexer.output;
18066     
18067     marked.parse = marked;
18068     
18069     Roo.Markdown.marked = marked;
18070
18071 })();/*
18072  * Based on:
18073  * Ext JS Library 1.1.1
18074  * Copyright(c) 2006-2007, Ext JS, LLC.
18075  *
18076  * Originally Released Under LGPL - original licence link has changed is not relivant.
18077  *
18078  * Fork - LGPL
18079  * <script type="text/javascript">
18080  */
18081
18082
18083
18084 /*
18085  * These classes are derivatives of the similarly named classes in the YUI Library.
18086  * The original license:
18087  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18088  * Code licensed under the BSD License:
18089  * http://developer.yahoo.net/yui/license.txt
18090  */
18091
18092 (function() {
18093
18094 var Event=Roo.EventManager;
18095 var Dom=Roo.lib.Dom;
18096
18097 /**
18098  * @class Roo.dd.DragDrop
18099  * @extends Roo.util.Observable
18100  * Defines the interface and base operation of items that that can be
18101  * dragged or can be drop targets.  It was designed to be extended, overriding
18102  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18103  * Up to three html elements can be associated with a DragDrop instance:
18104  * <ul>
18105  * <li>linked element: the element that is passed into the constructor.
18106  * This is the element which defines the boundaries for interaction with
18107  * other DragDrop objects.</li>
18108  * <li>handle element(s): The drag operation only occurs if the element that
18109  * was clicked matches a handle element.  By default this is the linked
18110  * element, but there are times that you will want only a portion of the
18111  * linked element to initiate the drag operation, and the setHandleElId()
18112  * method provides a way to define this.</li>
18113  * <li>drag element: this represents the element that would be moved along
18114  * with the cursor during a drag operation.  By default, this is the linked
18115  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18116  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18117  * </li>
18118  * </ul>
18119  * This class should not be instantiated until the onload event to ensure that
18120  * the associated elements are available.
18121  * The following would define a DragDrop obj that would interact with any
18122  * other DragDrop obj in the "group1" group:
18123  * <pre>
18124  *  dd = new Roo.dd.DragDrop("div1", "group1");
18125  * </pre>
18126  * Since none of the event handlers have been implemented, nothing would
18127  * actually happen if you were to run the code above.  Normally you would
18128  * override this class or one of the default implementations, but you can
18129  * also override the methods you want on an instance of the class...
18130  * <pre>
18131  *  dd.onDragDrop = function(e, id) {
18132  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18133  *  }
18134  * </pre>
18135  * @constructor
18136  * @param {String} id of the element that is linked to this instance
18137  * @param {String} sGroup the group of related DragDrop objects
18138  * @param {object} config an object containing configurable attributes
18139  *                Valid properties for DragDrop:
18140  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18141  */
18142 Roo.dd.DragDrop = function(id, sGroup, config) {
18143     if (id) {
18144         this.init(id, sGroup, config);
18145     }
18146     
18147 };
18148
18149 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18150
18151     /**
18152      * The id of the element associated with this object.  This is what we
18153      * refer to as the "linked element" because the size and position of
18154      * this element is used to determine when the drag and drop objects have
18155      * interacted.
18156      * @property id
18157      * @type String
18158      */
18159     id: null,
18160
18161     /**
18162      * Configuration attributes passed into the constructor
18163      * @property config
18164      * @type object
18165      */
18166     config: null,
18167
18168     /**
18169      * The id of the element that will be dragged.  By default this is same
18170      * as the linked element , but could be changed to another element. Ex:
18171      * Roo.dd.DDProxy
18172      * @property dragElId
18173      * @type String
18174      * @private
18175      */
18176     dragElId: null,
18177
18178     /**
18179      * the id of the element that initiates the drag operation.  By default
18180      * this is the linked element, but could be changed to be a child of this
18181      * element.  This lets us do things like only starting the drag when the
18182      * header element within the linked html element is clicked.
18183      * @property handleElId
18184      * @type String
18185      * @private
18186      */
18187     handleElId: null,
18188
18189     /**
18190      * An associative array of HTML tags that will be ignored if clicked.
18191      * @property invalidHandleTypes
18192      * @type {string: string}
18193      */
18194     invalidHandleTypes: null,
18195
18196     /**
18197      * An associative array of ids for elements that will be ignored if clicked
18198      * @property invalidHandleIds
18199      * @type {string: string}
18200      */
18201     invalidHandleIds: null,
18202
18203     /**
18204      * An indexted array of css class names for elements that will be ignored
18205      * if clicked.
18206      * @property invalidHandleClasses
18207      * @type string[]
18208      */
18209     invalidHandleClasses: null,
18210
18211     /**
18212      * The linked element's absolute X position at the time the drag was
18213      * started
18214      * @property startPageX
18215      * @type int
18216      * @private
18217      */
18218     startPageX: 0,
18219
18220     /**
18221      * The linked element's absolute X position at the time the drag was
18222      * started
18223      * @property startPageY
18224      * @type int
18225      * @private
18226      */
18227     startPageY: 0,
18228
18229     /**
18230      * The group defines a logical collection of DragDrop objects that are
18231      * related.  Instances only get events when interacting with other
18232      * DragDrop object in the same group.  This lets us define multiple
18233      * groups using a single DragDrop subclass if we want.
18234      * @property groups
18235      * @type {string: string}
18236      */
18237     groups: null,
18238
18239     /**
18240      * Individual drag/drop instances can be locked.  This will prevent
18241      * onmousedown start drag.
18242      * @property locked
18243      * @type boolean
18244      * @private
18245      */
18246     locked: false,
18247
18248     /**
18249      * Lock this instance
18250      * @method lock
18251      */
18252     lock: function() { this.locked = true; },
18253
18254     /**
18255      * Unlock this instace
18256      * @method unlock
18257      */
18258     unlock: function() { this.locked = false; },
18259
18260     /**
18261      * By default, all insances can be a drop target.  This can be disabled by
18262      * setting isTarget to false.
18263      * @method isTarget
18264      * @type boolean
18265      */
18266     isTarget: true,
18267
18268     /**
18269      * The padding configured for this drag and drop object for calculating
18270      * the drop zone intersection with this object.
18271      * @method padding
18272      * @type int[]
18273      */
18274     padding: null,
18275
18276     /**
18277      * Cached reference to the linked element
18278      * @property _domRef
18279      * @private
18280      */
18281     _domRef: null,
18282
18283     /**
18284      * Internal typeof flag
18285      * @property __ygDragDrop
18286      * @private
18287      */
18288     __ygDragDrop: true,
18289
18290     /**
18291      * Set to true when horizontal contraints are applied
18292      * @property constrainX
18293      * @type boolean
18294      * @private
18295      */
18296     constrainX: false,
18297
18298     /**
18299      * Set to true when vertical contraints are applied
18300      * @property constrainY
18301      * @type boolean
18302      * @private
18303      */
18304     constrainY: false,
18305
18306     /**
18307      * The left constraint
18308      * @property minX
18309      * @type int
18310      * @private
18311      */
18312     minX: 0,
18313
18314     /**
18315      * The right constraint
18316      * @property maxX
18317      * @type int
18318      * @private
18319      */
18320     maxX: 0,
18321
18322     /**
18323      * The up constraint
18324      * @property minY
18325      * @type int
18326      * @type int
18327      * @private
18328      */
18329     minY: 0,
18330
18331     /**
18332      * The down constraint
18333      * @property maxY
18334      * @type int
18335      * @private
18336      */
18337     maxY: 0,
18338
18339     /**
18340      * Maintain offsets when we resetconstraints.  Set to true when you want
18341      * the position of the element relative to its parent to stay the same
18342      * when the page changes
18343      *
18344      * @property maintainOffset
18345      * @type boolean
18346      */
18347     maintainOffset: false,
18348
18349     /**
18350      * Array of pixel locations the element will snap to if we specified a
18351      * horizontal graduation/interval.  This array is generated automatically
18352      * when you define a tick interval.
18353      * @property xTicks
18354      * @type int[]
18355      */
18356     xTicks: null,
18357
18358     /**
18359      * Array of pixel locations the element will snap to if we specified a
18360      * vertical graduation/interval.  This array is generated automatically
18361      * when you define a tick interval.
18362      * @property yTicks
18363      * @type int[]
18364      */
18365     yTicks: null,
18366
18367     /**
18368      * By default the drag and drop instance will only respond to the primary
18369      * button click (left button for a right-handed mouse).  Set to true to
18370      * allow drag and drop to start with any mouse click that is propogated
18371      * by the browser
18372      * @property primaryButtonOnly
18373      * @type boolean
18374      */
18375     primaryButtonOnly: true,
18376
18377     /**
18378      * The availabe property is false until the linked dom element is accessible.
18379      * @property available
18380      * @type boolean
18381      */
18382     available: false,
18383
18384     /**
18385      * By default, drags can only be initiated if the mousedown occurs in the
18386      * region the linked element is.  This is done in part to work around a
18387      * bug in some browsers that mis-report the mousedown if the previous
18388      * mouseup happened outside of the window.  This property is set to true
18389      * if outer handles are defined.
18390      *
18391      * @property hasOuterHandles
18392      * @type boolean
18393      * @default false
18394      */
18395     hasOuterHandles: false,
18396
18397     /**
18398      * Code that executes immediately before the startDrag event
18399      * @method b4StartDrag
18400      * @private
18401      */
18402     b4StartDrag: function(x, y) { },
18403
18404     /**
18405      * Abstract method called after a drag/drop object is clicked
18406      * and the drag or mousedown time thresholds have beeen met.
18407      * @method startDrag
18408      * @param {int} X click location
18409      * @param {int} Y click location
18410      */
18411     startDrag: function(x, y) { /* override this */ },
18412
18413     /**
18414      * Code that executes immediately before the onDrag event
18415      * @method b4Drag
18416      * @private
18417      */
18418     b4Drag: function(e) { },
18419
18420     /**
18421      * Abstract method called during the onMouseMove event while dragging an
18422      * object.
18423      * @method onDrag
18424      * @param {Event} e the mousemove event
18425      */
18426     onDrag: function(e) { /* override this */ },
18427
18428     /**
18429      * Abstract method called when this element fist begins hovering over
18430      * another DragDrop obj
18431      * @method onDragEnter
18432      * @param {Event} e the mousemove event
18433      * @param {String|DragDrop[]} id In POINT mode, the element
18434      * id this is hovering over.  In INTERSECT mode, an array of one or more
18435      * dragdrop items being hovered over.
18436      */
18437     onDragEnter: function(e, id) { /* override this */ },
18438
18439     /**
18440      * Code that executes immediately before the onDragOver event
18441      * @method b4DragOver
18442      * @private
18443      */
18444     b4DragOver: function(e) { },
18445
18446     /**
18447      * Abstract method called when this element is hovering over another
18448      * DragDrop obj
18449      * @method onDragOver
18450      * @param {Event} e the mousemove event
18451      * @param {String|DragDrop[]} id In POINT mode, the element
18452      * id this is hovering over.  In INTERSECT mode, an array of dd items
18453      * being hovered over.
18454      */
18455     onDragOver: function(e, id) { /* override this */ },
18456
18457     /**
18458      * Code that executes immediately before the onDragOut event
18459      * @method b4DragOut
18460      * @private
18461      */
18462     b4DragOut: function(e) { },
18463
18464     /**
18465      * Abstract method called when we are no longer hovering over an element
18466      * @method onDragOut
18467      * @param {Event} e the mousemove event
18468      * @param {String|DragDrop[]} id In POINT mode, the element
18469      * id this was hovering over.  In INTERSECT mode, an array of dd items
18470      * that the mouse is no longer over.
18471      */
18472     onDragOut: function(e, id) { /* override this */ },
18473
18474     /**
18475      * Code that executes immediately before the onDragDrop event
18476      * @method b4DragDrop
18477      * @private
18478      */
18479     b4DragDrop: function(e) { },
18480
18481     /**
18482      * Abstract method called when this item is dropped on another DragDrop
18483      * obj
18484      * @method onDragDrop
18485      * @param {Event} e the mouseup event
18486      * @param {String|DragDrop[]} id In POINT mode, the element
18487      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18488      * was dropped on.
18489      */
18490     onDragDrop: function(e, id) { /* override this */ },
18491
18492     /**
18493      * Abstract method called when this item is dropped on an area with no
18494      * drop target
18495      * @method onInvalidDrop
18496      * @param {Event} e the mouseup event
18497      */
18498     onInvalidDrop: function(e) { /* override this */ },
18499
18500     /**
18501      * Code that executes immediately before the endDrag event
18502      * @method b4EndDrag
18503      * @private
18504      */
18505     b4EndDrag: function(e) { },
18506
18507     /**
18508      * Fired when we are done dragging the object
18509      * @method endDrag
18510      * @param {Event} e the mouseup event
18511      */
18512     endDrag: function(e) { /* override this */ },
18513
18514     /**
18515      * Code executed immediately before the onMouseDown event
18516      * @method b4MouseDown
18517      * @param {Event} e the mousedown event
18518      * @private
18519      */
18520     b4MouseDown: function(e) {  },
18521
18522     /**
18523      * Event handler that fires when a drag/drop obj gets a mousedown
18524      * @method onMouseDown
18525      * @param {Event} e the mousedown event
18526      */
18527     onMouseDown: function(e) { /* override this */ },
18528
18529     /**
18530      * Event handler that fires when a drag/drop obj gets a mouseup
18531      * @method onMouseUp
18532      * @param {Event} e the mouseup event
18533      */
18534     onMouseUp: function(e) { /* override this */ },
18535
18536     /**
18537      * Override the onAvailable method to do what is needed after the initial
18538      * position was determined.
18539      * @method onAvailable
18540      */
18541     onAvailable: function () {
18542     },
18543
18544     /*
18545      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18546      * @type Object
18547      */
18548     defaultPadding : {left:0, right:0, top:0, bottom:0},
18549
18550     /*
18551      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18552  *
18553  * Usage:
18554  <pre><code>
18555  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18556                 { dragElId: "existingProxyDiv" });
18557  dd.startDrag = function(){
18558      this.constrainTo("parent-id");
18559  };
18560  </code></pre>
18561  * Or you can initalize it using the {@link Roo.Element} object:
18562  <pre><code>
18563  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18564      startDrag : function(){
18565          this.constrainTo("parent-id");
18566      }
18567  });
18568  </code></pre>
18569      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18570      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18571      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18572      * an object containing the sides to pad. For example: {right:10, bottom:10}
18573      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18574      */
18575     constrainTo : function(constrainTo, pad, inContent){
18576         if(typeof pad == "number"){
18577             pad = {left: pad, right:pad, top:pad, bottom:pad};
18578         }
18579         pad = pad || this.defaultPadding;
18580         var b = Roo.get(this.getEl()).getBox();
18581         var ce = Roo.get(constrainTo);
18582         var s = ce.getScroll();
18583         var c, cd = ce.dom;
18584         if(cd == document.body){
18585             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18586         }else{
18587             xy = ce.getXY();
18588             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18589         }
18590
18591
18592         var topSpace = b.y - c.y;
18593         var leftSpace = b.x - c.x;
18594
18595         this.resetConstraints();
18596         this.setXConstraint(leftSpace - (pad.left||0), // left
18597                 c.width - leftSpace - b.width - (pad.right||0) //right
18598         );
18599         this.setYConstraint(topSpace - (pad.top||0), //top
18600                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18601         );
18602     },
18603
18604     /**
18605      * Returns a reference to the linked element
18606      * @method getEl
18607      * @return {HTMLElement} the html element
18608      */
18609     getEl: function() {
18610         if (!this._domRef) {
18611             this._domRef = Roo.getDom(this.id);
18612         }
18613
18614         return this._domRef;
18615     },
18616
18617     /**
18618      * Returns a reference to the actual element to drag.  By default this is
18619      * the same as the html element, but it can be assigned to another
18620      * element. An example of this can be found in Roo.dd.DDProxy
18621      * @method getDragEl
18622      * @return {HTMLElement} the html element
18623      */
18624     getDragEl: function() {
18625         return Roo.getDom(this.dragElId);
18626     },
18627
18628     /**
18629      * Sets up the DragDrop object.  Must be called in the constructor of any
18630      * Roo.dd.DragDrop subclass
18631      * @method init
18632      * @param id the id of the linked element
18633      * @param {String} sGroup the group of related items
18634      * @param {object} config configuration attributes
18635      */
18636     init: function(id, sGroup, config) {
18637         this.initTarget(id, sGroup, config);
18638         if (!Roo.isTouch) {
18639             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18640         }
18641         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18642         // Event.on(this.id, "selectstart", Event.preventDefault);
18643     },
18644
18645     /**
18646      * Initializes Targeting functionality only... the object does not
18647      * get a mousedown handler.
18648      * @method initTarget
18649      * @param id the id of the linked element
18650      * @param {String} sGroup the group of related items
18651      * @param {object} config configuration attributes
18652      */
18653     initTarget: function(id, sGroup, config) {
18654
18655         // configuration attributes
18656         this.config = config || {};
18657
18658         // create a local reference to the drag and drop manager
18659         this.DDM = Roo.dd.DDM;
18660         // initialize the groups array
18661         this.groups = {};
18662
18663         // assume that we have an element reference instead of an id if the
18664         // parameter is not a string
18665         if (typeof id !== "string") {
18666             id = Roo.id(id);
18667         }
18668
18669         // set the id
18670         this.id = id;
18671
18672         // add to an interaction group
18673         this.addToGroup((sGroup) ? sGroup : "default");
18674
18675         // We don't want to register this as the handle with the manager
18676         // so we just set the id rather than calling the setter.
18677         this.handleElId = id;
18678
18679         // the linked element is the element that gets dragged by default
18680         this.setDragElId(id);
18681
18682         // by default, clicked anchors will not start drag operations.
18683         this.invalidHandleTypes = { A: "A" };
18684         this.invalidHandleIds = {};
18685         this.invalidHandleClasses = [];
18686
18687         this.applyConfig();
18688
18689         this.handleOnAvailable();
18690     },
18691
18692     /**
18693      * Applies the configuration parameters that were passed into the constructor.
18694      * This is supposed to happen at each level through the inheritance chain.  So
18695      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18696      * DragDrop in order to get all of the parameters that are available in
18697      * each object.
18698      * @method applyConfig
18699      */
18700     applyConfig: function() {
18701
18702         // configurable properties:
18703         //    padding, isTarget, maintainOffset, primaryButtonOnly
18704         this.padding           = this.config.padding || [0, 0, 0, 0];
18705         this.isTarget          = (this.config.isTarget !== false);
18706         this.maintainOffset    = (this.config.maintainOffset);
18707         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18708
18709     },
18710
18711     /**
18712      * Executed when the linked element is available
18713      * @method handleOnAvailable
18714      * @private
18715      */
18716     handleOnAvailable: function() {
18717         this.available = true;
18718         this.resetConstraints();
18719         this.onAvailable();
18720     },
18721
18722      /**
18723      * Configures the padding for the target zone in px.  Effectively expands
18724      * (or reduces) the virtual object size for targeting calculations.
18725      * Supports css-style shorthand; if only one parameter is passed, all sides
18726      * will have that padding, and if only two are passed, the top and bottom
18727      * will have the first param, the left and right the second.
18728      * @method setPadding
18729      * @param {int} iTop    Top pad
18730      * @param {int} iRight  Right pad
18731      * @param {int} iBot    Bot pad
18732      * @param {int} iLeft   Left pad
18733      */
18734     setPadding: function(iTop, iRight, iBot, iLeft) {
18735         // this.padding = [iLeft, iRight, iTop, iBot];
18736         if (!iRight && 0 !== iRight) {
18737             this.padding = [iTop, iTop, iTop, iTop];
18738         } else if (!iBot && 0 !== iBot) {
18739             this.padding = [iTop, iRight, iTop, iRight];
18740         } else {
18741             this.padding = [iTop, iRight, iBot, iLeft];
18742         }
18743     },
18744
18745     /**
18746      * Stores the initial placement of the linked element.
18747      * @method setInitialPosition
18748      * @param {int} diffX   the X offset, default 0
18749      * @param {int} diffY   the Y offset, default 0
18750      */
18751     setInitPosition: function(diffX, diffY) {
18752         var el = this.getEl();
18753
18754         if (!this.DDM.verifyEl(el)) {
18755             return;
18756         }
18757
18758         var dx = diffX || 0;
18759         var dy = diffY || 0;
18760
18761         var p = Dom.getXY( el );
18762
18763         this.initPageX = p[0] - dx;
18764         this.initPageY = p[1] - dy;
18765
18766         this.lastPageX = p[0];
18767         this.lastPageY = p[1];
18768
18769
18770         this.setStartPosition(p);
18771     },
18772
18773     /**
18774      * Sets the start position of the element.  This is set when the obj
18775      * is initialized, the reset when a drag is started.
18776      * @method setStartPosition
18777      * @param pos current position (from previous lookup)
18778      * @private
18779      */
18780     setStartPosition: function(pos) {
18781         var p = pos || Dom.getXY( this.getEl() );
18782         this.deltaSetXY = null;
18783
18784         this.startPageX = p[0];
18785         this.startPageY = p[1];
18786     },
18787
18788     /**
18789      * Add this instance to a group of related drag/drop objects.  All
18790      * instances belong to at least one group, and can belong to as many
18791      * groups as needed.
18792      * @method addToGroup
18793      * @param sGroup {string} the name of the group
18794      */
18795     addToGroup: function(sGroup) {
18796         this.groups[sGroup] = true;
18797         this.DDM.regDragDrop(this, sGroup);
18798     },
18799
18800     /**
18801      * Remove's this instance from the supplied interaction group
18802      * @method removeFromGroup
18803      * @param {string}  sGroup  The group to drop
18804      */
18805     removeFromGroup: function(sGroup) {
18806         if (this.groups[sGroup]) {
18807             delete this.groups[sGroup];
18808         }
18809
18810         this.DDM.removeDDFromGroup(this, sGroup);
18811     },
18812
18813     /**
18814      * Allows you to specify that an element other than the linked element
18815      * will be moved with the cursor during a drag
18816      * @method setDragElId
18817      * @param id {string} the id of the element that will be used to initiate the drag
18818      */
18819     setDragElId: function(id) {
18820         this.dragElId = id;
18821     },
18822
18823     /**
18824      * Allows you to specify a child of the linked element that should be
18825      * used to initiate the drag operation.  An example of this would be if
18826      * you have a content div with text and links.  Clicking anywhere in the
18827      * content area would normally start the drag operation.  Use this method
18828      * to specify that an element inside of the content div is the element
18829      * that starts the drag operation.
18830      * @method setHandleElId
18831      * @param id {string} the id of the element that will be used to
18832      * initiate the drag.
18833      */
18834     setHandleElId: function(id) {
18835         if (typeof id !== "string") {
18836             id = Roo.id(id);
18837         }
18838         this.handleElId = id;
18839         this.DDM.regHandle(this.id, id);
18840     },
18841
18842     /**
18843      * Allows you to set an element outside of the linked element as a drag
18844      * handle
18845      * @method setOuterHandleElId
18846      * @param id the id of the element that will be used to initiate the drag
18847      */
18848     setOuterHandleElId: function(id) {
18849         if (typeof id !== "string") {
18850             id = Roo.id(id);
18851         }
18852         Event.on(id, "mousedown",
18853                 this.handleMouseDown, this);
18854         this.setHandleElId(id);
18855
18856         this.hasOuterHandles = true;
18857     },
18858
18859     /**
18860      * Remove all drag and drop hooks for this element
18861      * @method unreg
18862      */
18863     unreg: function() {
18864         Event.un(this.id, "mousedown",
18865                 this.handleMouseDown);
18866         Event.un(this.id, "touchstart",
18867                 this.handleMouseDown);
18868         this._domRef = null;
18869         this.DDM._remove(this);
18870     },
18871
18872     destroy : function(){
18873         this.unreg();
18874     },
18875
18876     /**
18877      * Returns true if this instance is locked, or the drag drop mgr is locked
18878      * (meaning that all drag/drop is disabled on the page.)
18879      * @method isLocked
18880      * @return {boolean} true if this obj or all drag/drop is locked, else
18881      * false
18882      */
18883     isLocked: function() {
18884         return (this.DDM.isLocked() || this.locked);
18885     },
18886
18887     /**
18888      * Fired when this object is clicked
18889      * @method handleMouseDown
18890      * @param {Event} e
18891      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18892      * @private
18893      */
18894     handleMouseDown: function(e, oDD){
18895      
18896         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18897             //Roo.log('not touch/ button !=0');
18898             return;
18899         }
18900         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18901             return; // double touch..
18902         }
18903         
18904
18905         if (this.isLocked()) {
18906             //Roo.log('locked');
18907             return;
18908         }
18909
18910         this.DDM.refreshCache(this.groups);
18911 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18912         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18913         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18914             //Roo.log('no outer handes or not over target');
18915                 // do nothing.
18916         } else {
18917 //            Roo.log('check validator');
18918             if (this.clickValidator(e)) {
18919 //                Roo.log('validate success');
18920                 // set the initial element position
18921                 this.setStartPosition();
18922
18923
18924                 this.b4MouseDown(e);
18925                 this.onMouseDown(e);
18926
18927                 this.DDM.handleMouseDown(e, this);
18928
18929                 this.DDM.stopEvent(e);
18930             } else {
18931
18932
18933             }
18934         }
18935     },
18936
18937     clickValidator: function(e) {
18938         var target = e.getTarget();
18939         return ( this.isValidHandleChild(target) &&
18940                     (this.id == this.handleElId ||
18941                         this.DDM.handleWasClicked(target, this.id)) );
18942     },
18943
18944     /**
18945      * Allows you to specify a tag name that should not start a drag operation
18946      * when clicked.  This is designed to facilitate embedding links within a
18947      * drag handle that do something other than start the drag.
18948      * @method addInvalidHandleType
18949      * @param {string} tagName the type of element to exclude
18950      */
18951     addInvalidHandleType: function(tagName) {
18952         var type = tagName.toUpperCase();
18953         this.invalidHandleTypes[type] = type;
18954     },
18955
18956     /**
18957      * Lets you to specify an element id for a child of a drag handle
18958      * that should not initiate a drag
18959      * @method addInvalidHandleId
18960      * @param {string} id the element id of the element you wish to ignore
18961      */
18962     addInvalidHandleId: function(id) {
18963         if (typeof id !== "string") {
18964             id = Roo.id(id);
18965         }
18966         this.invalidHandleIds[id] = id;
18967     },
18968
18969     /**
18970      * Lets you specify a css class of elements that will not initiate a drag
18971      * @method addInvalidHandleClass
18972      * @param {string} cssClass the class of the elements you wish to ignore
18973      */
18974     addInvalidHandleClass: function(cssClass) {
18975         this.invalidHandleClasses.push(cssClass);
18976     },
18977
18978     /**
18979      * Unsets an excluded tag name set by addInvalidHandleType
18980      * @method removeInvalidHandleType
18981      * @param {string} tagName the type of element to unexclude
18982      */
18983     removeInvalidHandleType: function(tagName) {
18984         var type = tagName.toUpperCase();
18985         // this.invalidHandleTypes[type] = null;
18986         delete this.invalidHandleTypes[type];
18987     },
18988
18989     /**
18990      * Unsets an invalid handle id
18991      * @method removeInvalidHandleId
18992      * @param {string} id the id of the element to re-enable
18993      */
18994     removeInvalidHandleId: function(id) {
18995         if (typeof id !== "string") {
18996             id = Roo.id(id);
18997         }
18998         delete this.invalidHandleIds[id];
18999     },
19000
19001     /**
19002      * Unsets an invalid css class
19003      * @method removeInvalidHandleClass
19004      * @param {string} cssClass the class of the element(s) you wish to
19005      * re-enable
19006      */
19007     removeInvalidHandleClass: function(cssClass) {
19008         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19009             if (this.invalidHandleClasses[i] == cssClass) {
19010                 delete this.invalidHandleClasses[i];
19011             }
19012         }
19013     },
19014
19015     /**
19016      * Checks the tag exclusion list to see if this click should be ignored
19017      * @method isValidHandleChild
19018      * @param {HTMLElement} node the HTMLElement to evaluate
19019      * @return {boolean} true if this is a valid tag type, false if not
19020      */
19021     isValidHandleChild: function(node) {
19022
19023         var valid = true;
19024         // var n = (node.nodeName == "#text") ? node.parentNode : node;
19025         var nodeName;
19026         try {
19027             nodeName = node.nodeName.toUpperCase();
19028         } catch(e) {
19029             nodeName = node.nodeName;
19030         }
19031         valid = valid && !this.invalidHandleTypes[nodeName];
19032         valid = valid && !this.invalidHandleIds[node.id];
19033
19034         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19035             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19036         }
19037
19038
19039         return valid;
19040
19041     },
19042
19043     /**
19044      * Create the array of horizontal tick marks if an interval was specified
19045      * in setXConstraint().
19046      * @method setXTicks
19047      * @private
19048      */
19049     setXTicks: function(iStartX, iTickSize) {
19050         this.xTicks = [];
19051         this.xTickSize = iTickSize;
19052
19053         var tickMap = {};
19054
19055         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19056             if (!tickMap[i]) {
19057                 this.xTicks[this.xTicks.length] = i;
19058                 tickMap[i] = true;
19059             }
19060         }
19061
19062         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19063             if (!tickMap[i]) {
19064                 this.xTicks[this.xTicks.length] = i;
19065                 tickMap[i] = true;
19066             }
19067         }
19068
19069         this.xTicks.sort(this.DDM.numericSort) ;
19070     },
19071
19072     /**
19073      * Create the array of vertical tick marks if an interval was specified in
19074      * setYConstraint().
19075      * @method setYTicks
19076      * @private
19077      */
19078     setYTicks: function(iStartY, iTickSize) {
19079         this.yTicks = [];
19080         this.yTickSize = iTickSize;
19081
19082         var tickMap = {};
19083
19084         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19085             if (!tickMap[i]) {
19086                 this.yTicks[this.yTicks.length] = i;
19087                 tickMap[i] = true;
19088             }
19089         }
19090
19091         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19092             if (!tickMap[i]) {
19093                 this.yTicks[this.yTicks.length] = i;
19094                 tickMap[i] = true;
19095             }
19096         }
19097
19098         this.yTicks.sort(this.DDM.numericSort) ;
19099     },
19100
19101     /**
19102      * By default, the element can be dragged any place on the screen.  Use
19103      * this method to limit the horizontal travel of the element.  Pass in
19104      * 0,0 for the parameters if you want to lock the drag to the y axis.
19105      * @method setXConstraint
19106      * @param {int} iLeft the number of pixels the element can move to the left
19107      * @param {int} iRight the number of pixels the element can move to the
19108      * right
19109      * @param {int} iTickSize optional parameter for specifying that the
19110      * element
19111      * should move iTickSize pixels at a time.
19112      */
19113     setXConstraint: function(iLeft, iRight, iTickSize) {
19114         this.leftConstraint = iLeft;
19115         this.rightConstraint = iRight;
19116
19117         this.minX = this.initPageX - iLeft;
19118         this.maxX = this.initPageX + iRight;
19119         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19120
19121         this.constrainX = true;
19122     },
19123
19124     /**
19125      * Clears any constraints applied to this instance.  Also clears ticks
19126      * since they can't exist independent of a constraint at this time.
19127      * @method clearConstraints
19128      */
19129     clearConstraints: function() {
19130         this.constrainX = false;
19131         this.constrainY = false;
19132         this.clearTicks();
19133     },
19134
19135     /**
19136      * Clears any tick interval defined for this instance
19137      * @method clearTicks
19138      */
19139     clearTicks: function() {
19140         this.xTicks = null;
19141         this.yTicks = null;
19142         this.xTickSize = 0;
19143         this.yTickSize = 0;
19144     },
19145
19146     /**
19147      * By default, the element can be dragged any place on the screen.  Set
19148      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19149      * parameters if you want to lock the drag to the x axis.
19150      * @method setYConstraint
19151      * @param {int} iUp the number of pixels the element can move up
19152      * @param {int} iDown the number of pixels the element can move down
19153      * @param {int} iTickSize optional parameter for specifying that the
19154      * element should move iTickSize pixels at a time.
19155      */
19156     setYConstraint: function(iUp, iDown, iTickSize) {
19157         this.topConstraint = iUp;
19158         this.bottomConstraint = iDown;
19159
19160         this.minY = this.initPageY - iUp;
19161         this.maxY = this.initPageY + iDown;
19162         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19163
19164         this.constrainY = true;
19165
19166     },
19167
19168     /**
19169      * resetConstraints must be called if you manually reposition a dd element.
19170      * @method resetConstraints
19171      * @param {boolean} maintainOffset
19172      */
19173     resetConstraints: function() {
19174
19175
19176         // Maintain offsets if necessary
19177         if (this.initPageX || this.initPageX === 0) {
19178             // figure out how much this thing has moved
19179             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19180             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19181
19182             this.setInitPosition(dx, dy);
19183
19184         // This is the first time we have detected the element's position
19185         } else {
19186             this.setInitPosition();
19187         }
19188
19189         if (this.constrainX) {
19190             this.setXConstraint( this.leftConstraint,
19191                                  this.rightConstraint,
19192                                  this.xTickSize        );
19193         }
19194
19195         if (this.constrainY) {
19196             this.setYConstraint( this.topConstraint,
19197                                  this.bottomConstraint,
19198                                  this.yTickSize         );
19199         }
19200     },
19201
19202     /**
19203      * Normally the drag element is moved pixel by pixel, but we can specify
19204      * that it move a number of pixels at a time.  This method resolves the
19205      * location when we have it set up like this.
19206      * @method getTick
19207      * @param {int} val where we want to place the object
19208      * @param {int[]} tickArray sorted array of valid points
19209      * @return {int} the closest tick
19210      * @private
19211      */
19212     getTick: function(val, tickArray) {
19213
19214         if (!tickArray) {
19215             // If tick interval is not defined, it is effectively 1 pixel,
19216             // so we return the value passed to us.
19217             return val;
19218         } else if (tickArray[0] >= val) {
19219             // The value is lower than the first tick, so we return the first
19220             // tick.
19221             return tickArray[0];
19222         } else {
19223             for (var i=0, len=tickArray.length; i<len; ++i) {
19224                 var next = i + 1;
19225                 if (tickArray[next] && tickArray[next] >= val) {
19226                     var diff1 = val - tickArray[i];
19227                     var diff2 = tickArray[next] - val;
19228                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19229                 }
19230             }
19231
19232             // The value is larger than the last tick, so we return the last
19233             // tick.
19234             return tickArray[tickArray.length - 1];
19235         }
19236     },
19237
19238     /**
19239      * toString method
19240      * @method toString
19241      * @return {string} string representation of the dd obj
19242      */
19243     toString: function() {
19244         return ("DragDrop " + this.id);
19245     }
19246
19247 });
19248
19249 })();
19250 /*
19251  * Based on:
19252  * Ext JS Library 1.1.1
19253  * Copyright(c) 2006-2007, Ext JS, LLC.
19254  *
19255  * Originally Released Under LGPL - original licence link has changed is not relivant.
19256  *
19257  * Fork - LGPL
19258  * <script type="text/javascript">
19259  */
19260
19261
19262 /**
19263  * The drag and drop utility provides a framework for building drag and drop
19264  * applications.  In addition to enabling drag and drop for specific elements,
19265  * the drag and drop elements are tracked by the manager class, and the
19266  * interactions between the various elements are tracked during the drag and
19267  * the implementing code is notified about these important moments.
19268  */
19269
19270 // Only load the library once.  Rewriting the manager class would orphan
19271 // existing drag and drop instances.
19272 if (!Roo.dd.DragDropMgr) {
19273
19274 /**
19275  * @class Roo.dd.DragDropMgr
19276  * DragDropMgr is a singleton that tracks the element interaction for
19277  * all DragDrop items in the window.  Generally, you will not call
19278  * this class directly, but it does have helper methods that could
19279  * be useful in your DragDrop implementations.
19280  * @singleton
19281  */
19282 Roo.dd.DragDropMgr = function() {
19283
19284     var Event = Roo.EventManager;
19285
19286     return {
19287
19288         /**
19289          * Two dimensional Array of registered DragDrop objects.  The first
19290          * dimension is the DragDrop item group, the second the DragDrop
19291          * object.
19292          * @property ids
19293          * @type {string: string}
19294          * @private
19295          * @static
19296          */
19297         ids: {},
19298
19299         /**
19300          * Array of element ids defined as drag handles.  Used to determine
19301          * if the element that generated the mousedown event is actually the
19302          * handle and not the html element itself.
19303          * @property handleIds
19304          * @type {string: string}
19305          * @private
19306          * @static
19307          */
19308         handleIds: {},
19309
19310         /**
19311          * the DragDrop object that is currently being dragged
19312          * @property dragCurrent
19313          * @type DragDrop
19314          * @private
19315          * @static
19316          **/
19317         dragCurrent: null,
19318
19319         /**
19320          * the DragDrop object(s) that are being hovered over
19321          * @property dragOvers
19322          * @type Array
19323          * @private
19324          * @static
19325          */
19326         dragOvers: {},
19327
19328         /**
19329          * the X distance between the cursor and the object being dragged
19330          * @property deltaX
19331          * @type int
19332          * @private
19333          * @static
19334          */
19335         deltaX: 0,
19336
19337         /**
19338          * the Y distance between the cursor and the object being dragged
19339          * @property deltaY
19340          * @type int
19341          * @private
19342          * @static
19343          */
19344         deltaY: 0,
19345
19346         /**
19347          * Flag to determine if we should prevent the default behavior of the
19348          * events we define. By default this is true, but this can be set to
19349          * false if you need the default behavior (not recommended)
19350          * @property preventDefault
19351          * @type boolean
19352          * @static
19353          */
19354         preventDefault: true,
19355
19356         /**
19357          * Flag to determine if we should stop the propagation of the events
19358          * we generate. This is true by default but you may want to set it to
19359          * false if the html element contains other features that require the
19360          * mouse click.
19361          * @property stopPropagation
19362          * @type boolean
19363          * @static
19364          */
19365         stopPropagation: true,
19366
19367         /**
19368          * Internal flag that is set to true when drag and drop has been
19369          * intialized
19370          * @property initialized
19371          * @private
19372          * @static
19373          */
19374         initalized: false,
19375
19376         /**
19377          * All drag and drop can be disabled.
19378          * @property locked
19379          * @private
19380          * @static
19381          */
19382         locked: false,
19383
19384         /**
19385          * Called the first time an element is registered.
19386          * @method init
19387          * @private
19388          * @static
19389          */
19390         init: function() {
19391             this.initialized = true;
19392         },
19393
19394         /**
19395          * In point mode, drag and drop interaction is defined by the
19396          * location of the cursor during the drag/drop
19397          * @property POINT
19398          * @type int
19399          * @static
19400          */
19401         POINT: 0,
19402
19403         /**
19404          * In intersect mode, drag and drop interactio nis defined by the
19405          * overlap of two or more drag and drop objects.
19406          * @property INTERSECT
19407          * @type int
19408          * @static
19409          */
19410         INTERSECT: 1,
19411
19412         /**
19413          * The current drag and drop mode.  Default: POINT
19414          * @property mode
19415          * @type int
19416          * @static
19417          */
19418         mode: 0,
19419
19420         /**
19421          * Runs method on all drag and drop objects
19422          * @method _execOnAll
19423          * @private
19424          * @static
19425          */
19426         _execOnAll: function(sMethod, args) {
19427             for (var i in this.ids) {
19428                 for (var j in this.ids[i]) {
19429                     var oDD = this.ids[i][j];
19430                     if (! this.isTypeOfDD(oDD)) {
19431                         continue;
19432                     }
19433                     oDD[sMethod].apply(oDD, args);
19434                 }
19435             }
19436         },
19437
19438         /**
19439          * Drag and drop initialization.  Sets up the global event handlers
19440          * @method _onLoad
19441          * @private
19442          * @static
19443          */
19444         _onLoad: function() {
19445
19446             this.init();
19447
19448             if (!Roo.isTouch) {
19449                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19450                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19451             }
19452             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19453             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19454             
19455             Event.on(window,   "unload",    this._onUnload, this, true);
19456             Event.on(window,   "resize",    this._onResize, this, true);
19457             // Event.on(window,   "mouseout",    this._test);
19458
19459         },
19460
19461         /**
19462          * Reset constraints on all drag and drop objs
19463          * @method _onResize
19464          * @private
19465          * @static
19466          */
19467         _onResize: function(e) {
19468             this._execOnAll("resetConstraints", []);
19469         },
19470
19471         /**
19472          * Lock all drag and drop functionality
19473          * @method lock
19474          * @static
19475          */
19476         lock: function() { this.locked = true; },
19477
19478         /**
19479          * Unlock all drag and drop functionality
19480          * @method unlock
19481          * @static
19482          */
19483         unlock: function() { this.locked = false; },
19484
19485         /**
19486          * Is drag and drop locked?
19487          * @method isLocked
19488          * @return {boolean} True if drag and drop is locked, false otherwise.
19489          * @static
19490          */
19491         isLocked: function() { return this.locked; },
19492
19493         /**
19494          * Location cache that is set for all drag drop objects when a drag is
19495          * initiated, cleared when the drag is finished.
19496          * @property locationCache
19497          * @private
19498          * @static
19499          */
19500         locationCache: {},
19501
19502         /**
19503          * Set useCache to false if you want to force object the lookup of each
19504          * drag and drop linked element constantly during a drag.
19505          * @property useCache
19506          * @type boolean
19507          * @static
19508          */
19509         useCache: true,
19510
19511         /**
19512          * The number of pixels that the mouse needs to move after the
19513          * mousedown before the drag is initiated.  Default=3;
19514          * @property clickPixelThresh
19515          * @type int
19516          * @static
19517          */
19518         clickPixelThresh: 3,
19519
19520         /**
19521          * The number of milliseconds after the mousedown event to initiate the
19522          * drag if we don't get a mouseup event. Default=1000
19523          * @property clickTimeThresh
19524          * @type int
19525          * @static
19526          */
19527         clickTimeThresh: 350,
19528
19529         /**
19530          * Flag that indicates that either the drag pixel threshold or the
19531          * mousdown time threshold has been met
19532          * @property dragThreshMet
19533          * @type boolean
19534          * @private
19535          * @static
19536          */
19537         dragThreshMet: false,
19538
19539         /**
19540          * Timeout used for the click time threshold
19541          * @property clickTimeout
19542          * @type Object
19543          * @private
19544          * @static
19545          */
19546         clickTimeout: null,
19547
19548         /**
19549          * The X position of the mousedown event stored for later use when a
19550          * drag threshold is met.
19551          * @property startX
19552          * @type int
19553          * @private
19554          * @static
19555          */
19556         startX: 0,
19557
19558         /**
19559          * The Y position of the mousedown event stored for later use when a
19560          * drag threshold is met.
19561          * @property startY
19562          * @type int
19563          * @private
19564          * @static
19565          */
19566         startY: 0,
19567
19568         /**
19569          * Each DragDrop instance must be registered with the DragDropMgr.
19570          * This is executed in DragDrop.init()
19571          * @method regDragDrop
19572          * @param {DragDrop} oDD the DragDrop object to register
19573          * @param {String} sGroup the name of the group this element belongs to
19574          * @static
19575          */
19576         regDragDrop: function(oDD, sGroup) {
19577             if (!this.initialized) { this.init(); }
19578
19579             if (!this.ids[sGroup]) {
19580                 this.ids[sGroup] = {};
19581             }
19582             this.ids[sGroup][oDD.id] = oDD;
19583         },
19584
19585         /**
19586          * Removes the supplied dd instance from the supplied group. Executed
19587          * by DragDrop.removeFromGroup, so don't call this function directly.
19588          * @method removeDDFromGroup
19589          * @private
19590          * @static
19591          */
19592         removeDDFromGroup: function(oDD, sGroup) {
19593             if (!this.ids[sGroup]) {
19594                 this.ids[sGroup] = {};
19595             }
19596
19597             var obj = this.ids[sGroup];
19598             if (obj && obj[oDD.id]) {
19599                 delete obj[oDD.id];
19600             }
19601         },
19602
19603         /**
19604          * Unregisters a drag and drop item.  This is executed in
19605          * DragDrop.unreg, use that method instead of calling this directly.
19606          * @method _remove
19607          * @private
19608          * @static
19609          */
19610         _remove: function(oDD) {
19611             for (var g in oDD.groups) {
19612                 if (g && this.ids[g][oDD.id]) {
19613                     delete this.ids[g][oDD.id];
19614                 }
19615             }
19616             delete this.handleIds[oDD.id];
19617         },
19618
19619         /**
19620          * Each DragDrop handle element must be registered.  This is done
19621          * automatically when executing DragDrop.setHandleElId()
19622          * @method regHandle
19623          * @param {String} sDDId the DragDrop id this element is a handle for
19624          * @param {String} sHandleId the id of the element that is the drag
19625          * handle
19626          * @static
19627          */
19628         regHandle: function(sDDId, sHandleId) {
19629             if (!this.handleIds[sDDId]) {
19630                 this.handleIds[sDDId] = {};
19631             }
19632             this.handleIds[sDDId][sHandleId] = sHandleId;
19633         },
19634
19635         /**
19636          * Utility function to determine if a given element has been
19637          * registered as a drag drop item.
19638          * @method isDragDrop
19639          * @param {String} id the element id to check
19640          * @return {boolean} true if this element is a DragDrop item,
19641          * false otherwise
19642          * @static
19643          */
19644         isDragDrop: function(id) {
19645             return ( this.getDDById(id) ) ? true : false;
19646         },
19647
19648         /**
19649          * Returns the drag and drop instances that are in all groups the
19650          * passed in instance belongs to.
19651          * @method getRelated
19652          * @param {DragDrop} p_oDD the obj to get related data for
19653          * @param {boolean} bTargetsOnly if true, only return targetable objs
19654          * @return {DragDrop[]} the related instances
19655          * @static
19656          */
19657         getRelated: function(p_oDD, bTargetsOnly) {
19658             var oDDs = [];
19659             for (var i in p_oDD.groups) {
19660                 for (j in this.ids[i]) {
19661                     var dd = this.ids[i][j];
19662                     if (! this.isTypeOfDD(dd)) {
19663                         continue;
19664                     }
19665                     if (!bTargetsOnly || dd.isTarget) {
19666                         oDDs[oDDs.length] = dd;
19667                     }
19668                 }
19669             }
19670
19671             return oDDs;
19672         },
19673
19674         /**
19675          * Returns true if the specified dd target is a legal target for
19676          * the specifice drag obj
19677          * @method isLegalTarget
19678          * @param {DragDrop} the drag obj
19679          * @param {DragDrop} the target
19680          * @return {boolean} true if the target is a legal target for the
19681          * dd obj
19682          * @static
19683          */
19684         isLegalTarget: function (oDD, oTargetDD) {
19685             var targets = this.getRelated(oDD, true);
19686             for (var i=0, len=targets.length;i<len;++i) {
19687                 if (targets[i].id == oTargetDD.id) {
19688                     return true;
19689                 }
19690             }
19691
19692             return false;
19693         },
19694
19695         /**
19696          * My goal is to be able to transparently determine if an object is
19697          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19698          * returns "object", oDD.constructor.toString() always returns
19699          * "DragDrop" and not the name of the subclass.  So for now it just
19700          * evaluates a well-known variable in DragDrop.
19701          * @method isTypeOfDD
19702          * @param {Object} the object to evaluate
19703          * @return {boolean} true if typeof oDD = DragDrop
19704          * @static
19705          */
19706         isTypeOfDD: function (oDD) {
19707             return (oDD && oDD.__ygDragDrop);
19708         },
19709
19710         /**
19711          * Utility function to determine if a given element has been
19712          * registered as a drag drop handle for the given Drag Drop object.
19713          * @method isHandle
19714          * @param {String} id the element id to check
19715          * @return {boolean} true if this element is a DragDrop handle, false
19716          * otherwise
19717          * @static
19718          */
19719         isHandle: function(sDDId, sHandleId) {
19720             return ( this.handleIds[sDDId] &&
19721                             this.handleIds[sDDId][sHandleId] );
19722         },
19723
19724         /**
19725          * Returns the DragDrop instance for a given id
19726          * @method getDDById
19727          * @param {String} id the id of the DragDrop object
19728          * @return {DragDrop} the drag drop object, null if it is not found
19729          * @static
19730          */
19731         getDDById: function(id) {
19732             for (var i in this.ids) {
19733                 if (this.ids[i][id]) {
19734                     return this.ids[i][id];
19735                 }
19736             }
19737             return null;
19738         },
19739
19740         /**
19741          * Fired after a registered DragDrop object gets the mousedown event.
19742          * Sets up the events required to track the object being dragged
19743          * @method handleMouseDown
19744          * @param {Event} e the event
19745          * @param oDD the DragDrop object being dragged
19746          * @private
19747          * @static
19748          */
19749         handleMouseDown: function(e, oDD) {
19750             if(Roo.QuickTips){
19751                 Roo.QuickTips.disable();
19752             }
19753             this.currentTarget = e.getTarget();
19754
19755             this.dragCurrent = oDD;
19756
19757             var el = oDD.getEl();
19758
19759             // track start position
19760             this.startX = e.getPageX();
19761             this.startY = e.getPageY();
19762
19763             this.deltaX = this.startX - el.offsetLeft;
19764             this.deltaY = this.startY - el.offsetTop;
19765
19766             this.dragThreshMet = false;
19767
19768             this.clickTimeout = setTimeout(
19769                     function() {
19770                         var DDM = Roo.dd.DDM;
19771                         DDM.startDrag(DDM.startX, DDM.startY);
19772                     },
19773                     this.clickTimeThresh );
19774         },
19775
19776         /**
19777          * Fired when either the drag pixel threshol or the mousedown hold
19778          * time threshold has been met.
19779          * @method startDrag
19780          * @param x {int} the X position of the original mousedown
19781          * @param y {int} the Y position of the original mousedown
19782          * @static
19783          */
19784         startDrag: function(x, y) {
19785             clearTimeout(this.clickTimeout);
19786             if (this.dragCurrent) {
19787                 this.dragCurrent.b4StartDrag(x, y);
19788                 this.dragCurrent.startDrag(x, y);
19789             }
19790             this.dragThreshMet = true;
19791         },
19792
19793         /**
19794          * Internal function to handle the mouseup event.  Will be invoked
19795          * from the context of the document.
19796          * @method handleMouseUp
19797          * @param {Event} e the event
19798          * @private
19799          * @static
19800          */
19801         handleMouseUp: function(e) {
19802
19803             if(Roo.QuickTips){
19804                 Roo.QuickTips.enable();
19805             }
19806             if (! this.dragCurrent) {
19807                 return;
19808             }
19809
19810             clearTimeout(this.clickTimeout);
19811
19812             if (this.dragThreshMet) {
19813                 this.fireEvents(e, true);
19814             } else {
19815             }
19816
19817             this.stopDrag(e);
19818
19819             this.stopEvent(e);
19820         },
19821
19822         /**
19823          * Utility to stop event propagation and event default, if these
19824          * features are turned on.
19825          * @method stopEvent
19826          * @param {Event} e the event as returned by this.getEvent()
19827          * @static
19828          */
19829         stopEvent: function(e){
19830             if(this.stopPropagation) {
19831                 e.stopPropagation();
19832             }
19833
19834             if (this.preventDefault) {
19835                 e.preventDefault();
19836             }
19837         },
19838
19839         /**
19840          * Internal function to clean up event handlers after the drag
19841          * operation is complete
19842          * @method stopDrag
19843          * @param {Event} e the event
19844          * @private
19845          * @static
19846          */
19847         stopDrag: function(e) {
19848             // Fire the drag end event for the item that was dragged
19849             if (this.dragCurrent) {
19850                 if (this.dragThreshMet) {
19851                     this.dragCurrent.b4EndDrag(e);
19852                     this.dragCurrent.endDrag(e);
19853                 }
19854
19855                 this.dragCurrent.onMouseUp(e);
19856             }
19857
19858             this.dragCurrent = null;
19859             this.dragOvers = {};
19860         },
19861
19862         /**
19863          * Internal function to handle the mousemove event.  Will be invoked
19864          * from the context of the html element.
19865          *
19866          * @TODO figure out what we can do about mouse events lost when the
19867          * user drags objects beyond the window boundary.  Currently we can
19868          * detect this in internet explorer by verifying that the mouse is
19869          * down during the mousemove event.  Firefox doesn't give us the
19870          * button state on the mousemove event.
19871          * @method handleMouseMove
19872          * @param {Event} e the event
19873          * @private
19874          * @static
19875          */
19876         handleMouseMove: function(e) {
19877             if (! this.dragCurrent) {
19878                 return true;
19879             }
19880
19881             // var button = e.which || e.button;
19882
19883             // check for IE mouseup outside of page boundary
19884             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19885                 this.stopEvent(e);
19886                 return this.handleMouseUp(e);
19887             }
19888
19889             if (!this.dragThreshMet) {
19890                 var diffX = Math.abs(this.startX - e.getPageX());
19891                 var diffY = Math.abs(this.startY - e.getPageY());
19892                 if (diffX > this.clickPixelThresh ||
19893                             diffY > this.clickPixelThresh) {
19894                     this.startDrag(this.startX, this.startY);
19895                 }
19896             }
19897
19898             if (this.dragThreshMet) {
19899                 this.dragCurrent.b4Drag(e);
19900                 this.dragCurrent.onDrag(e);
19901                 if(!this.dragCurrent.moveOnly){
19902                     this.fireEvents(e, false);
19903                 }
19904             }
19905
19906             this.stopEvent(e);
19907
19908             return true;
19909         },
19910
19911         /**
19912          * Iterates over all of the DragDrop elements to find ones we are
19913          * hovering over or dropping on
19914          * @method fireEvents
19915          * @param {Event} e the event
19916          * @param {boolean} isDrop is this a drop op or a mouseover op?
19917          * @private
19918          * @static
19919          */
19920         fireEvents: function(e, isDrop) {
19921             var dc = this.dragCurrent;
19922
19923             // If the user did the mouse up outside of the window, we could
19924             // get here even though we have ended the drag.
19925             if (!dc || dc.isLocked()) {
19926                 return;
19927             }
19928
19929             var pt = e.getPoint();
19930
19931             // cache the previous dragOver array
19932             var oldOvers = [];
19933
19934             var outEvts   = [];
19935             var overEvts  = [];
19936             var dropEvts  = [];
19937             var enterEvts = [];
19938
19939             // Check to see if the object(s) we were hovering over is no longer
19940             // being hovered over so we can fire the onDragOut event
19941             for (var i in this.dragOvers) {
19942
19943                 var ddo = this.dragOvers[i];
19944
19945                 if (! this.isTypeOfDD(ddo)) {
19946                     continue;
19947                 }
19948
19949                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19950                     outEvts.push( ddo );
19951                 }
19952
19953                 oldOvers[i] = true;
19954                 delete this.dragOvers[i];
19955             }
19956
19957             for (var sGroup in dc.groups) {
19958
19959                 if ("string" != typeof sGroup) {
19960                     continue;
19961                 }
19962
19963                 for (i in this.ids[sGroup]) {
19964                     var oDD = this.ids[sGroup][i];
19965                     if (! this.isTypeOfDD(oDD)) {
19966                         continue;
19967                     }
19968
19969                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19970                         if (this.isOverTarget(pt, oDD, this.mode)) {
19971                             // look for drop interactions
19972                             if (isDrop) {
19973                                 dropEvts.push( oDD );
19974                             // look for drag enter and drag over interactions
19975                             } else {
19976
19977                                 // initial drag over: dragEnter fires
19978                                 if (!oldOvers[oDD.id]) {
19979                                     enterEvts.push( oDD );
19980                                 // subsequent drag overs: dragOver fires
19981                                 } else {
19982                                     overEvts.push( oDD );
19983                                 }
19984
19985                                 this.dragOvers[oDD.id] = oDD;
19986                             }
19987                         }
19988                     }
19989                 }
19990             }
19991
19992             if (this.mode) {
19993                 if (outEvts.length) {
19994                     dc.b4DragOut(e, outEvts);
19995                     dc.onDragOut(e, outEvts);
19996                 }
19997
19998                 if (enterEvts.length) {
19999                     dc.onDragEnter(e, enterEvts);
20000                 }
20001
20002                 if (overEvts.length) {
20003                     dc.b4DragOver(e, overEvts);
20004                     dc.onDragOver(e, overEvts);
20005                 }
20006
20007                 if (dropEvts.length) {
20008                     dc.b4DragDrop(e, dropEvts);
20009                     dc.onDragDrop(e, dropEvts);
20010                 }
20011
20012             } else {
20013                 // fire dragout events
20014                 var len = 0;
20015                 for (i=0, len=outEvts.length; i<len; ++i) {
20016                     dc.b4DragOut(e, outEvts[i].id);
20017                     dc.onDragOut(e, outEvts[i].id);
20018                 }
20019
20020                 // fire enter events
20021                 for (i=0,len=enterEvts.length; i<len; ++i) {
20022                     // dc.b4DragEnter(e, oDD.id);
20023                     dc.onDragEnter(e, enterEvts[i].id);
20024                 }
20025
20026                 // fire over events
20027                 for (i=0,len=overEvts.length; i<len; ++i) {
20028                     dc.b4DragOver(e, overEvts[i].id);
20029                     dc.onDragOver(e, overEvts[i].id);
20030                 }
20031
20032                 // fire drop events
20033                 for (i=0, len=dropEvts.length; i<len; ++i) {
20034                     dc.b4DragDrop(e, dropEvts[i].id);
20035                     dc.onDragDrop(e, dropEvts[i].id);
20036                 }
20037
20038             }
20039
20040             // notify about a drop that did not find a target
20041             if (isDrop && !dropEvts.length) {
20042                 dc.onInvalidDrop(e);
20043             }
20044
20045         },
20046
20047         /**
20048          * Helper function for getting the best match from the list of drag
20049          * and drop objects returned by the drag and drop events when we are
20050          * in INTERSECT mode.  It returns either the first object that the
20051          * cursor is over, or the object that has the greatest overlap with
20052          * the dragged element.
20053          * @method getBestMatch
20054          * @param  {DragDrop[]} dds The array of drag and drop objects
20055          * targeted
20056          * @return {DragDrop}       The best single match
20057          * @static
20058          */
20059         getBestMatch: function(dds) {
20060             var winner = null;
20061             // Return null if the input is not what we expect
20062             //if (!dds || !dds.length || dds.length == 0) {
20063                // winner = null;
20064             // If there is only one item, it wins
20065             //} else if (dds.length == 1) {
20066
20067             var len = dds.length;
20068
20069             if (len == 1) {
20070                 winner = dds[0];
20071             } else {
20072                 // Loop through the targeted items
20073                 for (var i=0; i<len; ++i) {
20074                     var dd = dds[i];
20075                     // If the cursor is over the object, it wins.  If the
20076                     // cursor is over multiple matches, the first one we come
20077                     // to wins.
20078                     if (dd.cursorIsOver) {
20079                         winner = dd;
20080                         break;
20081                     // Otherwise the object with the most overlap wins
20082                     } else {
20083                         if (!winner ||
20084                             winner.overlap.getArea() < dd.overlap.getArea()) {
20085                             winner = dd;
20086                         }
20087                     }
20088                 }
20089             }
20090
20091             return winner;
20092         },
20093
20094         /**
20095          * Refreshes the cache of the top-left and bottom-right points of the
20096          * drag and drop objects in the specified group(s).  This is in the
20097          * format that is stored in the drag and drop instance, so typical
20098          * usage is:
20099          * <code>
20100          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20101          * </code>
20102          * Alternatively:
20103          * <code>
20104          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20105          * </code>
20106          * @TODO this really should be an indexed array.  Alternatively this
20107          * method could accept both.
20108          * @method refreshCache
20109          * @param {Object} groups an associative array of groups to refresh
20110          * @static
20111          */
20112         refreshCache: function(groups) {
20113             for (var sGroup in groups) {
20114                 if ("string" != typeof sGroup) {
20115                     continue;
20116                 }
20117                 for (var i in this.ids[sGroup]) {
20118                     var oDD = this.ids[sGroup][i];
20119
20120                     if (this.isTypeOfDD(oDD)) {
20121                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20122                         var loc = this.getLocation(oDD);
20123                         if (loc) {
20124                             this.locationCache[oDD.id] = loc;
20125                         } else {
20126                             delete this.locationCache[oDD.id];
20127                             // this will unregister the drag and drop object if
20128                             // the element is not in a usable state
20129                             // oDD.unreg();
20130                         }
20131                     }
20132                 }
20133             }
20134         },
20135
20136         /**
20137          * This checks to make sure an element exists and is in the DOM.  The
20138          * main purpose is to handle cases where innerHTML is used to remove
20139          * drag and drop objects from the DOM.  IE provides an 'unspecified
20140          * error' when trying to access the offsetParent of such an element
20141          * @method verifyEl
20142          * @param {HTMLElement} el the element to check
20143          * @return {boolean} true if the element looks usable
20144          * @static
20145          */
20146         verifyEl: function(el) {
20147             if (el) {
20148                 var parent;
20149                 if(Roo.isIE){
20150                     try{
20151                         parent = el.offsetParent;
20152                     }catch(e){}
20153                 }else{
20154                     parent = el.offsetParent;
20155                 }
20156                 if (parent) {
20157                     return true;
20158                 }
20159             }
20160
20161             return false;
20162         },
20163
20164         /**
20165          * Returns a Region object containing the drag and drop element's position
20166          * and size, including the padding configured for it
20167          * @method getLocation
20168          * @param {DragDrop} oDD the drag and drop object to get the
20169          *                       location for
20170          * @return {Roo.lib.Region} a Region object representing the total area
20171          *                             the element occupies, including any padding
20172          *                             the instance is configured for.
20173          * @static
20174          */
20175         getLocation: function(oDD) {
20176             if (! this.isTypeOfDD(oDD)) {
20177                 return null;
20178             }
20179
20180             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20181
20182             try {
20183                 pos= Roo.lib.Dom.getXY(el);
20184             } catch (e) { }
20185
20186             if (!pos) {
20187                 return null;
20188             }
20189
20190             x1 = pos[0];
20191             x2 = x1 + el.offsetWidth;
20192             y1 = pos[1];
20193             y2 = y1 + el.offsetHeight;
20194
20195             t = y1 - oDD.padding[0];
20196             r = x2 + oDD.padding[1];
20197             b = y2 + oDD.padding[2];
20198             l = x1 - oDD.padding[3];
20199
20200             return new Roo.lib.Region( t, r, b, l );
20201         },
20202
20203         /**
20204          * Checks the cursor location to see if it over the target
20205          * @method isOverTarget
20206          * @param {Roo.lib.Point} pt The point to evaluate
20207          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20208          * @return {boolean} true if the mouse is over the target
20209          * @private
20210          * @static
20211          */
20212         isOverTarget: function(pt, oTarget, intersect) {
20213             // use cache if available
20214             var loc = this.locationCache[oTarget.id];
20215             if (!loc || !this.useCache) {
20216                 loc = this.getLocation(oTarget);
20217                 this.locationCache[oTarget.id] = loc;
20218
20219             }
20220
20221             if (!loc) {
20222                 return false;
20223             }
20224
20225             oTarget.cursorIsOver = loc.contains( pt );
20226
20227             // DragDrop is using this as a sanity check for the initial mousedown
20228             // in this case we are done.  In POINT mode, if the drag obj has no
20229             // contraints, we are also done. Otherwise we need to evaluate the
20230             // location of the target as related to the actual location of the
20231             // dragged element.
20232             var dc = this.dragCurrent;
20233             if (!dc || !dc.getTargetCoord ||
20234                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20235                 return oTarget.cursorIsOver;
20236             }
20237
20238             oTarget.overlap = null;
20239
20240             // Get the current location of the drag element, this is the
20241             // location of the mouse event less the delta that represents
20242             // where the original mousedown happened on the element.  We
20243             // need to consider constraints and ticks as well.
20244             var pos = dc.getTargetCoord(pt.x, pt.y);
20245
20246             var el = dc.getDragEl();
20247             var curRegion = new Roo.lib.Region( pos.y,
20248                                                    pos.x + el.offsetWidth,
20249                                                    pos.y + el.offsetHeight,
20250                                                    pos.x );
20251
20252             var overlap = curRegion.intersect(loc);
20253
20254             if (overlap) {
20255                 oTarget.overlap = overlap;
20256                 return (intersect) ? true : oTarget.cursorIsOver;
20257             } else {
20258                 return false;
20259             }
20260         },
20261
20262         /**
20263          * unload event handler
20264          * @method _onUnload
20265          * @private
20266          * @static
20267          */
20268         _onUnload: function(e, me) {
20269             Roo.dd.DragDropMgr.unregAll();
20270         },
20271
20272         /**
20273          * Cleans up the drag and drop events and objects.
20274          * @method unregAll
20275          * @private
20276          * @static
20277          */
20278         unregAll: function() {
20279
20280             if (this.dragCurrent) {
20281                 this.stopDrag();
20282                 this.dragCurrent = null;
20283             }
20284
20285             this._execOnAll("unreg", []);
20286
20287             for (i in this.elementCache) {
20288                 delete this.elementCache[i];
20289             }
20290
20291             this.elementCache = {};
20292             this.ids = {};
20293         },
20294
20295         /**
20296          * A cache of DOM elements
20297          * @property elementCache
20298          * @private
20299          * @static
20300          */
20301         elementCache: {},
20302
20303         /**
20304          * Get the wrapper for the DOM element specified
20305          * @method getElWrapper
20306          * @param {String} id the id of the element to get
20307          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20308          * @private
20309          * @deprecated This wrapper isn't that useful
20310          * @static
20311          */
20312         getElWrapper: function(id) {
20313             var oWrapper = this.elementCache[id];
20314             if (!oWrapper || !oWrapper.el) {
20315                 oWrapper = this.elementCache[id] =
20316                     new this.ElementWrapper(Roo.getDom(id));
20317             }
20318             return oWrapper;
20319         },
20320
20321         /**
20322          * Returns the actual DOM element
20323          * @method getElement
20324          * @param {String} id the id of the elment to get
20325          * @return {Object} The element
20326          * @deprecated use Roo.getDom instead
20327          * @static
20328          */
20329         getElement: function(id) {
20330             return Roo.getDom(id);
20331         },
20332
20333         /**
20334          * Returns the style property for the DOM element (i.e.,
20335          * document.getElById(id).style)
20336          * @method getCss
20337          * @param {String} id the id of the elment to get
20338          * @return {Object} The style property of the element
20339          * @deprecated use Roo.getDom instead
20340          * @static
20341          */
20342         getCss: function(id) {
20343             var el = Roo.getDom(id);
20344             return (el) ? el.style : null;
20345         },
20346
20347         /**
20348          * Inner class for cached elements
20349          * @class DragDropMgr.ElementWrapper
20350          * @for DragDropMgr
20351          * @private
20352          * @deprecated
20353          */
20354         ElementWrapper: function(el) {
20355                 /**
20356                  * The element
20357                  * @property el
20358                  */
20359                 this.el = el || null;
20360                 /**
20361                  * The element id
20362                  * @property id
20363                  */
20364                 this.id = this.el && el.id;
20365                 /**
20366                  * A reference to the style property
20367                  * @property css
20368                  */
20369                 this.css = this.el && el.style;
20370             },
20371
20372         /**
20373          * Returns the X position of an html element
20374          * @method getPosX
20375          * @param el the element for which to get the position
20376          * @return {int} the X coordinate
20377          * @for DragDropMgr
20378          * @deprecated use Roo.lib.Dom.getX instead
20379          * @static
20380          */
20381         getPosX: function(el) {
20382             return Roo.lib.Dom.getX(el);
20383         },
20384
20385         /**
20386          * Returns the Y position of an html element
20387          * @method getPosY
20388          * @param el the element for which to get the position
20389          * @return {int} the Y coordinate
20390          * @deprecated use Roo.lib.Dom.getY instead
20391          * @static
20392          */
20393         getPosY: function(el) {
20394             return Roo.lib.Dom.getY(el);
20395         },
20396
20397         /**
20398          * Swap two nodes.  In IE, we use the native method, for others we
20399          * emulate the IE behavior
20400          * @method swapNode
20401          * @param n1 the first node to swap
20402          * @param n2 the other node to swap
20403          * @static
20404          */
20405         swapNode: function(n1, n2) {
20406             if (n1.swapNode) {
20407                 n1.swapNode(n2);
20408             } else {
20409                 var p = n2.parentNode;
20410                 var s = n2.nextSibling;
20411
20412                 if (s == n1) {
20413                     p.insertBefore(n1, n2);
20414                 } else if (n2 == n1.nextSibling) {
20415                     p.insertBefore(n2, n1);
20416                 } else {
20417                     n1.parentNode.replaceChild(n2, n1);
20418                     p.insertBefore(n1, s);
20419                 }
20420             }
20421         },
20422
20423         /**
20424          * Returns the current scroll position
20425          * @method getScroll
20426          * @private
20427          * @static
20428          */
20429         getScroll: function () {
20430             var t, l, dde=document.documentElement, db=document.body;
20431             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20432                 t = dde.scrollTop;
20433                 l = dde.scrollLeft;
20434             } else if (db) {
20435                 t = db.scrollTop;
20436                 l = db.scrollLeft;
20437             } else {
20438
20439             }
20440             return { top: t, left: l };
20441         },
20442
20443         /**
20444          * Returns the specified element style property
20445          * @method getStyle
20446          * @param {HTMLElement} el          the element
20447          * @param {string}      styleProp   the style property
20448          * @return {string} The value of the style property
20449          * @deprecated use Roo.lib.Dom.getStyle
20450          * @static
20451          */
20452         getStyle: function(el, styleProp) {
20453             return Roo.fly(el).getStyle(styleProp);
20454         },
20455
20456         /**
20457          * Gets the scrollTop
20458          * @method getScrollTop
20459          * @return {int} the document's scrollTop
20460          * @static
20461          */
20462         getScrollTop: function () { return this.getScroll().top; },
20463
20464         /**
20465          * Gets the scrollLeft
20466          * @method getScrollLeft
20467          * @return {int} the document's scrollTop
20468          * @static
20469          */
20470         getScrollLeft: function () { return this.getScroll().left; },
20471
20472         /**
20473          * Sets the x/y position of an element to the location of the
20474          * target element.
20475          * @method moveToEl
20476          * @param {HTMLElement} moveEl      The element to move
20477          * @param {HTMLElement} targetEl    The position reference element
20478          * @static
20479          */
20480         moveToEl: function (moveEl, targetEl) {
20481             var aCoord = Roo.lib.Dom.getXY(targetEl);
20482             Roo.lib.Dom.setXY(moveEl, aCoord);
20483         },
20484
20485         /**
20486          * Numeric array sort function
20487          * @method numericSort
20488          * @static
20489          */
20490         numericSort: function(a, b) { return (a - b); },
20491
20492         /**
20493          * Internal counter
20494          * @property _timeoutCount
20495          * @private
20496          * @static
20497          */
20498         _timeoutCount: 0,
20499
20500         /**
20501          * Trying to make the load order less important.  Without this we get
20502          * an error if this file is loaded before the Event Utility.
20503          * @method _addListeners
20504          * @private
20505          * @static
20506          */
20507         _addListeners: function() {
20508             var DDM = Roo.dd.DDM;
20509             if ( Roo.lib.Event && document ) {
20510                 DDM._onLoad();
20511             } else {
20512                 if (DDM._timeoutCount > 2000) {
20513                 } else {
20514                     setTimeout(DDM._addListeners, 10);
20515                     if (document && document.body) {
20516                         DDM._timeoutCount += 1;
20517                     }
20518                 }
20519             }
20520         },
20521
20522         /**
20523          * Recursively searches the immediate parent and all child nodes for
20524          * the handle element in order to determine wheter or not it was
20525          * clicked.
20526          * @method handleWasClicked
20527          * @param node the html element to inspect
20528          * @static
20529          */
20530         handleWasClicked: function(node, id) {
20531             if (this.isHandle(id, node.id)) {
20532                 return true;
20533             } else {
20534                 // check to see if this is a text node child of the one we want
20535                 var p = node.parentNode;
20536
20537                 while (p) {
20538                     if (this.isHandle(id, p.id)) {
20539                         return true;
20540                     } else {
20541                         p = p.parentNode;
20542                     }
20543                 }
20544             }
20545
20546             return false;
20547         }
20548
20549     };
20550
20551 }();
20552
20553 // shorter alias, save a few bytes
20554 Roo.dd.DDM = Roo.dd.DragDropMgr;
20555 Roo.dd.DDM._addListeners();
20556
20557 }/*
20558  * Based on:
20559  * Ext JS Library 1.1.1
20560  * Copyright(c) 2006-2007, Ext JS, LLC.
20561  *
20562  * Originally Released Under LGPL - original licence link has changed is not relivant.
20563  *
20564  * Fork - LGPL
20565  * <script type="text/javascript">
20566  */
20567
20568 /**
20569  * @class Roo.dd.DD
20570  * A DragDrop implementation where the linked element follows the
20571  * mouse cursor during a drag.
20572  * @extends Roo.dd.DragDrop
20573  * @constructor
20574  * @param {String} id the id of the linked element
20575  * @param {String} sGroup the group of related DragDrop items
20576  * @param {object} config an object containing configurable attributes
20577  *                Valid properties for DD:
20578  *                    scroll
20579  */
20580 Roo.dd.DD = function(id, sGroup, config) {
20581     if (id) {
20582         this.init(id, sGroup, config);
20583     }
20584 };
20585
20586 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20587
20588     /**
20589      * When set to true, the utility automatically tries to scroll the browser
20590      * window wehn a drag and drop element is dragged near the viewport boundary.
20591      * Defaults to true.
20592      * @property scroll
20593      * @type boolean
20594      */
20595     scroll: true,
20596
20597     /**
20598      * Sets the pointer offset to the distance between the linked element's top
20599      * left corner and the location the element was clicked
20600      * @method autoOffset
20601      * @param {int} iPageX the X coordinate of the click
20602      * @param {int} iPageY the Y coordinate of the click
20603      */
20604     autoOffset: function(iPageX, iPageY) {
20605         var x = iPageX - this.startPageX;
20606         var y = iPageY - this.startPageY;
20607         this.setDelta(x, y);
20608     },
20609
20610     /**
20611      * Sets the pointer offset.  You can call this directly to force the
20612      * offset to be in a particular location (e.g., pass in 0,0 to set it
20613      * to the center of the object)
20614      * @method setDelta
20615      * @param {int} iDeltaX the distance from the left
20616      * @param {int} iDeltaY the distance from the top
20617      */
20618     setDelta: function(iDeltaX, iDeltaY) {
20619         this.deltaX = iDeltaX;
20620         this.deltaY = iDeltaY;
20621     },
20622
20623     /**
20624      * Sets the drag element to the location of the mousedown or click event,
20625      * maintaining the cursor location relative to the location on the element
20626      * that was clicked.  Override this if you want to place the element in a
20627      * location other than where the cursor is.
20628      * @method setDragElPos
20629      * @param {int} iPageX the X coordinate of the mousedown or drag event
20630      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20631      */
20632     setDragElPos: function(iPageX, iPageY) {
20633         // the first time we do this, we are going to check to make sure
20634         // the element has css positioning
20635
20636         var el = this.getDragEl();
20637         this.alignElWithMouse(el, iPageX, iPageY);
20638     },
20639
20640     /**
20641      * Sets the element to the location of the mousedown or click event,
20642      * maintaining the cursor location relative to the location on the element
20643      * that was clicked.  Override this if you want to place the element in a
20644      * location other than where the cursor is.
20645      * @method alignElWithMouse
20646      * @param {HTMLElement} el the element to move
20647      * @param {int} iPageX the X coordinate of the mousedown or drag event
20648      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20649      */
20650     alignElWithMouse: function(el, iPageX, iPageY) {
20651         var oCoord = this.getTargetCoord(iPageX, iPageY);
20652         var fly = el.dom ? el : Roo.fly(el);
20653         if (!this.deltaSetXY) {
20654             var aCoord = [oCoord.x, oCoord.y];
20655             fly.setXY(aCoord);
20656             var newLeft = fly.getLeft(true);
20657             var newTop  = fly.getTop(true);
20658             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20659         } else {
20660             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20661         }
20662
20663         this.cachePosition(oCoord.x, oCoord.y);
20664         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20665         return oCoord;
20666     },
20667
20668     /**
20669      * Saves the most recent position so that we can reset the constraints and
20670      * tick marks on-demand.  We need to know this so that we can calculate the
20671      * number of pixels the element is offset from its original position.
20672      * @method cachePosition
20673      * @param iPageX the current x position (optional, this just makes it so we
20674      * don't have to look it up again)
20675      * @param iPageY the current y position (optional, this just makes it so we
20676      * don't have to look it up again)
20677      */
20678     cachePosition: function(iPageX, iPageY) {
20679         if (iPageX) {
20680             this.lastPageX = iPageX;
20681             this.lastPageY = iPageY;
20682         } else {
20683             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20684             this.lastPageX = aCoord[0];
20685             this.lastPageY = aCoord[1];
20686         }
20687     },
20688
20689     /**
20690      * Auto-scroll the window if the dragged object has been moved beyond the
20691      * visible window boundary.
20692      * @method autoScroll
20693      * @param {int} x the drag element's x position
20694      * @param {int} y the drag element's y position
20695      * @param {int} h the height of the drag element
20696      * @param {int} w the width of the drag element
20697      * @private
20698      */
20699     autoScroll: function(x, y, h, w) {
20700
20701         if (this.scroll) {
20702             // The client height
20703             var clientH = Roo.lib.Dom.getViewWidth();
20704
20705             // The client width
20706             var clientW = Roo.lib.Dom.getViewHeight();
20707
20708             // The amt scrolled down
20709             var st = this.DDM.getScrollTop();
20710
20711             // The amt scrolled right
20712             var sl = this.DDM.getScrollLeft();
20713
20714             // Location of the bottom of the element
20715             var bot = h + y;
20716
20717             // Location of the right of the element
20718             var right = w + x;
20719
20720             // The distance from the cursor to the bottom of the visible area,
20721             // adjusted so that we don't scroll if the cursor is beyond the
20722             // element drag constraints
20723             var toBot = (clientH + st - y - this.deltaY);
20724
20725             // The distance from the cursor to the right of the visible area
20726             var toRight = (clientW + sl - x - this.deltaX);
20727
20728
20729             // How close to the edge the cursor must be before we scroll
20730             // var thresh = (document.all) ? 100 : 40;
20731             var thresh = 40;
20732
20733             // How many pixels to scroll per autoscroll op.  This helps to reduce
20734             // clunky scrolling. IE is more sensitive about this ... it needs this
20735             // value to be higher.
20736             var scrAmt = (document.all) ? 80 : 30;
20737
20738             // Scroll down if we are near the bottom of the visible page and the
20739             // obj extends below the crease
20740             if ( bot > clientH && toBot < thresh ) {
20741                 window.scrollTo(sl, st + scrAmt);
20742             }
20743
20744             // Scroll up if the window is scrolled down and the top of the object
20745             // goes above the top border
20746             if ( y < st && st > 0 && y - st < thresh ) {
20747                 window.scrollTo(sl, st - scrAmt);
20748             }
20749
20750             // Scroll right if the obj is beyond the right border and the cursor is
20751             // near the border.
20752             if ( right > clientW && toRight < thresh ) {
20753                 window.scrollTo(sl + scrAmt, st);
20754             }
20755
20756             // Scroll left if the window has been scrolled to the right and the obj
20757             // extends past the left border
20758             if ( x < sl && sl > 0 && x - sl < thresh ) {
20759                 window.scrollTo(sl - scrAmt, st);
20760             }
20761         }
20762     },
20763
20764     /**
20765      * Finds the location the element should be placed if we want to move
20766      * it to where the mouse location less the click offset would place us.
20767      * @method getTargetCoord
20768      * @param {int} iPageX the X coordinate of the click
20769      * @param {int} iPageY the Y coordinate of the click
20770      * @return an object that contains the coordinates (Object.x and Object.y)
20771      * @private
20772      */
20773     getTargetCoord: function(iPageX, iPageY) {
20774
20775
20776         var x = iPageX - this.deltaX;
20777         var y = iPageY - this.deltaY;
20778
20779         if (this.constrainX) {
20780             if (x < this.minX) { x = this.minX; }
20781             if (x > this.maxX) { x = this.maxX; }
20782         }
20783
20784         if (this.constrainY) {
20785             if (y < this.minY) { y = this.minY; }
20786             if (y > this.maxY) { y = this.maxY; }
20787         }
20788
20789         x = this.getTick(x, this.xTicks);
20790         y = this.getTick(y, this.yTicks);
20791
20792
20793         return {x:x, y:y};
20794     },
20795
20796     /*
20797      * Sets up config options specific to this class. Overrides
20798      * Roo.dd.DragDrop, but all versions of this method through the
20799      * inheritance chain are called
20800      */
20801     applyConfig: function() {
20802         Roo.dd.DD.superclass.applyConfig.call(this);
20803         this.scroll = (this.config.scroll !== false);
20804     },
20805
20806     /*
20807      * Event that fires prior to the onMouseDown event.  Overrides
20808      * Roo.dd.DragDrop.
20809      */
20810     b4MouseDown: function(e) {
20811         // this.resetConstraints();
20812         this.autoOffset(e.getPageX(),
20813                             e.getPageY());
20814     },
20815
20816     /*
20817      * Event that fires prior to the onDrag event.  Overrides
20818      * Roo.dd.DragDrop.
20819      */
20820     b4Drag: function(e) {
20821         this.setDragElPos(e.getPageX(),
20822                             e.getPageY());
20823     },
20824
20825     toString: function() {
20826         return ("DD " + this.id);
20827     }
20828
20829     //////////////////////////////////////////////////////////////////////////
20830     // Debugging ygDragDrop events that can be overridden
20831     //////////////////////////////////////////////////////////////////////////
20832     /*
20833     startDrag: function(x, y) {
20834     },
20835
20836     onDrag: function(e) {
20837     },
20838
20839     onDragEnter: function(e, id) {
20840     },
20841
20842     onDragOver: function(e, id) {
20843     },
20844
20845     onDragOut: function(e, id) {
20846     },
20847
20848     onDragDrop: function(e, id) {
20849     },
20850
20851     endDrag: function(e) {
20852     }
20853
20854     */
20855
20856 });/*
20857  * Based on:
20858  * Ext JS Library 1.1.1
20859  * Copyright(c) 2006-2007, Ext JS, LLC.
20860  *
20861  * Originally Released Under LGPL - original licence link has changed is not relivant.
20862  *
20863  * Fork - LGPL
20864  * <script type="text/javascript">
20865  */
20866
20867 /**
20868  * @class Roo.dd.DDProxy
20869  * A DragDrop implementation that inserts an empty, bordered div into
20870  * the document that follows the cursor during drag operations.  At the time of
20871  * the click, the frame div is resized to the dimensions of the linked html
20872  * element, and moved to the exact location of the linked element.
20873  *
20874  * References to the "frame" element refer to the single proxy element that
20875  * was created to be dragged in place of all DDProxy elements on the
20876  * page.
20877  *
20878  * @extends Roo.dd.DD
20879  * @constructor
20880  * @param {String} id the id of the linked html element
20881  * @param {String} sGroup the group of related DragDrop objects
20882  * @param {object} config an object containing configurable attributes
20883  *                Valid properties for DDProxy in addition to those in DragDrop:
20884  *                   resizeFrame, centerFrame, dragElId
20885  */
20886 Roo.dd.DDProxy = function(id, sGroup, config) {
20887     if (id) {
20888         this.init(id, sGroup, config);
20889         this.initFrame();
20890     }
20891 };
20892
20893 /**
20894  * The default drag frame div id
20895  * @property Roo.dd.DDProxy.dragElId
20896  * @type String
20897  * @static
20898  */
20899 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20900
20901 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20902
20903     /**
20904      * By default we resize the drag frame to be the same size as the element
20905      * we want to drag (this is to get the frame effect).  We can turn it off
20906      * if we want a different behavior.
20907      * @property resizeFrame
20908      * @type boolean
20909      */
20910     resizeFrame: true,
20911
20912     /**
20913      * By default the frame is positioned exactly where the drag element is, so
20914      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20915      * you do not have constraints on the obj is to have the drag frame centered
20916      * around the cursor.  Set centerFrame to true for this effect.
20917      * @property centerFrame
20918      * @type boolean
20919      */
20920     centerFrame: false,
20921
20922     /**
20923      * Creates the proxy element if it does not yet exist
20924      * @method createFrame
20925      */
20926     createFrame: function() {
20927         var self = this;
20928         var body = document.body;
20929
20930         if (!body || !body.firstChild) {
20931             setTimeout( function() { self.createFrame(); }, 50 );
20932             return;
20933         }
20934
20935         var div = this.getDragEl();
20936
20937         if (!div) {
20938             div    = document.createElement("div");
20939             div.id = this.dragElId;
20940             var s  = div.style;
20941
20942             s.position   = "absolute";
20943             s.visibility = "hidden";
20944             s.cursor     = "move";
20945             s.border     = "2px solid #aaa";
20946             s.zIndex     = 999;
20947
20948             // appendChild can blow up IE if invoked prior to the window load event
20949             // while rendering a table.  It is possible there are other scenarios
20950             // that would cause this to happen as well.
20951             body.insertBefore(div, body.firstChild);
20952         }
20953     },
20954
20955     /**
20956      * Initialization for the drag frame element.  Must be called in the
20957      * constructor of all subclasses
20958      * @method initFrame
20959      */
20960     initFrame: function() {
20961         this.createFrame();
20962     },
20963
20964     applyConfig: function() {
20965         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20966
20967         this.resizeFrame = (this.config.resizeFrame !== false);
20968         this.centerFrame = (this.config.centerFrame);
20969         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20970     },
20971
20972     /**
20973      * Resizes the drag frame to the dimensions of the clicked object, positions
20974      * it over the object, and finally displays it
20975      * @method showFrame
20976      * @param {int} iPageX X click position
20977      * @param {int} iPageY Y click position
20978      * @private
20979      */
20980     showFrame: function(iPageX, iPageY) {
20981         var el = this.getEl();
20982         var dragEl = this.getDragEl();
20983         var s = dragEl.style;
20984
20985         this._resizeProxy();
20986
20987         if (this.centerFrame) {
20988             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20989                            Math.round(parseInt(s.height, 10)/2) );
20990         }
20991
20992         this.setDragElPos(iPageX, iPageY);
20993
20994         Roo.fly(dragEl).show();
20995     },
20996
20997     /**
20998      * The proxy is automatically resized to the dimensions of the linked
20999      * element when a drag is initiated, unless resizeFrame is set to false
21000      * @method _resizeProxy
21001      * @private
21002      */
21003     _resizeProxy: function() {
21004         if (this.resizeFrame) {
21005             var el = this.getEl();
21006             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21007         }
21008     },
21009
21010     // overrides Roo.dd.DragDrop
21011     b4MouseDown: function(e) {
21012         var x = e.getPageX();
21013         var y = e.getPageY();
21014         this.autoOffset(x, y);
21015         this.setDragElPos(x, y);
21016     },
21017
21018     // overrides Roo.dd.DragDrop
21019     b4StartDrag: function(x, y) {
21020         // show the drag frame
21021         this.showFrame(x, y);
21022     },
21023
21024     // overrides Roo.dd.DragDrop
21025     b4EndDrag: function(e) {
21026         Roo.fly(this.getDragEl()).hide();
21027     },
21028
21029     // overrides Roo.dd.DragDrop
21030     // By default we try to move the element to the last location of the frame.
21031     // This is so that the default behavior mirrors that of Roo.dd.DD.
21032     endDrag: function(e) {
21033
21034         var lel = this.getEl();
21035         var del = this.getDragEl();
21036
21037         // Show the drag frame briefly so we can get its position
21038         del.style.visibility = "";
21039
21040         this.beforeMove();
21041         // Hide the linked element before the move to get around a Safari
21042         // rendering bug.
21043         lel.style.visibility = "hidden";
21044         Roo.dd.DDM.moveToEl(lel, del);
21045         del.style.visibility = "hidden";
21046         lel.style.visibility = "";
21047
21048         this.afterDrag();
21049     },
21050
21051     beforeMove : function(){
21052
21053     },
21054
21055     afterDrag : function(){
21056
21057     },
21058
21059     toString: function() {
21060         return ("DDProxy " + this.id);
21061     }
21062
21063 });
21064 /*
21065  * Based on:
21066  * Ext JS Library 1.1.1
21067  * Copyright(c) 2006-2007, Ext JS, LLC.
21068  *
21069  * Originally Released Under LGPL - original licence link has changed is not relivant.
21070  *
21071  * Fork - LGPL
21072  * <script type="text/javascript">
21073  */
21074
21075  /**
21076  * @class Roo.dd.DDTarget
21077  * A DragDrop implementation that does not move, but can be a drop
21078  * target.  You would get the same result by simply omitting implementation
21079  * for the event callbacks, but this way we reduce the processing cost of the
21080  * event listener and the callbacks.
21081  * @extends Roo.dd.DragDrop
21082  * @constructor
21083  * @param {String} id the id of the element that is a drop target
21084  * @param {String} sGroup the group of related DragDrop objects
21085  * @param {object} config an object containing configurable attributes
21086  *                 Valid properties for DDTarget in addition to those in
21087  *                 DragDrop:
21088  *                    none
21089  */
21090 Roo.dd.DDTarget = function(id, sGroup, config) {
21091     if (id) {
21092         this.initTarget(id, sGroup, config);
21093     }
21094     if (config.listeners || config.events) { 
21095        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
21096             listeners : config.listeners || {}, 
21097             events : config.events || {} 
21098         });    
21099     }
21100 };
21101
21102 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21103 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21104     toString: function() {
21105         return ("DDTarget " + this.id);
21106     }
21107 });
21108 /*
21109  * Based on:
21110  * Ext JS Library 1.1.1
21111  * Copyright(c) 2006-2007, Ext JS, LLC.
21112  *
21113  * Originally Released Under LGPL - original licence link has changed is not relivant.
21114  *
21115  * Fork - LGPL
21116  * <script type="text/javascript">
21117  */
21118  
21119
21120 /**
21121  * @class Roo.dd.ScrollManager
21122  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21123  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21124  * @singleton
21125  */
21126 Roo.dd.ScrollManager = function(){
21127     var ddm = Roo.dd.DragDropMgr;
21128     var els = {};
21129     var dragEl = null;
21130     var proc = {};
21131     
21132     
21133     
21134     var onStop = function(e){
21135         dragEl = null;
21136         clearProc();
21137     };
21138     
21139     var triggerRefresh = function(){
21140         if(ddm.dragCurrent){
21141              ddm.refreshCache(ddm.dragCurrent.groups);
21142         }
21143     };
21144     
21145     var doScroll = function(){
21146         if(ddm.dragCurrent){
21147             var dds = Roo.dd.ScrollManager;
21148             if(!dds.animate){
21149                 if(proc.el.scroll(proc.dir, dds.increment)){
21150                     triggerRefresh();
21151                 }
21152             }else{
21153                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21154             }
21155         }
21156     };
21157     
21158     var clearProc = function(){
21159         if(proc.id){
21160             clearInterval(proc.id);
21161         }
21162         proc.id = 0;
21163         proc.el = null;
21164         proc.dir = "";
21165     };
21166     
21167     var startProc = function(el, dir){
21168          Roo.log('scroll startproc');
21169         clearProc();
21170         proc.el = el;
21171         proc.dir = dir;
21172         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21173     };
21174     
21175     var onFire = function(e, isDrop){
21176        
21177         if(isDrop || !ddm.dragCurrent){ return; }
21178         var dds = Roo.dd.ScrollManager;
21179         if(!dragEl || dragEl != ddm.dragCurrent){
21180             dragEl = ddm.dragCurrent;
21181             // refresh regions on drag start
21182             dds.refreshCache();
21183         }
21184         
21185         var xy = Roo.lib.Event.getXY(e);
21186         var pt = new Roo.lib.Point(xy[0], xy[1]);
21187         for(var id in els){
21188             var el = els[id], r = el._region;
21189             if(r && r.contains(pt) && el.isScrollable()){
21190                 if(r.bottom - pt.y <= dds.thresh){
21191                     if(proc.el != el){
21192                         startProc(el, "down");
21193                     }
21194                     return;
21195                 }else if(r.right - pt.x <= dds.thresh){
21196                     if(proc.el != el){
21197                         startProc(el, "left");
21198                     }
21199                     return;
21200                 }else if(pt.y - r.top <= dds.thresh){
21201                     if(proc.el != el){
21202                         startProc(el, "up");
21203                     }
21204                     return;
21205                 }else if(pt.x - r.left <= dds.thresh){
21206                     if(proc.el != el){
21207                         startProc(el, "right");
21208                     }
21209                     return;
21210                 }
21211             }
21212         }
21213         clearProc();
21214     };
21215     
21216     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21217     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21218     
21219     return {
21220         /**
21221          * Registers new overflow element(s) to auto scroll
21222          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21223          */
21224         register : function(el){
21225             if(el instanceof Array){
21226                 for(var i = 0, len = el.length; i < len; i++) {
21227                         this.register(el[i]);
21228                 }
21229             }else{
21230                 el = Roo.get(el);
21231                 els[el.id] = el;
21232             }
21233             Roo.dd.ScrollManager.els = els;
21234         },
21235         
21236         /**
21237          * Unregisters overflow element(s) so they are no longer scrolled
21238          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21239          */
21240         unregister : function(el){
21241             if(el instanceof Array){
21242                 for(var i = 0, len = el.length; i < len; i++) {
21243                         this.unregister(el[i]);
21244                 }
21245             }else{
21246                 el = Roo.get(el);
21247                 delete els[el.id];
21248             }
21249         },
21250         
21251         /**
21252          * The number of pixels from the edge of a container the pointer needs to be to 
21253          * trigger scrolling (defaults to 25)
21254          * @type Number
21255          */
21256         thresh : 25,
21257         
21258         /**
21259          * The number of pixels to scroll in each scroll increment (defaults to 50)
21260          * @type Number
21261          */
21262         increment : 100,
21263         
21264         /**
21265          * The frequency of scrolls in milliseconds (defaults to 500)
21266          * @type Number
21267          */
21268         frequency : 500,
21269         
21270         /**
21271          * True to animate the scroll (defaults to true)
21272          * @type Boolean
21273          */
21274         animate: true,
21275         
21276         /**
21277          * The animation duration in seconds - 
21278          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21279          * @type Number
21280          */
21281         animDuration: .4,
21282         
21283         /**
21284          * Manually trigger a cache refresh.
21285          */
21286         refreshCache : function(){
21287             for(var id in els){
21288                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21289                     els[id]._region = els[id].getRegion();
21290                 }
21291             }
21292         }
21293     };
21294 }();/*
21295  * Based on:
21296  * Ext JS Library 1.1.1
21297  * Copyright(c) 2006-2007, Ext JS, LLC.
21298  *
21299  * Originally Released Under LGPL - original licence link has changed is not relivant.
21300  *
21301  * Fork - LGPL
21302  * <script type="text/javascript">
21303  */
21304  
21305
21306 /**
21307  * @class Roo.dd.Registry
21308  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21309  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21310  * @singleton
21311  */
21312 Roo.dd.Registry = function(){
21313     var elements = {}; 
21314     var handles = {}; 
21315     var autoIdSeed = 0;
21316
21317     var getId = function(el, autogen){
21318         if(typeof el == "string"){
21319             return el;
21320         }
21321         var id = el.id;
21322         if(!id && autogen !== false){
21323             id = "roodd-" + (++autoIdSeed);
21324             el.id = id;
21325         }
21326         return id;
21327     };
21328     
21329     return {
21330     /**
21331      * Register a drag drop element
21332      * @param {String|HTMLElement} element The id or DOM node to register
21333      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21334      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21335      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21336      * populated in the data object (if applicable):
21337      * <pre>
21338 Value      Description<br />
21339 ---------  ------------------------------------------<br />
21340 handles    Array of DOM nodes that trigger dragging<br />
21341            for the element being registered<br />
21342 isHandle   True if the element passed in triggers<br />
21343            dragging itself, else false
21344 </pre>
21345      */
21346         register : function(el, data){
21347             data = data || {};
21348             if(typeof el == "string"){
21349                 el = document.getElementById(el);
21350             }
21351             data.ddel = el;
21352             elements[getId(el)] = data;
21353             if(data.isHandle !== false){
21354                 handles[data.ddel.id] = data;
21355             }
21356             if(data.handles){
21357                 var hs = data.handles;
21358                 for(var i = 0, len = hs.length; i < len; i++){
21359                         handles[getId(hs[i])] = data;
21360                 }
21361             }
21362         },
21363
21364     /**
21365      * Unregister a drag drop element
21366      * @param {String|HTMLElement}  element The id or DOM node to unregister
21367      */
21368         unregister : function(el){
21369             var id = getId(el, false);
21370             var data = elements[id];
21371             if(data){
21372                 delete elements[id];
21373                 if(data.handles){
21374                     var hs = data.handles;
21375                     for(var i = 0, len = hs.length; i < len; i++){
21376                         delete handles[getId(hs[i], false)];
21377                     }
21378                 }
21379             }
21380         },
21381
21382     /**
21383      * Returns the handle registered for a DOM Node by id
21384      * @param {String|HTMLElement} id The DOM node or id to look up
21385      * @return {Object} handle The custom handle data
21386      */
21387         getHandle : function(id){
21388             if(typeof id != "string"){ // must be element?
21389                 id = id.id;
21390             }
21391             return handles[id];
21392         },
21393
21394     /**
21395      * Returns the handle that is registered for the DOM node that is the target of the event
21396      * @param {Event} e The event
21397      * @return {Object} handle The custom handle data
21398      */
21399         getHandleFromEvent : function(e){
21400             var t = Roo.lib.Event.getTarget(e);
21401             return t ? handles[t.id] : null;
21402         },
21403
21404     /**
21405      * Returns a custom data object that is registered for a DOM node by id
21406      * @param {String|HTMLElement} id The DOM node or id to look up
21407      * @return {Object} data The custom data
21408      */
21409         getTarget : function(id){
21410             if(typeof id != "string"){ // must be element?
21411                 id = id.id;
21412             }
21413             return elements[id];
21414         },
21415
21416     /**
21417      * Returns a custom data object that is registered for the DOM node that is the target of the event
21418      * @param {Event} e The event
21419      * @return {Object} data The custom data
21420      */
21421         getTargetFromEvent : function(e){
21422             var t = Roo.lib.Event.getTarget(e);
21423             return t ? elements[t.id] || handles[t.id] : null;
21424         }
21425     };
21426 }();/*
21427  * Based on:
21428  * Ext JS Library 1.1.1
21429  * Copyright(c) 2006-2007, Ext JS, LLC.
21430  *
21431  * Originally Released Under LGPL - original licence link has changed is not relivant.
21432  *
21433  * Fork - LGPL
21434  * <script type="text/javascript">
21435  */
21436  
21437
21438 /**
21439  * @class Roo.dd.StatusProxy
21440  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21441  * default drag proxy used by all Roo.dd components.
21442  * @constructor
21443  * @param {Object} config
21444  */
21445 Roo.dd.StatusProxy = function(config){
21446     Roo.apply(this, config);
21447     this.id = this.id || Roo.id();
21448     this.el = new Roo.Layer({
21449         dh: {
21450             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21451                 {tag: "div", cls: "x-dd-drop-icon"},
21452                 {tag: "div", cls: "x-dd-drag-ghost"}
21453             ]
21454         }, 
21455         shadow: !config || config.shadow !== false
21456     });
21457     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21458     this.dropStatus = this.dropNotAllowed;
21459 };
21460
21461 Roo.dd.StatusProxy.prototype = {
21462     /**
21463      * @cfg {String} dropAllowed
21464      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21465      */
21466     dropAllowed : "x-dd-drop-ok",
21467     /**
21468      * @cfg {String} dropNotAllowed
21469      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21470      */
21471     dropNotAllowed : "x-dd-drop-nodrop",
21472
21473     /**
21474      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21475      * over the current target element.
21476      * @param {String} cssClass The css class for the new drop status indicator image
21477      */
21478     setStatus : function(cssClass){
21479         cssClass = cssClass || this.dropNotAllowed;
21480         if(this.dropStatus != cssClass){
21481             this.el.replaceClass(this.dropStatus, cssClass);
21482             this.dropStatus = cssClass;
21483         }
21484     },
21485
21486     /**
21487      * Resets the status indicator to the default dropNotAllowed value
21488      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21489      */
21490     reset : function(clearGhost){
21491         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21492         this.dropStatus = this.dropNotAllowed;
21493         if(clearGhost){
21494             this.ghost.update("");
21495         }
21496     },
21497
21498     /**
21499      * Updates the contents of the ghost element
21500      * @param {String} html The html that will replace the current innerHTML of the ghost element
21501      */
21502     update : function(html){
21503         if(typeof html == "string"){
21504             this.ghost.update(html);
21505         }else{
21506             this.ghost.update("");
21507             html.style.margin = "0";
21508             this.ghost.dom.appendChild(html);
21509         }
21510         // ensure float = none set?? cant remember why though.
21511         var el = this.ghost.dom.firstChild;
21512                 if(el){
21513                         Roo.fly(el).setStyle('float', 'none');
21514                 }
21515     },
21516     
21517     /**
21518      * Returns the underlying proxy {@link Roo.Layer}
21519      * @return {Roo.Layer} el
21520     */
21521     getEl : function(){
21522         return this.el;
21523     },
21524
21525     /**
21526      * Returns the ghost element
21527      * @return {Roo.Element} el
21528      */
21529     getGhost : function(){
21530         return this.ghost;
21531     },
21532
21533     /**
21534      * Hides the proxy
21535      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21536      */
21537     hide : function(clear){
21538         this.el.hide();
21539         if(clear){
21540             this.reset(true);
21541         }
21542     },
21543
21544     /**
21545      * Stops the repair animation if it's currently running
21546      */
21547     stop : function(){
21548         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21549             this.anim.stop();
21550         }
21551     },
21552
21553     /**
21554      * Displays this proxy
21555      */
21556     show : function(){
21557         this.el.show();
21558     },
21559
21560     /**
21561      * Force the Layer to sync its shadow and shim positions to the element
21562      */
21563     sync : function(){
21564         this.el.sync();
21565     },
21566
21567     /**
21568      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21569      * invalid drop operation by the item being dragged.
21570      * @param {Array} xy The XY position of the element ([x, y])
21571      * @param {Function} callback The function to call after the repair is complete
21572      * @param {Object} scope The scope in which to execute the callback
21573      */
21574     repair : function(xy, callback, scope){
21575         this.callback = callback;
21576         this.scope = scope;
21577         if(xy && this.animRepair !== false){
21578             this.el.addClass("x-dd-drag-repair");
21579             this.el.hideUnders(true);
21580             this.anim = this.el.shift({
21581                 duration: this.repairDuration || .5,
21582                 easing: 'easeOut',
21583                 xy: xy,
21584                 stopFx: true,
21585                 callback: this.afterRepair,
21586                 scope: this
21587             });
21588         }else{
21589             this.afterRepair();
21590         }
21591     },
21592
21593     // private
21594     afterRepair : function(){
21595         this.hide(true);
21596         if(typeof this.callback == "function"){
21597             this.callback.call(this.scope || this);
21598         }
21599         this.callback = null;
21600         this.scope = null;
21601     }
21602 };/*
21603  * Based on:
21604  * Ext JS Library 1.1.1
21605  * Copyright(c) 2006-2007, Ext JS, LLC.
21606  *
21607  * Originally Released Under LGPL - original licence link has changed is not relivant.
21608  *
21609  * Fork - LGPL
21610  * <script type="text/javascript">
21611  */
21612
21613 /**
21614  * @class Roo.dd.DragSource
21615  * @extends Roo.dd.DDProxy
21616  * A simple class that provides the basic implementation needed to make any element draggable.
21617  * @constructor
21618  * @param {String/HTMLElement/Element} el The container element
21619  * @param {Object} config
21620  */
21621 Roo.dd.DragSource = function(el, config){
21622     this.el = Roo.get(el);
21623     this.dragData = {};
21624     
21625     Roo.apply(this, config);
21626     
21627     if(!this.proxy){
21628         this.proxy = new Roo.dd.StatusProxy();
21629     }
21630
21631     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21632           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21633     
21634     this.dragging = false;
21635 };
21636
21637 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21638     /**
21639      * @cfg {String} dropAllowed
21640      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21641      */
21642     dropAllowed : "x-dd-drop-ok",
21643     /**
21644      * @cfg {String} dropNotAllowed
21645      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21646      */
21647     dropNotAllowed : "x-dd-drop-nodrop",
21648
21649     /**
21650      * Returns the data object associated with this drag source
21651      * @return {Object} data An object containing arbitrary data
21652      */
21653     getDragData : function(e){
21654         return this.dragData;
21655     },
21656
21657     // private
21658     onDragEnter : function(e, id){
21659         var target = Roo.dd.DragDropMgr.getDDById(id);
21660         this.cachedTarget = target;
21661         if(this.beforeDragEnter(target, e, id) !== false){
21662             if(target.isNotifyTarget){
21663                 var status = target.notifyEnter(this, e, this.dragData);
21664                 this.proxy.setStatus(status);
21665             }else{
21666                 this.proxy.setStatus(this.dropAllowed);
21667             }
21668             
21669             if(this.afterDragEnter){
21670                 /**
21671                  * An empty function by default, but provided so that you can perform a custom action
21672                  * when the dragged item enters the drop target by providing an implementation.
21673                  * @param {Roo.dd.DragDrop} target The drop target
21674                  * @param {Event} e The event object
21675                  * @param {String} id The id of the dragged element
21676                  * @method afterDragEnter
21677                  */
21678                 this.afterDragEnter(target, e, id);
21679             }
21680         }
21681     },
21682
21683     /**
21684      * An empty function by default, but provided so that you can perform a custom action
21685      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21686      * @param {Roo.dd.DragDrop} target The drop target
21687      * @param {Event} e The event object
21688      * @param {String} id The id of the dragged element
21689      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21690      */
21691     beforeDragEnter : function(target, e, id){
21692         return true;
21693     },
21694
21695     // private
21696     alignElWithMouse: function() {
21697         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21698         this.proxy.sync();
21699     },
21700
21701     // private
21702     onDragOver : function(e, id){
21703         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21704         if(this.beforeDragOver(target, e, id) !== false){
21705             if(target.isNotifyTarget){
21706                 var status = target.notifyOver(this, e, this.dragData);
21707                 this.proxy.setStatus(status);
21708             }
21709
21710             if(this.afterDragOver){
21711                 /**
21712                  * An empty function by default, but provided so that you can perform a custom action
21713                  * while the dragged item is over the drop target by providing an implementation.
21714                  * @param {Roo.dd.DragDrop} target The drop target
21715                  * @param {Event} e The event object
21716                  * @param {String} id The id of the dragged element
21717                  * @method afterDragOver
21718                  */
21719                 this.afterDragOver(target, e, id);
21720             }
21721         }
21722     },
21723
21724     /**
21725      * An empty function by default, but provided so that you can perform a custom action
21726      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21727      * @param {Roo.dd.DragDrop} target The drop target
21728      * @param {Event} e The event object
21729      * @param {String} id The id of the dragged element
21730      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21731      */
21732     beforeDragOver : function(target, e, id){
21733         return true;
21734     },
21735
21736     // private
21737     onDragOut : function(e, id){
21738         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21739         if(this.beforeDragOut(target, e, id) !== false){
21740             if(target.isNotifyTarget){
21741                 target.notifyOut(this, e, this.dragData);
21742             }
21743             this.proxy.reset();
21744             if(this.afterDragOut){
21745                 /**
21746                  * An empty function by default, but provided so that you can perform a custom action
21747                  * after the dragged item is dragged out of the target without dropping.
21748                  * @param {Roo.dd.DragDrop} target The drop target
21749                  * @param {Event} e The event object
21750                  * @param {String} id The id of the dragged element
21751                  * @method afterDragOut
21752                  */
21753                 this.afterDragOut(target, e, id);
21754             }
21755         }
21756         this.cachedTarget = null;
21757     },
21758
21759     /**
21760      * An empty function by default, but provided so that you can perform a custom action before the dragged
21761      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21762      * @param {Roo.dd.DragDrop} target The drop target
21763      * @param {Event} e The event object
21764      * @param {String} id The id of the dragged element
21765      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21766      */
21767     beforeDragOut : function(target, e, id){
21768         return true;
21769     },
21770     
21771     // private
21772     onDragDrop : function(e, id){
21773         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21774         if(this.beforeDragDrop(target, e, id) !== false){
21775             if(target.isNotifyTarget){
21776                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21777                     this.onValidDrop(target, e, id);
21778                 }else{
21779                     this.onInvalidDrop(target, e, id);
21780                 }
21781             }else{
21782                 this.onValidDrop(target, e, id);
21783             }
21784             
21785             if(this.afterDragDrop){
21786                 /**
21787                  * An empty function by default, but provided so that you can perform a custom action
21788                  * after a valid drag drop has occurred by providing an implementation.
21789                  * @param {Roo.dd.DragDrop} target The drop target
21790                  * @param {Event} e The event object
21791                  * @param {String} id The id of the dropped element
21792                  * @method afterDragDrop
21793                  */
21794                 this.afterDragDrop(target, e, id);
21795             }
21796         }
21797         delete this.cachedTarget;
21798     },
21799
21800     /**
21801      * An empty function by default, but provided so that you can perform a custom action before the dragged
21802      * item is dropped onto the target and optionally cancel the onDragDrop.
21803      * @param {Roo.dd.DragDrop} target The drop target
21804      * @param {Event} e The event object
21805      * @param {String} id The id of the dragged element
21806      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21807      */
21808     beforeDragDrop : function(target, e, id){
21809         return true;
21810     },
21811
21812     // private
21813     onValidDrop : function(target, e, id){
21814         this.hideProxy();
21815         if(this.afterValidDrop){
21816             /**
21817              * An empty function by default, but provided so that you can perform a custom action
21818              * after a valid drop has occurred by providing an implementation.
21819              * @param {Object} target The target DD 
21820              * @param {Event} e The event object
21821              * @param {String} id The id of the dropped element
21822              * @method afterInvalidDrop
21823              */
21824             this.afterValidDrop(target, e, id);
21825         }
21826     },
21827
21828     // private
21829     getRepairXY : function(e, data){
21830         return this.el.getXY();  
21831     },
21832
21833     // private
21834     onInvalidDrop : function(target, e, id){
21835         this.beforeInvalidDrop(target, e, id);
21836         if(this.cachedTarget){
21837             if(this.cachedTarget.isNotifyTarget){
21838                 this.cachedTarget.notifyOut(this, e, this.dragData);
21839             }
21840             this.cacheTarget = null;
21841         }
21842         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21843
21844         if(this.afterInvalidDrop){
21845             /**
21846              * An empty function by default, but provided so that you can perform a custom action
21847              * after an invalid drop has occurred by providing an implementation.
21848              * @param {Event} e The event object
21849              * @param {String} id The id of the dropped element
21850              * @method afterInvalidDrop
21851              */
21852             this.afterInvalidDrop(e, id);
21853         }
21854     },
21855
21856     // private
21857     afterRepair : function(){
21858         if(Roo.enableFx){
21859             this.el.highlight(this.hlColor || "c3daf9");
21860         }
21861         this.dragging = false;
21862     },
21863
21864     /**
21865      * An empty function by default, but provided so that you can perform a custom action after an invalid
21866      * drop has occurred.
21867      * @param {Roo.dd.DragDrop} target The drop target
21868      * @param {Event} e The event object
21869      * @param {String} id The id of the dragged element
21870      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21871      */
21872     beforeInvalidDrop : function(target, e, id){
21873         return true;
21874     },
21875
21876     // private
21877     handleMouseDown : function(e){
21878         if(this.dragging) {
21879             return;
21880         }
21881         var data = this.getDragData(e);
21882         if(data && this.onBeforeDrag(data, e) !== false){
21883             this.dragData = data;
21884             this.proxy.stop();
21885             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21886         } 
21887     },
21888
21889     /**
21890      * An empty function by default, but provided so that you can perform a custom action before the initial
21891      * drag event begins and optionally cancel it.
21892      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21893      * @param {Event} e The event object
21894      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21895      */
21896     onBeforeDrag : function(data, e){
21897         return true;
21898     },
21899
21900     /**
21901      * An empty function by default, but provided so that you can perform a custom action once the initial
21902      * drag event has begun.  The drag cannot be canceled from this function.
21903      * @param {Number} x The x position of the click on the dragged object
21904      * @param {Number} y The y position of the click on the dragged object
21905      */
21906     onStartDrag : Roo.emptyFn,
21907
21908     // private - YUI override
21909     startDrag : function(x, y){
21910         this.proxy.reset();
21911         this.dragging = true;
21912         this.proxy.update("");
21913         this.onInitDrag(x, y);
21914         this.proxy.show();
21915     },
21916
21917     // private
21918     onInitDrag : function(x, y){
21919         var clone = this.el.dom.cloneNode(true);
21920         clone.id = Roo.id(); // prevent duplicate ids
21921         this.proxy.update(clone);
21922         this.onStartDrag(x, y);
21923         return true;
21924     },
21925
21926     /**
21927      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21928      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21929      */
21930     getProxy : function(){
21931         return this.proxy;  
21932     },
21933
21934     /**
21935      * Hides the drag source's {@link Roo.dd.StatusProxy}
21936      */
21937     hideProxy : function(){
21938         this.proxy.hide();  
21939         this.proxy.reset(true);
21940         this.dragging = false;
21941     },
21942
21943     // private
21944     triggerCacheRefresh : function(){
21945         Roo.dd.DDM.refreshCache(this.groups);
21946     },
21947
21948     // private - override to prevent hiding
21949     b4EndDrag: function(e) {
21950     },
21951
21952     // private - override to prevent moving
21953     endDrag : function(e){
21954         this.onEndDrag(this.dragData, e);
21955     },
21956
21957     // private
21958     onEndDrag : function(data, e){
21959     },
21960     
21961     // private - pin to cursor
21962     autoOffset : function(x, y) {
21963         this.setDelta(-12, -20);
21964     }    
21965 });/*
21966  * Based on:
21967  * Ext JS Library 1.1.1
21968  * Copyright(c) 2006-2007, Ext JS, LLC.
21969  *
21970  * Originally Released Under LGPL - original licence link has changed is not relivant.
21971  *
21972  * Fork - LGPL
21973  * <script type="text/javascript">
21974  */
21975
21976
21977 /**
21978  * @class Roo.dd.DropTarget
21979  * @extends Roo.dd.DDTarget
21980  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21981  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21982  * @constructor
21983  * @param {String/HTMLElement/Element} el The container element
21984  * @param {Object} config
21985  */
21986 Roo.dd.DropTarget = function(el, config){
21987     this.el = Roo.get(el);
21988     
21989     var listeners = false; ;
21990     if (config && config.listeners) {
21991         listeners= config.listeners;
21992         delete config.listeners;
21993     }
21994     Roo.apply(this, config);
21995     
21996     if(this.containerScroll){
21997         Roo.dd.ScrollManager.register(this.el);
21998     }
21999     this.addEvents( {
22000          /**
22001          * @scope Roo.dd.DropTarget
22002          */
22003          
22004          /**
22005          * @event enter
22006          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22007          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
22008          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
22009          * 
22010          * IMPORTANT : it should set this.overClass and this.dropAllowed
22011          * 
22012          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22013          * @param {Event} e The event
22014          * @param {Object} data An object containing arbitrary data supplied by the drag source
22015          */
22016         "enter" : true,
22017         
22018          /**
22019          * @event over
22020          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22021          * This method will be called on every mouse movement while the drag source is over the drop target.
22022          * This default implementation simply returns the dropAllowed config value.
22023          * 
22024          * IMPORTANT : it should set this.dropAllowed
22025          * 
22026          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22027          * @param {Event} e The event
22028          * @param {Object} data An object containing arbitrary data supplied by the drag source
22029          
22030          */
22031         "over" : true,
22032         /**
22033          * @event out
22034          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22035          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
22036          * overClass (if any) from the drop element.
22037          * 
22038          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22039          * @param {Event} e The event
22040          * @param {Object} data An object containing arbitrary data supplied by the drag source
22041          */
22042          "out" : true,
22043          
22044         /**
22045          * @event drop
22046          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22047          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
22048          * implementation that does something to process the drop event and returns true so that the drag source's
22049          * repair action does not run.
22050          * 
22051          * IMPORTANT : it should set this.success
22052          * 
22053          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22054          * @param {Event} e The event
22055          * @param {Object} data An object containing arbitrary data supplied by the drag source
22056         */
22057          "drop" : true
22058     });
22059             
22060      
22061     Roo.dd.DropTarget.superclass.constructor.call(  this, 
22062         this.el.dom, 
22063         this.ddGroup || this.group,
22064         {
22065             isTarget: true,
22066             listeners : listeners || {} 
22067            
22068         
22069         }
22070     );
22071
22072 };
22073
22074 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22075     /**
22076      * @cfg {String} overClass
22077      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22078      */
22079      /**
22080      * @cfg {String} ddGroup
22081      * The drag drop group to handle drop events for
22082      */
22083      
22084     /**
22085      * @cfg {String} dropAllowed
22086      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22087      */
22088     dropAllowed : "x-dd-drop-ok",
22089     /**
22090      * @cfg {String} dropNotAllowed
22091      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22092      */
22093     dropNotAllowed : "x-dd-drop-nodrop",
22094     /**
22095      * @cfg {boolean} success
22096      * set this after drop listener.. 
22097      */
22098     success : false,
22099     /**
22100      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22101      * if the drop point is valid for over/enter..
22102      */
22103     valid : false,
22104     // private
22105     isTarget : true,
22106
22107     // private
22108     isNotifyTarget : true,
22109     
22110     /**
22111      * @hide
22112      */
22113     notifyEnter : function(dd, e, data)
22114     {
22115         this.valid = true;
22116         this.fireEvent('enter', dd, e, data);
22117         if(this.overClass){
22118             this.el.addClass(this.overClass);
22119         }
22120         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22121             this.valid ? this.dropAllowed : this.dropNotAllowed
22122         );
22123     },
22124
22125     /**
22126      * @hide
22127      */
22128     notifyOver : function(dd, e, data)
22129     {
22130         this.valid = true;
22131         this.fireEvent('over', dd, e, data);
22132         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22133             this.valid ? this.dropAllowed : this.dropNotAllowed
22134         );
22135     },
22136
22137     /**
22138      * @hide
22139      */
22140     notifyOut : function(dd, e, data)
22141     {
22142         this.fireEvent('out', dd, e, data);
22143         if(this.overClass){
22144             this.el.removeClass(this.overClass);
22145         }
22146     },
22147
22148     /**
22149      * @hide
22150      */
22151     notifyDrop : function(dd, e, data)
22152     {
22153         this.success = false;
22154         this.fireEvent('drop', dd, e, data);
22155         return this.success;
22156     }
22157 });/*
22158  * Based on:
22159  * Ext JS Library 1.1.1
22160  * Copyright(c) 2006-2007, Ext JS, LLC.
22161  *
22162  * Originally Released Under LGPL - original licence link has changed is not relivant.
22163  *
22164  * Fork - LGPL
22165  * <script type="text/javascript">
22166  */
22167
22168
22169 /**
22170  * @class Roo.dd.DragZone
22171  * @extends Roo.dd.DragSource
22172  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22173  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22174  * @constructor
22175  * @param {String/HTMLElement/Element} el The container element
22176  * @param {Object} config
22177  */
22178 Roo.dd.DragZone = function(el, config){
22179     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22180     if(this.containerScroll){
22181         Roo.dd.ScrollManager.register(this.el);
22182     }
22183 };
22184
22185 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22186     /**
22187      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22188      * for auto scrolling during drag operations.
22189      */
22190     /**
22191      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22192      * method after a failed drop (defaults to "c3daf9" - light blue)
22193      */
22194
22195     /**
22196      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22197      * for a valid target to drag based on the mouse down. Override this method
22198      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22199      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22200      * @param {EventObject} e The mouse down event
22201      * @return {Object} The dragData
22202      */
22203     getDragData : function(e){
22204         return Roo.dd.Registry.getHandleFromEvent(e);
22205     },
22206     
22207     /**
22208      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22209      * this.dragData.ddel
22210      * @param {Number} x The x position of the click on the dragged object
22211      * @param {Number} y The y position of the click on the dragged object
22212      * @return {Boolean} true to continue the drag, false to cancel
22213      */
22214     onInitDrag : function(x, y){
22215         this.proxy.update(this.dragData.ddel.cloneNode(true));
22216         this.onStartDrag(x, y);
22217         return true;
22218     },
22219     
22220     /**
22221      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22222      */
22223     afterRepair : function(){
22224         if(Roo.enableFx){
22225             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22226         }
22227         this.dragging = false;
22228     },
22229
22230     /**
22231      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22232      * the XY of this.dragData.ddel
22233      * @param {EventObject} e The mouse up event
22234      * @return {Array} The xy location (e.g. [100, 200])
22235      */
22236     getRepairXY : function(e){
22237         return Roo.Element.fly(this.dragData.ddel).getXY();  
22238     }
22239 });/*
22240  * Based on:
22241  * Ext JS Library 1.1.1
22242  * Copyright(c) 2006-2007, Ext JS, LLC.
22243  *
22244  * Originally Released Under LGPL - original licence link has changed is not relivant.
22245  *
22246  * Fork - LGPL
22247  * <script type="text/javascript">
22248  */
22249 /**
22250  * @class Roo.dd.DropZone
22251  * @extends Roo.dd.DropTarget
22252  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22253  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22254  * @constructor
22255  * @param {String/HTMLElement/Element} el The container element
22256  * @param {Object} config
22257  */
22258 Roo.dd.DropZone = function(el, config){
22259     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22260 };
22261
22262 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22263     /**
22264      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22265      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22266      * provide your own custom lookup.
22267      * @param {Event} e The event
22268      * @return {Object} data The custom data
22269      */
22270     getTargetFromEvent : function(e){
22271         return Roo.dd.Registry.getTargetFromEvent(e);
22272     },
22273
22274     /**
22275      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22276      * that it has registered.  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     onNodeEnter : function(n, dd, e, data){
22285         
22286     },
22287
22288     /**
22289      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22290      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22291      * overridden to provide the proper feedback.
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 {String} status The CSS class that communicates the drop status back to the source so that the
22298      * underlying {@link Roo.dd.StatusProxy} can be updated
22299      */
22300     onNodeOver : function(n, dd, e, data){
22301         return this.dropAllowed;
22302     },
22303
22304     /**
22305      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22306      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22307      * node-specific processing if necessary.
22308      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22309      * {@link #getTargetFromEvent} for this node)
22310      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22311      * @param {Event} e The event
22312      * @param {Object} data An object containing arbitrary data supplied by the drag source
22313      */
22314     onNodeOut : function(n, dd, e, data){
22315         
22316     },
22317
22318     /**
22319      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22320      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22321      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22322      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22323      * {@link #getTargetFromEvent} for this node)
22324      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22325      * @param {Event} e The event
22326      * @param {Object} data An object containing arbitrary data supplied by the drag source
22327      * @return {Boolean} True if the drop was valid, else false
22328      */
22329     onNodeDrop : function(n, dd, e, data){
22330         return false;
22331     },
22332
22333     /**
22334      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22335      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22336      * it should be overridden to provide the proper feedback if necessary.
22337      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22338      * @param {Event} e The event
22339      * @param {Object} data An object containing arbitrary data supplied by the drag source
22340      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22341      * underlying {@link Roo.dd.StatusProxy} can be updated
22342      */
22343     onContainerOver : function(dd, e, data){
22344         return this.dropNotAllowed;
22345     },
22346
22347     /**
22348      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22349      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22350      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22351      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22352      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22353      * @param {Event} e The event
22354      * @param {Object} data An object containing arbitrary data supplied by the drag source
22355      * @return {Boolean} True if the drop was valid, else false
22356      */
22357     onContainerDrop : function(dd, e, data){
22358         return false;
22359     },
22360
22361     /**
22362      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22363      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22364      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22365      * you should override this method and provide a custom implementation.
22366      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22367      * @param {Event} e The event
22368      * @param {Object} data An object containing arbitrary data supplied by the drag source
22369      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22370      * underlying {@link Roo.dd.StatusProxy} can be updated
22371      */
22372     notifyEnter : function(dd, e, data){
22373         return this.dropNotAllowed;
22374     },
22375
22376     /**
22377      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22378      * This method will be called on every mouse movement while the drag source is over the drop zone.
22379      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22380      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22381      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22382      * registered node, it will call {@link #onContainerOver}.
22383      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22384      * @param {Event} e The event
22385      * @param {Object} data An object containing arbitrary data supplied by the drag source
22386      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22387      * underlying {@link Roo.dd.StatusProxy} can be updated
22388      */
22389     notifyOver : function(dd, e, data){
22390         var n = this.getTargetFromEvent(e);
22391         if(!n){ // not over valid drop target
22392             if(this.lastOverNode){
22393                 this.onNodeOut(this.lastOverNode, dd, e, data);
22394                 this.lastOverNode = null;
22395             }
22396             return this.onContainerOver(dd, e, data);
22397         }
22398         if(this.lastOverNode != n){
22399             if(this.lastOverNode){
22400                 this.onNodeOut(this.lastOverNode, dd, e, data);
22401             }
22402             this.onNodeEnter(n, dd, e, data);
22403             this.lastOverNode = n;
22404         }
22405         return this.onNodeOver(n, dd, e, data);
22406     },
22407
22408     /**
22409      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22410      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22411      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22412      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22413      * @param {Event} e The event
22414      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22415      */
22416     notifyOut : function(dd, e, data){
22417         if(this.lastOverNode){
22418             this.onNodeOut(this.lastOverNode, dd, e, data);
22419             this.lastOverNode = null;
22420         }
22421     },
22422
22423     /**
22424      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22425      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22426      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22427      * otherwise it will call {@link #onContainerDrop}.
22428      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22429      * @param {Event} e The event
22430      * @param {Object} data An object containing arbitrary data supplied by the drag source
22431      * @return {Boolean} True if the drop was valid, else false
22432      */
22433     notifyDrop : function(dd, e, data){
22434         if(this.lastOverNode){
22435             this.onNodeOut(this.lastOverNode, dd, e, data);
22436             this.lastOverNode = null;
22437         }
22438         var n = this.getTargetFromEvent(e);
22439         return n ?
22440             this.onNodeDrop(n, dd, e, data) :
22441             this.onContainerDrop(dd, e, data);
22442     },
22443
22444     // private
22445     triggerCacheRefresh : function(){
22446         Roo.dd.DDM.refreshCache(this.groups);
22447     }  
22448 });