Roo/XComponent.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             console.log(s);
346             
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  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
892  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
893  * they are already different, the first value passed in is returned.  Note that this method returns the new value
894  * but does not change the current string.
895  * <pre><code>
896 // alternate sort directions
897 sort = sort.toggle('ASC', 'DESC');
898
899 // instead of conditional logic:
900 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
901 </code></pre>
902  * @param {String} value The value to compare to the current string
903  * @param {String} other The new value to use if the string already equals the first value passed in
904  * @return {String} The new value
905  */
906  
907 String.prototype.toggle = function(value, other){
908     return this == value ? other : value;
909 };/*
910  * Based on:
911  * Ext JS Library 1.1.1
912  * Copyright(c) 2006-2007, Ext JS, LLC.
913  *
914  * Originally Released Under LGPL - original licence link has changed is not relivant.
915  *
916  * Fork - LGPL
917  * <script type="text/javascript">
918  */
919
920  /**
921  * @class Number
922  */
923 Roo.applyIf(Number.prototype, {
924     /**
925      * Checks whether or not the current number is within a desired range.  If the number is already within the
926      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
927      * exceeded.  Note that this method returns the constrained value but does not change the current number.
928      * @param {Number} min The minimum number in the range
929      * @param {Number} max The maximum number in the range
930      * @return {Number} The constrained value if outside the range, otherwise the current value
931      */
932     constrain : function(min, max){
933         return Math.min(Math.max(this, min), max);
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  * @class Array
947  */
948 Roo.applyIf(Array.prototype, {
949     /**
950      * 
951      * Checks whether or not the specified object exists in the array.
952      * @param {Object} o The object to check for
953      * @return {Number} The index of o in the array (or -1 if it is not found)
954      */
955     indexOf : function(o){
956        for (var i = 0, len = this.length; i < len; i++){
957               if(this[i] == o) { return i; }
958        }
959            return -1;
960     },
961
962     /**
963      * Removes the specified object from the array.  If the object is not found nothing happens.
964      * @param {Object} o The object to remove
965      */
966     remove : function(o){
967        var index = this.indexOf(o);
968        if(index != -1){
969            this.splice(index, 1);
970        }
971     },
972     /**
973      * Map (JS 1.6 compatibility)
974      * @param {Function} function  to call
975      */
976     map : function(fun )
977     {
978         var len = this.length >>> 0;
979         if (typeof fun != "function") {
980             throw new TypeError();
981         }
982         var res = new Array(len);
983         var thisp = arguments[1];
984         for (var i = 0; i < len; i++)
985         {
986             if (i in this) {
987                 res[i] = fun.call(thisp, this[i], i, this);
988             }
989         }
990
991         return res;
992     }
993     
994 });
995
996
997  
998 /*
999  * Based on:
1000  * Ext JS Library 1.1.1
1001  * Copyright(c) 2006-2007, Ext JS, LLC.
1002  *
1003  * Originally Released Under LGPL - original licence link has changed is not relivant.
1004  *
1005  * Fork - LGPL
1006  * <script type="text/javascript">
1007  */
1008
1009 /**
1010  * @class Date
1011  *
1012  * The date parsing and format syntax is a subset of
1013  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1014  * supported will provide results equivalent to their PHP versions.
1015  *
1016  * Following is the list of all currently supported formats:
1017  *<pre>
1018 Sample date:
1019 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1020
1021 Format  Output      Description
1022 ------  ----------  --------------------------------------------------------------
1023   d      10         Day of the month, 2 digits with leading zeros
1024   D      Wed        A textual representation of a day, three letters
1025   j      10         Day of the month without leading zeros
1026   l      Wednesday  A full textual representation of the day of the week
1027   S      th         English ordinal day of month suffix, 2 chars (use with j)
1028   w      3          Numeric representation of the day of the week
1029   z      9          The julian date, or day of the year (0-365)
1030   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1031   F      January    A full textual representation of the month
1032   m      01         Numeric representation of a month, with leading zeros
1033   M      Jan        Month name abbreviation, three letters
1034   n      1          Numeric representation of a month, without leading zeros
1035   t      31         Number of days in the given month
1036   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1037   Y      2007       A full numeric representation of a year, 4 digits
1038   y      07         A two digit representation of a year
1039   a      pm         Lowercase Ante meridiem and Post meridiem
1040   A      PM         Uppercase Ante meridiem and Post meridiem
1041   g      3          12-hour format of an hour without leading zeros
1042   G      15         24-hour format of an hour without leading zeros
1043   h      03         12-hour format of an hour with leading zeros
1044   H      15         24-hour format of an hour with leading zeros
1045   i      05         Minutes with leading zeros
1046   s      01         Seconds, with leading zeros
1047   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1048   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1049   T      CST        Timezone setting of the machine running the code
1050   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1051 </pre>
1052  *
1053  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1054  * <pre><code>
1055 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1056 document.write(dt.format('Y-m-d'));                         //2007-01-10
1057 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1058 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
1059  </code></pre>
1060  *
1061  * Here are some standard date/time patterns that you might find helpful.  They
1062  * are not part of the source of Date.js, but to use them you can simply copy this
1063  * block of code into any script that is included after Date.js and they will also become
1064  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1065  * <pre><code>
1066 Date.patterns = {
1067     ISO8601Long:"Y-m-d H:i:s",
1068     ISO8601Short:"Y-m-d",
1069     ShortDate: "n/j/Y",
1070     LongDate: "l, F d, Y",
1071     FullDateTime: "l, F d, Y g:i:s A",
1072     MonthDay: "F d",
1073     ShortTime: "g:i A",
1074     LongTime: "g:i:s A",
1075     SortableDateTime: "Y-m-d\\TH:i:s",
1076     UniversalSortableDateTime: "Y-m-d H:i:sO",
1077     YearMonth: "F, Y"
1078 };
1079 </code></pre>
1080  *
1081  * Example usage:
1082  * <pre><code>
1083 var dt = new Date();
1084 document.write(dt.format(Date.patterns.ShortDate));
1085  </code></pre>
1086  */
1087
1088 /*
1089  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1090  * They generate precompiled functions from date formats instead of parsing and
1091  * processing the pattern every time you format a date.  These functions are available
1092  * on every Date object (any javascript function).
1093  *
1094  * The original article and download are here:
1095  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1096  *
1097  */
1098  
1099  
1100  // was in core
1101 /**
1102  Returns the number of milliseconds between this date and date
1103  @param {Date} date (optional) Defaults to now
1104  @return {Number} The diff in milliseconds
1105  @member Date getElapsed
1106  */
1107 Date.prototype.getElapsed = function(date) {
1108         return Math.abs((date || new Date()).getTime()-this.getTime());
1109 };
1110 // was in date file..
1111
1112
1113 // private
1114 Date.parseFunctions = {count:0};
1115 // private
1116 Date.parseRegexes = [];
1117 // private
1118 Date.formatFunctions = {count:0};
1119
1120 // private
1121 Date.prototype.dateFormat = function(format) {
1122     if (Date.formatFunctions[format] == null) {
1123         Date.createNewFormat(format);
1124     }
1125     var func = Date.formatFunctions[format];
1126     return this[func]();
1127 };
1128
1129
1130 /**
1131  * Formats a date given the supplied format string
1132  * @param {String} format The format string
1133  * @return {String} The formatted date
1134  * @method
1135  */
1136 Date.prototype.format = Date.prototype.dateFormat;
1137
1138 // private
1139 Date.createNewFormat = function(format) {
1140     var funcName = "format" + Date.formatFunctions.count++;
1141     Date.formatFunctions[format] = funcName;
1142     var code = "Date.prototype." + funcName + " = function(){return ";
1143     var special = false;
1144     var ch = '';
1145     for (var i = 0; i < format.length; ++i) {
1146         ch = format.charAt(i);
1147         if (!special && ch == "\\") {
1148             special = true;
1149         }
1150         else if (special) {
1151             special = false;
1152             code += "'" + String.escape(ch) + "' + ";
1153         }
1154         else {
1155             code += Date.getFormatCode(ch);
1156         }
1157     }
1158     /** eval:var:zzzzzzzzzzzzz */
1159     eval(code.substring(0, code.length - 3) + ";}");
1160 };
1161
1162 // private
1163 Date.getFormatCode = function(character) {
1164     switch (character) {
1165     case "d":
1166         return "String.leftPad(this.getDate(), 2, '0') + ";
1167     case "D":
1168         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1169     case "j":
1170         return "this.getDate() + ";
1171     case "l":
1172         return "Date.dayNames[this.getDay()] + ";
1173     case "S":
1174         return "this.getSuffix() + ";
1175     case "w":
1176         return "this.getDay() + ";
1177     case "z":
1178         return "this.getDayOfYear() + ";
1179     case "W":
1180         return "this.getWeekOfYear() + ";
1181     case "F":
1182         return "Date.monthNames[this.getMonth()] + ";
1183     case "m":
1184         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1185     case "M":
1186         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1187     case "n":
1188         return "(this.getMonth() + 1) + ";
1189     case "t":
1190         return "this.getDaysInMonth() + ";
1191     case "L":
1192         return "(this.isLeapYear() ? 1 : 0) + ";
1193     case "Y":
1194         return "this.getFullYear() + ";
1195     case "y":
1196         return "('' + this.getFullYear()).substring(2, 4) + ";
1197     case "a":
1198         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1199     case "A":
1200         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1201     case "g":
1202         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1203     case "G":
1204         return "this.getHours() + ";
1205     case "h":
1206         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1207     case "H":
1208         return "String.leftPad(this.getHours(), 2, '0') + ";
1209     case "i":
1210         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1211     case "s":
1212         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1213     case "O":
1214         return "this.getGMTOffset() + ";
1215     case "P":
1216         return "this.getGMTColonOffset() + ";
1217     case "T":
1218         return "this.getTimezone() + ";
1219     case "Z":
1220         return "(this.getTimezoneOffset() * -60) + ";
1221     default:
1222         return "'" + String.escape(character) + "' + ";
1223     }
1224 };
1225
1226 /**
1227  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1228  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1229  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1230  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1231  * string or the parse operation will fail.
1232  * Example Usage:
1233 <pre><code>
1234 //dt = Fri May 25 2007 (current date)
1235 var dt = new Date();
1236
1237 //dt = Thu May 25 2006 (today's month/day in 2006)
1238 dt = Date.parseDate("2006", "Y");
1239
1240 //dt = Sun Jan 15 2006 (all date parts specified)
1241 dt = Date.parseDate("2006-1-15", "Y-m-d");
1242
1243 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1244 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1245 </code></pre>
1246  * @param {String} input The unparsed date as a string
1247  * @param {String} format The format the date is in
1248  * @return {Date} The parsed date
1249  * @static
1250  */
1251 Date.parseDate = function(input, format) {
1252     if (Date.parseFunctions[format] == null) {
1253         Date.createParser(format);
1254     }
1255     var func = Date.parseFunctions[format];
1256     return Date[func](input);
1257 };
1258 /**
1259  * @private
1260  */
1261
1262 Date.createParser = function(format) {
1263     var funcName = "parse" + Date.parseFunctions.count++;
1264     var regexNum = Date.parseRegexes.length;
1265     var currentGroup = 1;
1266     Date.parseFunctions[format] = funcName;
1267
1268     var code = "Date." + funcName + " = function(input){\n"
1269         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1270         + "var d = new Date();\n"
1271         + "y = d.getFullYear();\n"
1272         + "m = d.getMonth();\n"
1273         + "d = d.getDate();\n"
1274         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1275         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1276         + "if (results && results.length > 0) {";
1277     var regex = "";
1278
1279     var special = false;
1280     var ch = '';
1281     for (var i = 0; i < format.length; ++i) {
1282         ch = format.charAt(i);
1283         if (!special && ch == "\\") {
1284             special = true;
1285         }
1286         else if (special) {
1287             special = false;
1288             regex += String.escape(ch);
1289         }
1290         else {
1291             var obj = Date.formatCodeToRegex(ch, currentGroup);
1292             currentGroup += obj.g;
1293             regex += obj.s;
1294             if (obj.g && obj.c) {
1295                 code += obj.c;
1296             }
1297         }
1298     }
1299
1300     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1301         + "{v = new Date(y, m, d, h, i, s);}\n"
1302         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1303         + "{v = new Date(y, m, d, h, i);}\n"
1304         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1305         + "{v = new Date(y, m, d, h);}\n"
1306         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1307         + "{v = new Date(y, m, d);}\n"
1308         + "else if (y >= 0 && m >= 0)\n"
1309         + "{v = new Date(y, m);}\n"
1310         + "else if (y >= 0)\n"
1311         + "{v = new Date(y);}\n"
1312         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1313         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1314         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1315         + ";}";
1316
1317     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1318     /** eval:var:zzzzzzzzzzzzz */
1319     eval(code);
1320 };
1321
1322 // private
1323 Date.formatCodeToRegex = function(character, currentGroup) {
1324     switch (character) {
1325     case "D":
1326         return {g:0,
1327         c:null,
1328         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1329     case "j":
1330         return {g:1,
1331             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1332             s:"(\\d{1,2})"}; // day of month without leading zeroes
1333     case "d":
1334         return {g:1,
1335             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1336             s:"(\\d{2})"}; // day of month with leading zeroes
1337     case "l":
1338         return {g:0,
1339             c:null,
1340             s:"(?:" + Date.dayNames.join("|") + ")"};
1341     case "S":
1342         return {g:0,
1343             c:null,
1344             s:"(?:st|nd|rd|th)"};
1345     case "w":
1346         return {g:0,
1347             c:null,
1348             s:"\\d"};
1349     case "z":
1350         return {g:0,
1351             c:null,
1352             s:"(?:\\d{1,3})"};
1353     case "W":
1354         return {g:0,
1355             c:null,
1356             s:"(?:\\d{2})"};
1357     case "F":
1358         return {g:1,
1359             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1360             s:"(" + Date.monthNames.join("|") + ")"};
1361     case "M":
1362         return {g:1,
1363             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1364             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1365     case "n":
1366         return {g:1,
1367             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1368             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1369     case "m":
1370         return {g:1,
1371             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1372             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1373     case "t":
1374         return {g:0,
1375             c:null,
1376             s:"\\d{1,2}"};
1377     case "L":
1378         return {g:0,
1379             c:null,
1380             s:"(?:1|0)"};
1381     case "Y":
1382         return {g:1,
1383             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1384             s:"(\\d{4})"};
1385     case "y":
1386         return {g:1,
1387             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1388                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1389             s:"(\\d{1,2})"};
1390     case "a":
1391         return {g:1,
1392             c:"if (results[" + currentGroup + "] == 'am') {\n"
1393                 + "if (h == 12) { h = 0; }\n"
1394                 + "} else { if (h < 12) { h += 12; }}",
1395             s:"(am|pm)"};
1396     case "A":
1397         return {g:1,
1398             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1399                 + "if (h == 12) { h = 0; }\n"
1400                 + "} else { if (h < 12) { h += 12; }}",
1401             s:"(AM|PM)"};
1402     case "g":
1403     case "G":
1404         return {g:1,
1405             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1406             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1407     case "h":
1408     case "H":
1409         return {g:1,
1410             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1411             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1412     case "i":
1413         return {g:1,
1414             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1415             s:"(\\d{2})"};
1416     case "s":
1417         return {g:1,
1418             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1419             s:"(\\d{2})"};
1420     case "O":
1421         return {g:1,
1422             c:[
1423                 "o = results[", currentGroup, "];\n",
1424                 "var sn = o.substring(0,1);\n", // get + / - sign
1425                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1426                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1427                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1428                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1429             ].join(""),
1430             s:"([+\-]\\d{2,4})"};
1431     
1432     
1433     case "P":
1434         return {g:1,
1435                 c:[
1436                    "o = results[", currentGroup, "];\n",
1437                    "var sn = o.substring(0,1);\n",
1438                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1439                    "var mn = o.substring(4,6) % 60;\n",
1440                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1441                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1442             ].join(""),
1443             s:"([+\-]\\d{4})"};
1444     case "T":
1445         return {g:0,
1446             c:null,
1447             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1448     case "Z":
1449         return {g:1,
1450             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1451                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1452             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1453     default:
1454         return {g:0,
1455             c:null,
1456             s:String.escape(character)};
1457     }
1458 };
1459
1460 /**
1461  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1462  * @return {String} The abbreviated timezone name (e.g. 'CST')
1463  */
1464 Date.prototype.getTimezone = function() {
1465     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1466 };
1467
1468 /**
1469  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1470  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1471  */
1472 Date.prototype.getGMTOffset = function() {
1473     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1474         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1475         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1476 };
1477
1478 /**
1479  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1480  * @return {String} 2-characters representing hours and 2-characters representing minutes
1481  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1482  */
1483 Date.prototype.getGMTColonOffset = function() {
1484         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1485                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1486                 + ":"
1487                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1488 }
1489
1490 /**
1491  * Get the numeric day number of the year, adjusted for leap year.
1492  * @return {Number} 0 through 364 (365 in leap years)
1493  */
1494 Date.prototype.getDayOfYear = function() {
1495     var num = 0;
1496     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1497     for (var i = 0; i < this.getMonth(); ++i) {
1498         num += Date.daysInMonth[i];
1499     }
1500     return num + this.getDate() - 1;
1501 };
1502
1503 /**
1504  * Get the string representation of the numeric week number of the year
1505  * (equivalent to the format specifier 'W').
1506  * @return {String} '00' through '52'
1507  */
1508 Date.prototype.getWeekOfYear = function() {
1509     // Skip to Thursday of this week
1510     var now = this.getDayOfYear() + (4 - this.getDay());
1511     // Find the first Thursday of the year
1512     var jan1 = new Date(this.getFullYear(), 0, 1);
1513     var then = (7 - jan1.getDay() + 4);
1514     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1515 };
1516
1517 /**
1518  * Whether or not the current date is in a leap year.
1519  * @return {Boolean} True if the current date is in a leap year, else false
1520  */
1521 Date.prototype.isLeapYear = function() {
1522     var year = this.getFullYear();
1523     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1524 };
1525
1526 /**
1527  * Get the first day of the current month, adjusted for leap year.  The returned value
1528  * is the numeric day index within the week (0-6) which can be used in conjunction with
1529  * the {@link #monthNames} array to retrieve the textual day name.
1530  * Example:
1531  *<pre><code>
1532 var dt = new Date('1/10/2007');
1533 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1534 </code></pre>
1535  * @return {Number} The day number (0-6)
1536  */
1537 Date.prototype.getFirstDayOfMonth = function() {
1538     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1539     return (day < 0) ? (day + 7) : day;
1540 };
1541
1542 /**
1543  * Get the last day of the current month, adjusted for leap year.  The returned value
1544  * is the numeric day index within the week (0-6) which can be used in conjunction with
1545  * the {@link #monthNames} array to retrieve the textual day name.
1546  * Example:
1547  *<pre><code>
1548 var dt = new Date('1/10/2007');
1549 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1550 </code></pre>
1551  * @return {Number} The day number (0-6)
1552  */
1553 Date.prototype.getLastDayOfMonth = function() {
1554     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1555     return (day < 0) ? (day + 7) : day;
1556 };
1557
1558
1559 /**
1560  * Get the first date of this date's month
1561  * @return {Date}
1562  */
1563 Date.prototype.getFirstDateOfMonth = function() {
1564     return new Date(this.getFullYear(), this.getMonth(), 1);
1565 };
1566
1567 /**
1568  * Get the last date of this date's month
1569  * @return {Date}
1570  */
1571 Date.prototype.getLastDateOfMonth = function() {
1572     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1573 };
1574 /**
1575  * Get the number of days in the current month, adjusted for leap year.
1576  * @return {Number} The number of days in the month
1577  */
1578 Date.prototype.getDaysInMonth = function() {
1579     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1580     return Date.daysInMonth[this.getMonth()];
1581 };
1582
1583 /**
1584  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1585  * @return {String} 'st, 'nd', 'rd' or 'th'
1586  */
1587 Date.prototype.getSuffix = function() {
1588     switch (this.getDate()) {
1589         case 1:
1590         case 21:
1591         case 31:
1592             return "st";
1593         case 2:
1594         case 22:
1595             return "nd";
1596         case 3:
1597         case 23:
1598             return "rd";
1599         default:
1600             return "th";
1601     }
1602 };
1603
1604 // private
1605 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1606
1607 /**
1608  * An array of textual month names.
1609  * Override these values for international dates, for example...
1610  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1611  * @type Array
1612  * @static
1613  */
1614 Date.monthNames =
1615    ["January",
1616     "February",
1617     "March",
1618     "April",
1619     "May",
1620     "June",
1621     "July",
1622     "August",
1623     "September",
1624     "October",
1625     "November",
1626     "December"];
1627
1628 /**
1629  * An array of textual day names.
1630  * Override these values for international dates, for example...
1631  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1632  * @type Array
1633  * @static
1634  */
1635 Date.dayNames =
1636    ["Sunday",
1637     "Monday",
1638     "Tuesday",
1639     "Wednesday",
1640     "Thursday",
1641     "Friday",
1642     "Saturday"];
1643
1644 // private
1645 Date.y2kYear = 50;
1646 // private
1647 Date.monthNumbers = {
1648     Jan:0,
1649     Feb:1,
1650     Mar:2,
1651     Apr:3,
1652     May:4,
1653     Jun:5,
1654     Jul:6,
1655     Aug:7,
1656     Sep:8,
1657     Oct:9,
1658     Nov:10,
1659     Dec:11};
1660
1661 /**
1662  * Creates and returns a new Date instance with the exact same date value as the called instance.
1663  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1664  * variable will also be changed.  When the intention is to create a new variable that will not
1665  * modify the original instance, you should create a clone.
1666  *
1667  * Example of correctly cloning a date:
1668  * <pre><code>
1669 //wrong way:
1670 var orig = new Date('10/1/2006');
1671 var copy = orig;
1672 copy.setDate(5);
1673 document.write(orig);  //returns 'Thu Oct 05 2006'!
1674
1675 //correct way:
1676 var orig = new Date('10/1/2006');
1677 var copy = orig.clone();
1678 copy.setDate(5);
1679 document.write(orig);  //returns 'Thu Oct 01 2006'
1680 </code></pre>
1681  * @return {Date} The new Date instance
1682  */
1683 Date.prototype.clone = function() {
1684         return new Date(this.getTime());
1685 };
1686
1687 /**
1688  * Clears any time information from this date
1689  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1690  @return {Date} this or the clone
1691  */
1692 Date.prototype.clearTime = function(clone){
1693     if(clone){
1694         return this.clone().clearTime();
1695     }
1696     this.setHours(0);
1697     this.setMinutes(0);
1698     this.setSeconds(0);
1699     this.setMilliseconds(0);
1700     return this;
1701 };
1702
1703 // private
1704 // safari setMonth is broken -- check that this is only donw once...
1705 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1706     Date.brokenSetMonth = Date.prototype.setMonth;
1707         Date.prototype.setMonth = function(num){
1708                 if(num <= -1){
1709                         var n = Math.ceil(-num);
1710                         var back_year = Math.ceil(n/12);
1711                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1712                         this.setFullYear(this.getFullYear() - back_year);
1713                         return Date.brokenSetMonth.call(this, month);
1714                 } else {
1715                         return Date.brokenSetMonth.apply(this, arguments);
1716                 }
1717         };
1718 }
1719
1720 /** Date interval constant 
1721 * @static 
1722 * @type String */
1723 Date.MILLI = "ms";
1724 /** Date interval constant 
1725 * @static 
1726 * @type String */
1727 Date.SECOND = "s";
1728 /** Date interval constant 
1729 * @static 
1730 * @type String */
1731 Date.MINUTE = "mi";
1732 /** Date interval constant 
1733 * @static 
1734 * @type String */
1735 Date.HOUR = "h";
1736 /** Date interval constant 
1737 * @static 
1738 * @type String */
1739 Date.DAY = "d";
1740 /** Date interval constant 
1741 * @static 
1742 * @type String */
1743 Date.MONTH = "mo";
1744 /** Date interval constant 
1745 * @static 
1746 * @type String */
1747 Date.YEAR = "y";
1748
1749 /**
1750  * Provides a convenient method of performing basic date arithmetic.  This method
1751  * does not modify the Date instance being called - it creates and returns
1752  * a new Date instance containing the resulting date value.
1753  *
1754  * Examples:
1755  * <pre><code>
1756 //Basic usage:
1757 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1758 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1759
1760 //Negative values will subtract correctly:
1761 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1762 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1763
1764 //You can even chain several calls together in one line!
1765 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1766 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1767  </code></pre>
1768  *
1769  * @param {String} interval   A valid date interval enum value
1770  * @param {Number} value      The amount to add to the current date
1771  * @return {Date} The new Date instance
1772  */
1773 Date.prototype.add = function(interval, value){
1774   var d = this.clone();
1775   if (!interval || value === 0) { return d; }
1776   switch(interval.toLowerCase()){
1777     case Date.MILLI:
1778       d.setMilliseconds(this.getMilliseconds() + value);
1779       break;
1780     case Date.SECOND:
1781       d.setSeconds(this.getSeconds() + value);
1782       break;
1783     case Date.MINUTE:
1784       d.setMinutes(this.getMinutes() + value);
1785       break;
1786     case Date.HOUR:
1787       d.setHours(this.getHours() + value);
1788       break;
1789     case Date.DAY:
1790       d.setDate(this.getDate() + value);
1791       break;
1792     case Date.MONTH:
1793       var day = this.getDate();
1794       if(day > 28){
1795           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1796       }
1797       d.setDate(day);
1798       d.setMonth(this.getMonth() + value);
1799       break;
1800     case Date.YEAR:
1801       d.setFullYear(this.getFullYear() + value);
1802       break;
1803   }
1804   return d;
1805 };
1806 /*
1807  * Based on:
1808  * Ext JS Library 1.1.1
1809  * Copyright(c) 2006-2007, Ext JS, LLC.
1810  *
1811  * Originally Released Under LGPL - original licence link has changed is not relivant.
1812  *
1813  * Fork - LGPL
1814  * <script type="text/javascript">
1815  */
1816
1817 /**
1818  * @class Roo.lib.Dom
1819  * @static
1820  * 
1821  * Dom utils (from YIU afaik)
1822  * 
1823  **/
1824 Roo.lib.Dom = {
1825     /**
1826      * Get the view width
1827      * @param {Boolean} full True will get the full document, otherwise it's the view width
1828      * @return {Number} The width
1829      */
1830      
1831     getViewWidth : function(full) {
1832         return full ? this.getDocumentWidth() : this.getViewportWidth();
1833     },
1834     /**
1835      * Get the view height
1836      * @param {Boolean} full True will get the full document, otherwise it's the view height
1837      * @return {Number} The height
1838      */
1839     getViewHeight : function(full) {
1840         return full ? this.getDocumentHeight() : this.getViewportHeight();
1841     },
1842
1843     getDocumentHeight: function() {
1844         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1845         return Math.max(scrollHeight, this.getViewportHeight());
1846     },
1847
1848     getDocumentWidth: function() {
1849         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1850         return Math.max(scrollWidth, this.getViewportWidth());
1851     },
1852
1853     getViewportHeight: function() {
1854         var height = self.innerHeight;
1855         var mode = document.compatMode;
1856
1857         if ((mode || Roo.isIE) && !Roo.isOpera) {
1858             height = (mode == "CSS1Compat") ?
1859                      document.documentElement.clientHeight :
1860                      document.body.clientHeight;
1861         }
1862
1863         return height;
1864     },
1865
1866     getViewportWidth: function() {
1867         var width = self.innerWidth;
1868         var mode = document.compatMode;
1869
1870         if (mode || Roo.isIE) {
1871             width = (mode == "CSS1Compat") ?
1872                     document.documentElement.clientWidth :
1873                     document.body.clientWidth;
1874         }
1875         return width;
1876     },
1877
1878     isAncestor : function(p, c) {
1879         p = Roo.getDom(p);
1880         c = Roo.getDom(c);
1881         if (!p || !c) {
1882             return false;
1883         }
1884
1885         if (p.contains && !Roo.isSafari) {
1886             return p.contains(c);
1887         } else if (p.compareDocumentPosition) {
1888             return !!(p.compareDocumentPosition(c) & 16);
1889         } else {
1890             var parent = c.parentNode;
1891             while (parent) {
1892                 if (parent == p) {
1893                     return true;
1894                 }
1895                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1896                     return false;
1897                 }
1898                 parent = parent.parentNode;
1899             }
1900             return false;
1901         }
1902     },
1903
1904     getRegion : function(el) {
1905         return Roo.lib.Region.getRegion(el);
1906     },
1907
1908     getY : function(el) {
1909         return this.getXY(el)[1];
1910     },
1911
1912     getX : function(el) {
1913         return this.getXY(el)[0];
1914     },
1915
1916     getXY : function(el) {
1917         var p, pe, b, scroll, bd = document.body;
1918         el = Roo.getDom(el);
1919         var fly = Roo.lib.AnimBase.fly;
1920         if (el.getBoundingClientRect) {
1921             b = el.getBoundingClientRect();
1922             scroll = fly(document).getScroll();
1923             return [b.left + scroll.left, b.top + scroll.top];
1924         }
1925         var x = 0, y = 0;
1926
1927         p = el;
1928
1929         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1930
1931         while (p) {
1932
1933             x += p.offsetLeft;
1934             y += p.offsetTop;
1935
1936             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1937                 hasAbsolute = true;
1938             }
1939
1940             if (Roo.isGecko) {
1941                 pe = fly(p);
1942
1943                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1944                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1945
1946
1947                 x += bl;
1948                 y += bt;
1949
1950
1951                 if (p != el && pe.getStyle('overflow') != 'visible') {
1952                     x += bl;
1953                     y += bt;
1954                 }
1955             }
1956             p = p.offsetParent;
1957         }
1958
1959         if (Roo.isSafari && hasAbsolute) {
1960             x -= bd.offsetLeft;
1961             y -= bd.offsetTop;
1962         }
1963
1964         if (Roo.isGecko && !hasAbsolute) {
1965             var dbd = fly(bd);
1966             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1967             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1968         }
1969
1970         p = el.parentNode;
1971         while (p && p != bd) {
1972             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1973                 x -= p.scrollLeft;
1974                 y -= p.scrollTop;
1975             }
1976             p = p.parentNode;
1977         }
1978         return [x, y];
1979     },
1980  
1981   
1982
1983
1984     setXY : function(el, xy) {
1985         el = Roo.fly(el, '_setXY');
1986         el.position();
1987         var pts = el.translatePoints(xy);
1988         if (xy[0] !== false) {
1989             el.dom.style.left = pts.left + "px";
1990         }
1991         if (xy[1] !== false) {
1992             el.dom.style.top = pts.top + "px";
1993         }
1994     },
1995
1996     setX : function(el, x) {
1997         this.setXY(el, [x, false]);
1998     },
1999
2000     setY : function(el, y) {
2001         this.setXY(el, [false, y]);
2002     }
2003 };
2004 /*
2005  * Portions of this file are based on pieces of Yahoo User Interface Library
2006  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2007  * YUI licensed under the BSD License:
2008  * http://developer.yahoo.net/yui/license.txt
2009  * <script type="text/javascript">
2010  *
2011  */
2012
2013 Roo.lib.Event = function() {
2014     var loadComplete = false;
2015     var listeners = [];
2016     var unloadListeners = [];
2017     var retryCount = 0;
2018     var onAvailStack = [];
2019     var counter = 0;
2020     var lastError = null;
2021
2022     return {
2023         POLL_RETRYS: 200,
2024         POLL_INTERVAL: 20,
2025         EL: 0,
2026         TYPE: 1,
2027         FN: 2,
2028         WFN: 3,
2029         OBJ: 3,
2030         ADJ_SCOPE: 4,
2031         _interval: null,
2032
2033         startInterval: function() {
2034             if (!this._interval) {
2035                 var self = this;
2036                 var callback = function() {
2037                     self._tryPreloadAttach();
2038                 };
2039                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2040
2041             }
2042         },
2043
2044         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2045             onAvailStack.push({ id:         p_id,
2046                 fn:         p_fn,
2047                 obj:        p_obj,
2048                 override:   p_override,
2049                 checkReady: false    });
2050
2051             retryCount = this.POLL_RETRYS;
2052             this.startInterval();
2053         },
2054
2055
2056         addListener: function(el, eventName, fn) {
2057             el = Roo.getDom(el);
2058             if (!el || !fn) {
2059                 return false;
2060             }
2061
2062             if ("unload" == eventName) {
2063                 unloadListeners[unloadListeners.length] =
2064                 [el, eventName, fn];
2065                 return true;
2066             }
2067
2068             var wrappedFn = function(e) {
2069                 return fn(Roo.lib.Event.getEvent(e));
2070             };
2071
2072             var li = [el, eventName, fn, wrappedFn];
2073
2074             var index = listeners.length;
2075             listeners[index] = li;
2076
2077             this.doAdd(el, eventName, wrappedFn, false);
2078             return true;
2079
2080         },
2081
2082
2083         removeListener: function(el, eventName, fn) {
2084             var i, len;
2085
2086             el = Roo.getDom(el);
2087
2088             if(!fn) {
2089                 return this.purgeElement(el, false, eventName);
2090             }
2091
2092
2093             if ("unload" == eventName) {
2094
2095                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2096                     var li = unloadListeners[i];
2097                     if (li &&
2098                         li[0] == el &&
2099                         li[1] == eventName &&
2100                         li[2] == fn) {
2101                         unloadListeners.splice(i, 1);
2102                         return true;
2103                     }
2104                 }
2105
2106                 return false;
2107             }
2108
2109             var cacheItem = null;
2110
2111
2112             var index = arguments[3];
2113
2114             if ("undefined" == typeof index) {
2115                 index = this._getCacheIndex(el, eventName, fn);
2116             }
2117
2118             if (index >= 0) {
2119                 cacheItem = listeners[index];
2120             }
2121
2122             if (!el || !cacheItem) {
2123                 return false;
2124             }
2125
2126             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2127
2128             delete listeners[index][this.WFN];
2129             delete listeners[index][this.FN];
2130             listeners.splice(index, 1);
2131
2132             return true;
2133
2134         },
2135
2136
2137         getTarget: function(ev, resolveTextNode) {
2138             ev = ev.browserEvent || ev;
2139             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2140             var t = ev.target || ev.srcElement;
2141             return this.resolveTextNode(t);
2142         },
2143
2144
2145         resolveTextNode: function(node) {
2146             if (Roo.isSafari && node && 3 == node.nodeType) {
2147                 return node.parentNode;
2148             } else {
2149                 return node;
2150             }
2151         },
2152
2153
2154         getPageX: function(ev) {
2155             ev = ev.browserEvent || ev;
2156             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2157             var x = ev.pageX;
2158             if (!x && 0 !== x) {
2159                 x = ev.clientX || 0;
2160
2161                 if (Roo.isIE) {
2162                     x += this.getScroll()[1];
2163                 }
2164             }
2165
2166             return x;
2167         },
2168
2169
2170         getPageY: function(ev) {
2171             ev = ev.browserEvent || ev;
2172             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2173             var y = ev.pageY;
2174             if (!y && 0 !== y) {
2175                 y = ev.clientY || 0;
2176
2177                 if (Roo.isIE) {
2178                     y += this.getScroll()[0];
2179                 }
2180             }
2181
2182
2183             return y;
2184         },
2185
2186
2187         getXY: function(ev) {
2188             ev = ev.browserEvent || ev;
2189             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2190             return [this.getPageX(ev), this.getPageY(ev)];
2191         },
2192
2193
2194         getRelatedTarget: function(ev) {
2195             ev = ev.browserEvent || ev;
2196             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2197             var t = ev.relatedTarget;
2198             if (!t) {
2199                 if (ev.type == "mouseout") {
2200                     t = ev.toElement;
2201                 } else if (ev.type == "mouseover") {
2202                     t = ev.fromElement;
2203                 }
2204             }
2205
2206             return this.resolveTextNode(t);
2207         },
2208
2209
2210         getTime: function(ev) {
2211             ev = ev.browserEvent || ev;
2212             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2213             if (!ev.time) {
2214                 var t = new Date().getTime();
2215                 try {
2216                     ev.time = t;
2217                 } catch(ex) {
2218                     this.lastError = ex;
2219                     return t;
2220                 }
2221             }
2222
2223             return ev.time;
2224         },
2225
2226
2227         stopEvent: function(ev) {
2228             this.stopPropagation(ev);
2229             this.preventDefault(ev);
2230         },
2231
2232
2233         stopPropagation: function(ev) {
2234             ev = ev.browserEvent || ev;
2235             if (ev.stopPropagation) {
2236                 ev.stopPropagation();
2237             } else {
2238                 ev.cancelBubble = true;
2239             }
2240         },
2241
2242
2243         preventDefault: function(ev) {
2244             ev = ev.browserEvent || ev;
2245             if(ev.preventDefault) {
2246                 ev.preventDefault();
2247             } else {
2248                 ev.returnValue = false;
2249             }
2250         },
2251
2252
2253         getEvent: function(e) {
2254             var ev = e || window.event;
2255             if (!ev) {
2256                 var c = this.getEvent.caller;
2257                 while (c) {
2258                     ev = c.arguments[0];
2259                     if (ev && Event == ev.constructor) {
2260                         break;
2261                     }
2262                     c = c.caller;
2263                 }
2264             }
2265             return ev;
2266         },
2267
2268
2269         getCharCode: function(ev) {
2270             ev = ev.browserEvent || ev;
2271             return ev.charCode || ev.keyCode || 0;
2272         },
2273
2274
2275         _getCacheIndex: function(el, eventName, fn) {
2276             for (var i = 0,len = listeners.length; i < len; ++i) {
2277                 var li = listeners[i];
2278                 if (li &&
2279                     li[this.FN] == fn &&
2280                     li[this.EL] == el &&
2281                     li[this.TYPE] == eventName) {
2282                     return i;
2283                 }
2284             }
2285
2286             return -1;
2287         },
2288
2289
2290         elCache: {},
2291
2292
2293         getEl: function(id) {
2294             return document.getElementById(id);
2295         },
2296
2297
2298         clearCache: function() {
2299         },
2300
2301
2302         _load: function(e) {
2303             loadComplete = true;
2304             var EU = Roo.lib.Event;
2305
2306
2307             if (Roo.isIE) {
2308                 EU.doRemove(window, "load", EU._load);
2309             }
2310         },
2311
2312
2313         _tryPreloadAttach: function() {
2314
2315             if (this.locked) {
2316                 return false;
2317             }
2318
2319             this.locked = true;
2320
2321
2322             var tryAgain = !loadComplete;
2323             if (!tryAgain) {
2324                 tryAgain = (retryCount > 0);
2325             }
2326
2327
2328             var notAvail = [];
2329             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2330                 var item = onAvailStack[i];
2331                 if (item) {
2332                     var el = this.getEl(item.id);
2333
2334                     if (el) {
2335                         if (!item.checkReady ||
2336                             loadComplete ||
2337                             el.nextSibling ||
2338                             (document && document.body)) {
2339
2340                             var scope = el;
2341                             if (item.override) {
2342                                 if (item.override === true) {
2343                                     scope = item.obj;
2344                                 } else {
2345                                     scope = item.override;
2346                                 }
2347                             }
2348                             item.fn.call(scope, item.obj);
2349                             onAvailStack[i] = null;
2350                         }
2351                     } else {
2352                         notAvail.push(item);
2353                     }
2354                 }
2355             }
2356
2357             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2358
2359             if (tryAgain) {
2360
2361                 this.startInterval();
2362             } else {
2363                 clearInterval(this._interval);
2364                 this._interval = null;
2365             }
2366
2367             this.locked = false;
2368
2369             return true;
2370
2371         },
2372
2373
2374         purgeElement: function(el, recurse, eventName) {
2375             var elListeners = this.getListeners(el, eventName);
2376             if (elListeners) {
2377                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2378                     var l = elListeners[i];
2379                     this.removeListener(el, l.type, l.fn);
2380                 }
2381             }
2382
2383             if (recurse && el && el.childNodes) {
2384                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2385                     this.purgeElement(el.childNodes[i], recurse, eventName);
2386                 }
2387             }
2388         },
2389
2390
2391         getListeners: function(el, eventName) {
2392             var results = [], searchLists;
2393             if (!eventName) {
2394                 searchLists = [listeners, unloadListeners];
2395             } else if (eventName == "unload") {
2396                 searchLists = [unloadListeners];
2397             } else {
2398                 searchLists = [listeners];
2399             }
2400
2401             for (var j = 0; j < searchLists.length; ++j) {
2402                 var searchList = searchLists[j];
2403                 if (searchList && searchList.length > 0) {
2404                     for (var i = 0,len = searchList.length; i < len; ++i) {
2405                         var l = searchList[i];
2406                         if (l && l[this.EL] === el &&
2407                             (!eventName || eventName === l[this.TYPE])) {
2408                             results.push({
2409                                 type:   l[this.TYPE],
2410                                 fn:     l[this.FN],
2411                                 obj:    l[this.OBJ],
2412                                 adjust: l[this.ADJ_SCOPE],
2413                                 index:  i
2414                             });
2415                         }
2416                     }
2417                 }
2418             }
2419
2420             return (results.length) ? results : null;
2421         },
2422
2423
2424         _unload: function(e) {
2425
2426             var EU = Roo.lib.Event, i, j, l, len, index;
2427
2428             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2429                 l = unloadListeners[i];
2430                 if (l) {
2431                     var scope = window;
2432                     if (l[EU.ADJ_SCOPE]) {
2433                         if (l[EU.ADJ_SCOPE] === true) {
2434                             scope = l[EU.OBJ];
2435                         } else {
2436                             scope = l[EU.ADJ_SCOPE];
2437                         }
2438                     }
2439                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2440                     unloadListeners[i] = null;
2441                     l = null;
2442                     scope = null;
2443                 }
2444             }
2445
2446             unloadListeners = null;
2447
2448             if (listeners && listeners.length > 0) {
2449                 j = listeners.length;
2450                 while (j) {
2451                     index = j - 1;
2452                     l = listeners[index];
2453                     if (l) {
2454                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2455                                 l[EU.FN], index);
2456                     }
2457                     j = j - 1;
2458                 }
2459                 l = null;
2460
2461                 EU.clearCache();
2462             }
2463
2464             EU.doRemove(window, "unload", EU._unload);
2465
2466         },
2467
2468
2469         getScroll: function() {
2470             var dd = document.documentElement, db = document.body;
2471             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2472                 return [dd.scrollTop, dd.scrollLeft];
2473             } else if (db) {
2474                 return [db.scrollTop, db.scrollLeft];
2475             } else {
2476                 return [0, 0];
2477             }
2478         },
2479
2480
2481         doAdd: function () {
2482             if (window.addEventListener) {
2483                 return function(el, eventName, fn, capture) {
2484                     el.addEventListener(eventName, fn, (capture));
2485                 };
2486             } else if (window.attachEvent) {
2487                 return function(el, eventName, fn, capture) {
2488                     el.attachEvent("on" + eventName, fn);
2489                 };
2490             } else {
2491                 return function() {
2492                 };
2493             }
2494         }(),
2495
2496
2497         doRemove: function() {
2498             if (window.removeEventListener) {
2499                 return function (el, eventName, fn, capture) {
2500                     el.removeEventListener(eventName, fn, (capture));
2501                 };
2502             } else if (window.detachEvent) {
2503                 return function (el, eventName, fn) {
2504                     el.detachEvent("on" + eventName, fn);
2505                 };
2506             } else {
2507                 return function() {
2508                 };
2509             }
2510         }()
2511     };
2512     
2513 }();
2514 (function() {     
2515    
2516     var E = Roo.lib.Event;
2517     E.on = E.addListener;
2518     E.un = E.removeListener;
2519
2520     if (document && document.body) {
2521         E._load();
2522     } else {
2523         E.doAdd(window, "load", E._load);
2524     }
2525     E.doAdd(window, "unload", E._unload);
2526     E._tryPreloadAttach();
2527 })();
2528
2529 /*
2530  * Portions of this file are based on pieces of Yahoo User Interface Library
2531  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2532  * YUI licensed under the BSD License:
2533  * http://developer.yahoo.net/yui/license.txt
2534  * <script type="text/javascript">
2535  *
2536  */
2537
2538 (function() {
2539     /**
2540      * @class Roo.lib.Ajax
2541      *
2542      */
2543     Roo.lib.Ajax = {
2544         /**
2545          * @static 
2546          */
2547         request : function(method, uri, cb, data, options) {
2548             if(options){
2549                 var hs = options.headers;
2550                 if(hs){
2551                     for(var h in hs){
2552                         if(hs.hasOwnProperty(h)){
2553                             this.initHeader(h, hs[h], false);
2554                         }
2555                     }
2556                 }
2557                 if(options.xmlData){
2558                     this.initHeader('Content-Type', 'text/xml', false);
2559                     method = 'POST';
2560                     data = options.xmlData;
2561                 }
2562             }
2563
2564             return this.asyncRequest(method, uri, cb, data);
2565         },
2566
2567         serializeForm : function(form) {
2568             if(typeof form == 'string') {
2569                 form = (document.getElementById(form) || document.forms[form]);
2570             }
2571
2572             var el, name, val, disabled, data = '', hasSubmit = false;
2573             for (var i = 0; i < form.elements.length; i++) {
2574                 el = form.elements[i];
2575                 disabled = form.elements[i].disabled;
2576                 name = form.elements[i].name;
2577                 val = form.elements[i].value;
2578
2579                 if (!disabled && name){
2580                     switch (el.type)
2581                             {
2582                         case 'select-one':
2583                         case 'select-multiple':
2584                             for (var j = 0; j < el.options.length; j++) {
2585                                 if (el.options[j].selected) {
2586                                     if (Roo.isIE) {
2587                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2588                                     }
2589                                     else {
2590                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2591                                     }
2592                                 }
2593                             }
2594                             break;
2595                         case 'radio':
2596                         case 'checkbox':
2597                             if (el.checked) {
2598                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2599                             }
2600                             break;
2601                         case 'file':
2602
2603                         case undefined:
2604
2605                         case 'reset':
2606
2607                         case 'button':
2608
2609                             break;
2610                         case 'submit':
2611                             if(hasSubmit == false) {
2612                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2613                                 hasSubmit = true;
2614                             }
2615                             break;
2616                         default:
2617                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2618                             break;
2619                     }
2620                 }
2621             }
2622             data = data.substr(0, data.length - 1);
2623             return data;
2624         },
2625
2626         headers:{},
2627
2628         hasHeaders:false,
2629
2630         useDefaultHeader:true,
2631
2632         defaultPostHeader:'application/x-www-form-urlencoded',
2633
2634         useDefaultXhrHeader:true,
2635
2636         defaultXhrHeader:'XMLHttpRequest',
2637
2638         hasDefaultHeaders:true,
2639
2640         defaultHeaders:{},
2641
2642         poll:{},
2643
2644         timeout:{},
2645
2646         pollInterval:50,
2647
2648         transactionId:0,
2649
2650         setProgId:function(id)
2651         {
2652             this.activeX.unshift(id);
2653         },
2654
2655         setDefaultPostHeader:function(b)
2656         {
2657             this.useDefaultHeader = b;
2658         },
2659
2660         setDefaultXhrHeader:function(b)
2661         {
2662             this.useDefaultXhrHeader = b;
2663         },
2664
2665         setPollingInterval:function(i)
2666         {
2667             if (typeof i == 'number' && isFinite(i)) {
2668                 this.pollInterval = i;
2669             }
2670         },
2671
2672         createXhrObject:function(transactionId)
2673         {
2674             var obj,http;
2675             try
2676             {
2677
2678                 http = new XMLHttpRequest();
2679
2680                 obj = { conn:http, tId:transactionId };
2681             }
2682             catch(e)
2683             {
2684                 for (var i = 0; i < this.activeX.length; ++i) {
2685                     try
2686                     {
2687
2688                         http = new ActiveXObject(this.activeX[i]);
2689
2690                         obj = { conn:http, tId:transactionId };
2691                         break;
2692                     }
2693                     catch(e) {
2694                     }
2695                 }
2696             }
2697             finally
2698             {
2699                 return obj;
2700             }
2701         },
2702
2703         getConnectionObject:function()
2704         {
2705             var o;
2706             var tId = this.transactionId;
2707
2708             try
2709             {
2710                 o = this.createXhrObject(tId);
2711                 if (o) {
2712                     this.transactionId++;
2713                 }
2714             }
2715             catch(e) {
2716             }
2717             finally
2718             {
2719                 return o;
2720             }
2721         },
2722
2723         asyncRequest:function(method, uri, callback, postData)
2724         {
2725             var o = this.getConnectionObject();
2726
2727             if (!o) {
2728                 return null;
2729             }
2730             else {
2731                 o.conn.open(method, uri, true);
2732
2733                 if (this.useDefaultXhrHeader) {
2734                     if (!this.defaultHeaders['X-Requested-With']) {
2735                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2736                     }
2737                 }
2738
2739                 if(postData && this.useDefaultHeader){
2740                     this.initHeader('Content-Type', this.defaultPostHeader);
2741                 }
2742
2743                  if (this.hasDefaultHeaders || this.hasHeaders) {
2744                     this.setHeader(o);
2745                 }
2746
2747                 this.handleReadyState(o, callback);
2748                 o.conn.send(postData || null);
2749
2750                 return o;
2751             }
2752         },
2753
2754         handleReadyState:function(o, callback)
2755         {
2756             var oConn = this;
2757
2758             if (callback && callback.timeout) {
2759                 
2760                 this.timeout[o.tId] = window.setTimeout(function() {
2761                     oConn.abort(o, callback, true);
2762                 }, callback.timeout);
2763             }
2764
2765             this.poll[o.tId] = window.setInterval(
2766                     function() {
2767                         if (o.conn && o.conn.readyState == 4) {
2768                             window.clearInterval(oConn.poll[o.tId]);
2769                             delete oConn.poll[o.tId];
2770
2771                             if(callback && callback.timeout) {
2772                                 window.clearTimeout(oConn.timeout[o.tId]);
2773                                 delete oConn.timeout[o.tId];
2774                             }
2775
2776                             oConn.handleTransactionResponse(o, callback);
2777                         }
2778                     }
2779                     , this.pollInterval);
2780         },
2781
2782         handleTransactionResponse:function(o, callback, isAbort)
2783         {
2784
2785             if (!callback) {
2786                 this.releaseObject(o);
2787                 return;
2788             }
2789
2790             var httpStatus, responseObject;
2791
2792             try
2793             {
2794                 if (o.conn.status !== undefined && o.conn.status != 0) {
2795                     httpStatus = o.conn.status;
2796                 }
2797                 else {
2798                     httpStatus = 13030;
2799                 }
2800             }
2801             catch(e) {
2802
2803
2804                 httpStatus = 13030;
2805             }
2806
2807             if (httpStatus >= 200 && httpStatus < 300) {
2808                 responseObject = this.createResponseObject(o, callback.argument);
2809                 if (callback.success) {
2810                     if (!callback.scope) {
2811                         callback.success(responseObject);
2812                     }
2813                     else {
2814
2815
2816                         callback.success.apply(callback.scope, [responseObject]);
2817                     }
2818                 }
2819             }
2820             else {
2821                 switch (httpStatus) {
2822
2823                     case 12002:
2824                     case 12029:
2825                     case 12030:
2826                     case 12031:
2827                     case 12152:
2828                     case 13030:
2829                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2830                         if (callback.failure) {
2831                             if (!callback.scope) {
2832                                 callback.failure(responseObject);
2833                             }
2834                             else {
2835                                 callback.failure.apply(callback.scope, [responseObject]);
2836                             }
2837                         }
2838                         break;
2839                     default:
2840                         responseObject = this.createResponseObject(o, callback.argument);
2841                         if (callback.failure) {
2842                             if (!callback.scope) {
2843                                 callback.failure(responseObject);
2844                             }
2845                             else {
2846                                 callback.failure.apply(callback.scope, [responseObject]);
2847                             }
2848                         }
2849                 }
2850             }
2851
2852             this.releaseObject(o);
2853             responseObject = null;
2854         },
2855
2856         createResponseObject:function(o, callbackArg)
2857         {
2858             var obj = {};
2859             var headerObj = {};
2860
2861             try
2862             {
2863                 var headerStr = o.conn.getAllResponseHeaders();
2864                 var header = headerStr.split('\n');
2865                 for (var i = 0; i < header.length; i++) {
2866                     var delimitPos = header[i].indexOf(':');
2867                     if (delimitPos != -1) {
2868                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2869                     }
2870                 }
2871             }
2872             catch(e) {
2873             }
2874
2875             obj.tId = o.tId;
2876             obj.status = o.conn.status;
2877             obj.statusText = o.conn.statusText;
2878             obj.getResponseHeader = headerObj;
2879             obj.getAllResponseHeaders = headerStr;
2880             obj.responseText = o.conn.responseText;
2881             obj.responseXML = o.conn.responseXML;
2882
2883             if (typeof callbackArg !== undefined) {
2884                 obj.argument = callbackArg;
2885             }
2886
2887             return obj;
2888         },
2889
2890         createExceptionObject:function(tId, callbackArg, isAbort)
2891         {
2892             var COMM_CODE = 0;
2893             var COMM_ERROR = 'communication failure';
2894             var ABORT_CODE = -1;
2895             var ABORT_ERROR = 'transaction aborted';
2896
2897             var obj = {};
2898
2899             obj.tId = tId;
2900             if (isAbort) {
2901                 obj.status = ABORT_CODE;
2902                 obj.statusText = ABORT_ERROR;
2903             }
2904             else {
2905                 obj.status = COMM_CODE;
2906                 obj.statusText = COMM_ERROR;
2907             }
2908
2909             if (callbackArg) {
2910                 obj.argument = callbackArg;
2911             }
2912
2913             return obj;
2914         },
2915
2916         initHeader:function(label, value, isDefault)
2917         {
2918             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2919
2920             if (headerObj[label] === undefined) {
2921                 headerObj[label] = value;
2922             }
2923             else {
2924
2925
2926                 headerObj[label] = value + "," + headerObj[label];
2927             }
2928
2929             if (isDefault) {
2930                 this.hasDefaultHeaders = true;
2931             }
2932             else {
2933                 this.hasHeaders = true;
2934             }
2935         },
2936
2937
2938         setHeader:function(o)
2939         {
2940             if (this.hasDefaultHeaders) {
2941                 for (var prop in this.defaultHeaders) {
2942                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2943                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2944                     }
2945                 }
2946             }
2947
2948             if (this.hasHeaders) {
2949                 for (var prop in this.headers) {
2950                     if (this.headers.hasOwnProperty(prop)) {
2951                         o.conn.setRequestHeader(prop, this.headers[prop]);
2952                     }
2953                 }
2954                 this.headers = {};
2955                 this.hasHeaders = false;
2956             }
2957         },
2958
2959         resetDefaultHeaders:function() {
2960             delete this.defaultHeaders;
2961             this.defaultHeaders = {};
2962             this.hasDefaultHeaders = false;
2963         },
2964
2965         abort:function(o, callback, isTimeout)
2966         {
2967             if(this.isCallInProgress(o)) {
2968                 o.conn.abort();
2969                 window.clearInterval(this.poll[o.tId]);
2970                 delete this.poll[o.tId];
2971                 if (isTimeout) {
2972                     delete this.timeout[o.tId];
2973                 }
2974
2975                 this.handleTransactionResponse(o, callback, true);
2976
2977                 return true;
2978             }
2979             else {
2980                 return false;
2981             }
2982         },
2983
2984
2985         isCallInProgress:function(o)
2986         {
2987             if (o && o.conn) {
2988                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2989             }
2990             else {
2991
2992                 return false;
2993             }
2994         },
2995
2996
2997         releaseObject:function(o)
2998         {
2999
3000             o.conn = null;
3001
3002             o = null;
3003         },
3004
3005         activeX:[
3006         'MSXML2.XMLHTTP.3.0',
3007         'MSXML2.XMLHTTP',
3008         'Microsoft.XMLHTTP'
3009         ]
3010
3011
3012     };
3013 })();/*
3014  * Portions of this file are based on pieces of Yahoo User Interface Library
3015  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3016  * YUI licensed under the BSD License:
3017  * http://developer.yahoo.net/yui/license.txt
3018  * <script type="text/javascript">
3019  *
3020  */
3021
3022 Roo.lib.Region = function(t, r, b, l) {
3023     this.top = t;
3024     this[1] = t;
3025     this.right = r;
3026     this.bottom = b;
3027     this.left = l;
3028     this[0] = l;
3029 };
3030
3031
3032 Roo.lib.Region.prototype = {
3033     contains : function(region) {
3034         return ( region.left >= this.left &&
3035                  region.right <= this.right &&
3036                  region.top >= this.top &&
3037                  region.bottom <= this.bottom    );
3038
3039     },
3040
3041     getArea : function() {
3042         return ( (this.bottom - this.top) * (this.right - this.left) );
3043     },
3044
3045     intersect : function(region) {
3046         var t = Math.max(this.top, region.top);
3047         var r = Math.min(this.right, region.right);
3048         var b = Math.min(this.bottom, region.bottom);
3049         var l = Math.max(this.left, region.left);
3050
3051         if (b >= t && r >= l) {
3052             return new Roo.lib.Region(t, r, b, l);
3053         } else {
3054             return null;
3055         }
3056     },
3057     union : function(region) {
3058         var t = Math.min(this.top, region.top);
3059         var r = Math.max(this.right, region.right);
3060         var b = Math.max(this.bottom, region.bottom);
3061         var l = Math.min(this.left, region.left);
3062
3063         return new Roo.lib.Region(t, r, b, l);
3064     },
3065
3066     adjust : function(t, l, b, r) {
3067         this.top += t;
3068         this.left += l;
3069         this.right += r;
3070         this.bottom += b;
3071         return this;
3072     }
3073 };
3074
3075 Roo.lib.Region.getRegion = function(el) {
3076     var p = Roo.lib.Dom.getXY(el);
3077
3078     var t = p[1];
3079     var r = p[0] + el.offsetWidth;
3080     var b = p[1] + el.offsetHeight;
3081     var l = p[0];
3082
3083     return new Roo.lib.Region(t, r, b, l);
3084 };
3085 /*
3086  * Portions of this file are based on pieces of Yahoo User Interface Library
3087  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3088  * YUI licensed under the BSD License:
3089  * http://developer.yahoo.net/yui/license.txt
3090  * <script type="text/javascript">
3091  *
3092  */
3093 //@@dep Roo.lib.Region
3094
3095
3096 Roo.lib.Point = function(x, y) {
3097     if (x instanceof Array) {
3098         y = x[1];
3099         x = x[0];
3100     }
3101     this.x = this.right = this.left = this[0] = x;
3102     this.y = this.top = this.bottom = this[1] = y;
3103 };
3104
3105 Roo.lib.Point.prototype = new Roo.lib.Region();
3106 /*
3107  * Portions of this file are based on pieces of Yahoo User Interface Library
3108  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3109  * YUI licensed under the BSD License:
3110  * http://developer.yahoo.net/yui/license.txt
3111  * <script type="text/javascript">
3112  *
3113  */
3114  
3115 (function() {   
3116
3117     Roo.lib.Anim = {
3118         scroll : function(el, args, duration, easing, cb, scope) {
3119             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3120         },
3121
3122         motion : function(el, args, duration, easing, cb, scope) {
3123             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3124         },
3125
3126         color : function(el, args, duration, easing, cb, scope) {
3127             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3128         },
3129
3130         run : function(el, args, duration, easing, cb, scope, type) {
3131             type = type || Roo.lib.AnimBase;
3132             if (typeof easing == "string") {
3133                 easing = Roo.lib.Easing[easing];
3134             }
3135             var anim = new type(el, args, duration, easing);
3136             anim.animateX(function() {
3137                 Roo.callback(cb, scope);
3138             });
3139             return anim;
3140         }
3141     };
3142 })();/*
3143  * Portions of this file are based on pieces of Yahoo User Interface Library
3144  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3145  * YUI licensed under the BSD License:
3146  * http://developer.yahoo.net/yui/license.txt
3147  * <script type="text/javascript">
3148  *
3149  */
3150
3151 (function() {    
3152     var libFlyweight;
3153     
3154     function fly(el) {
3155         if (!libFlyweight) {
3156             libFlyweight = new Roo.Element.Flyweight();
3157         }
3158         libFlyweight.dom = el;
3159         return libFlyweight;
3160     }
3161
3162     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3163     
3164    
3165     
3166     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3167         if (el) {
3168             this.init(el, attributes, duration, method);
3169         }
3170     };
3171
3172     Roo.lib.AnimBase.fly = fly;
3173     
3174     
3175     
3176     Roo.lib.AnimBase.prototype = {
3177
3178         toString: function() {
3179             var el = this.getEl();
3180             var id = el.id || el.tagName;
3181             return ("Anim " + id);
3182         },
3183
3184         patterns: {
3185             noNegatives:        /width|height|opacity|padding/i,
3186             offsetAttribute:  /^((width|height)|(top|left))$/,
3187             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3188             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3189         },
3190
3191
3192         doMethod: function(attr, start, end) {
3193             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3194         },
3195
3196
3197         setAttribute: function(attr, val, unit) {
3198             if (this.patterns.noNegatives.test(attr)) {
3199                 val = (val > 0) ? val : 0;
3200             }
3201
3202             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3203         },
3204
3205
3206         getAttribute: function(attr) {
3207             var el = this.getEl();
3208             var val = fly(el).getStyle(attr);
3209
3210             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3211                 return parseFloat(val);
3212             }
3213
3214             var a = this.patterns.offsetAttribute.exec(attr) || [];
3215             var pos = !!( a[3] );
3216             var box = !!( a[2] );
3217
3218
3219             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3220                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3221             } else {
3222                 val = 0;
3223             }
3224
3225             return val;
3226         },
3227
3228
3229         getDefaultUnit: function(attr) {
3230             if (this.patterns.defaultUnit.test(attr)) {
3231                 return 'px';
3232             }
3233
3234             return '';
3235         },
3236
3237         animateX : function(callback, scope) {
3238             var f = function() {
3239                 this.onComplete.removeListener(f);
3240                 if (typeof callback == "function") {
3241                     callback.call(scope || this, this);
3242                 }
3243             };
3244             this.onComplete.addListener(f, this);
3245             this.animate();
3246         },
3247
3248
3249         setRuntimeAttribute: function(attr) {
3250             var start;
3251             var end;
3252             var attributes = this.attributes;
3253
3254             this.runtimeAttributes[attr] = {};
3255
3256             var isset = function(prop) {
3257                 return (typeof prop !== 'undefined');
3258             };
3259
3260             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3261                 return false;
3262             }
3263
3264             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3265
3266
3267             if (isset(attributes[attr]['to'])) {
3268                 end = attributes[attr]['to'];
3269             } else if (isset(attributes[attr]['by'])) {
3270                 if (start.constructor == Array) {
3271                     end = [];
3272                     for (var i = 0, len = start.length; i < len; ++i) {
3273                         end[i] = start[i] + attributes[attr]['by'][i];
3274                     }
3275                 } else {
3276                     end = start + attributes[attr]['by'];
3277                 }
3278             }
3279
3280             this.runtimeAttributes[attr].start = start;
3281             this.runtimeAttributes[attr].end = end;
3282
3283
3284             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3285         },
3286
3287
3288         init: function(el, attributes, duration, method) {
3289
3290             var isAnimated = false;
3291
3292
3293             var startTime = null;
3294
3295
3296             var actualFrames = 0;
3297
3298
3299             el = Roo.getDom(el);
3300
3301
3302             this.attributes = attributes || {};
3303
3304
3305             this.duration = duration || 1;
3306
3307
3308             this.method = method || Roo.lib.Easing.easeNone;
3309
3310
3311             this.useSeconds = true;
3312
3313
3314             this.currentFrame = 0;
3315
3316
3317             this.totalFrames = Roo.lib.AnimMgr.fps;
3318
3319
3320             this.getEl = function() {
3321                 return el;
3322             };
3323
3324
3325             this.isAnimated = function() {
3326                 return isAnimated;
3327             };
3328
3329
3330             this.getStartTime = function() {
3331                 return startTime;
3332             };
3333
3334             this.runtimeAttributes = {};
3335
3336
3337             this.animate = function() {
3338                 if (this.isAnimated()) {
3339                     return false;
3340                 }
3341
3342                 this.currentFrame = 0;
3343
3344                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3345
3346                 Roo.lib.AnimMgr.registerElement(this);
3347             };
3348
3349
3350             this.stop = function(finish) {
3351                 if (finish) {
3352                     this.currentFrame = this.totalFrames;
3353                     this._onTween.fire();
3354                 }
3355                 Roo.lib.AnimMgr.stop(this);
3356             };
3357
3358             var onStart = function() {
3359                 this.onStart.fire();
3360
3361                 this.runtimeAttributes = {};
3362                 for (var attr in this.attributes) {
3363                     this.setRuntimeAttribute(attr);
3364                 }
3365
3366                 isAnimated = true;
3367                 actualFrames = 0;
3368                 startTime = new Date();
3369             };
3370
3371
3372             var onTween = function() {
3373                 var data = {
3374                     duration: new Date() - this.getStartTime(),
3375                     currentFrame: this.currentFrame
3376                 };
3377
3378                 data.toString = function() {
3379                     return (
3380                             'duration: ' + data.duration +
3381                             ', currentFrame: ' + data.currentFrame
3382                             );
3383                 };
3384
3385                 this.onTween.fire(data);
3386
3387                 var runtimeAttributes = this.runtimeAttributes;
3388
3389                 for (var attr in runtimeAttributes) {
3390                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3391                 }
3392
3393                 actualFrames += 1;
3394             };
3395
3396             var onComplete = function() {
3397                 var actual_duration = (new Date() - startTime) / 1000 ;
3398
3399                 var data = {
3400                     duration: actual_duration,
3401                     frames: actualFrames,
3402                     fps: actualFrames / actual_duration
3403                 };
3404
3405                 data.toString = function() {
3406                     return (
3407                             'duration: ' + data.duration +
3408                             ', frames: ' + data.frames +
3409                             ', fps: ' + data.fps
3410                             );
3411                 };
3412
3413                 isAnimated = false;
3414                 actualFrames = 0;
3415                 this.onComplete.fire(data);
3416             };
3417
3418
3419             this._onStart = new Roo.util.Event(this);
3420             this.onStart = new Roo.util.Event(this);
3421             this.onTween = new Roo.util.Event(this);
3422             this._onTween = new Roo.util.Event(this);
3423             this.onComplete = new Roo.util.Event(this);
3424             this._onComplete = new Roo.util.Event(this);
3425             this._onStart.addListener(onStart);
3426             this._onTween.addListener(onTween);
3427             this._onComplete.addListener(onComplete);
3428         }
3429     };
3430 })();
3431 /*
3432  * Portions of this file are based on pieces of Yahoo User Interface Library
3433  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3434  * YUI licensed under the BSD License:
3435  * http://developer.yahoo.net/yui/license.txt
3436  * <script type="text/javascript">
3437  *
3438  */
3439
3440 Roo.lib.AnimMgr = new function() {
3441
3442     var thread = null;
3443
3444
3445     var queue = [];
3446
3447
3448     var tweenCount = 0;
3449
3450
3451     this.fps = 1000;
3452
3453
3454     this.delay = 1;
3455
3456
3457     this.registerElement = function(tween) {
3458         queue[queue.length] = tween;
3459         tweenCount += 1;
3460         tween._onStart.fire();
3461         this.start();
3462     };
3463
3464
3465     this.unRegister = function(tween, index) {
3466         tween._onComplete.fire();
3467         index = index || getIndex(tween);
3468         if (index != -1) {
3469             queue.splice(index, 1);
3470         }
3471
3472         tweenCount -= 1;
3473         if (tweenCount <= 0) {
3474             this.stop();
3475         }
3476     };
3477
3478
3479     this.start = function() {
3480         if (thread === null) {
3481             thread = setInterval(this.run, this.delay);
3482         }
3483     };
3484
3485
3486     this.stop = function(tween) {
3487         if (!tween) {
3488             clearInterval(thread);
3489
3490             for (var i = 0, len = queue.length; i < len; ++i) {
3491                 if (queue[0].isAnimated()) {
3492                     this.unRegister(queue[0], 0);
3493                 }
3494             }
3495
3496             queue = [];
3497             thread = null;
3498             tweenCount = 0;
3499         }
3500         else {
3501             this.unRegister(tween);
3502         }
3503     };
3504
3505
3506     this.run = function() {
3507         for (var i = 0, len = queue.length; i < len; ++i) {
3508             var tween = queue[i];
3509             if (!tween || !tween.isAnimated()) {
3510                 continue;
3511             }
3512
3513             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3514             {
3515                 tween.currentFrame += 1;
3516
3517                 if (tween.useSeconds) {
3518                     correctFrame(tween);
3519                 }
3520                 tween._onTween.fire();
3521             }
3522             else {
3523                 Roo.lib.AnimMgr.stop(tween, i);
3524             }
3525         }
3526     };
3527
3528     var getIndex = function(anim) {
3529         for (var i = 0, len = queue.length; i < len; ++i) {
3530             if (queue[i] == anim) {
3531                 return i;
3532             }
3533         }
3534         return -1;
3535     };
3536
3537
3538     var correctFrame = function(tween) {
3539         var frames = tween.totalFrames;
3540         var frame = tween.currentFrame;
3541         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3542         var elapsed = (new Date() - tween.getStartTime());
3543         var tweak = 0;
3544
3545         if (elapsed < tween.duration * 1000) {
3546             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3547         } else {
3548             tweak = frames - (frame + 1);
3549         }
3550         if (tweak > 0 && isFinite(tweak)) {
3551             if (tween.currentFrame + tweak >= frames) {
3552                 tweak = frames - (frame + 1);
3553             }
3554
3555             tween.currentFrame += tweak;
3556         }
3557     };
3558 };
3559
3560     /*
3561  * Portions of this file are based on pieces of Yahoo User Interface Library
3562  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3563  * YUI licensed under the BSD License:
3564  * http://developer.yahoo.net/yui/license.txt
3565  * <script type="text/javascript">
3566  *
3567  */
3568 Roo.lib.Bezier = new function() {
3569
3570         this.getPosition = function(points, t) {
3571             var n = points.length;
3572             var tmp = [];
3573
3574             for (var i = 0; i < n; ++i) {
3575                 tmp[i] = [points[i][0], points[i][1]];
3576             }
3577
3578             for (var j = 1; j < n; ++j) {
3579                 for (i = 0; i < n - j; ++i) {
3580                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3581                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3582                 }
3583             }
3584
3585             return [ tmp[0][0], tmp[0][1] ];
3586
3587         };
3588     };/*
3589  * Portions of this file are based on pieces of Yahoo User Interface Library
3590  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3591  * YUI licensed under the BSD License:
3592  * http://developer.yahoo.net/yui/license.txt
3593  * <script type="text/javascript">
3594  *
3595  */
3596 (function() {
3597
3598     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3599         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3600     };
3601
3602     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3603
3604     var fly = Roo.lib.AnimBase.fly;
3605     var Y = Roo.lib;
3606     var superclass = Y.ColorAnim.superclass;
3607     var proto = Y.ColorAnim.prototype;
3608
3609     proto.toString = function() {
3610         var el = this.getEl();
3611         var id = el.id || el.tagName;
3612         return ("ColorAnim " + id);
3613     };
3614
3615     proto.patterns.color = /color$/i;
3616     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3617     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3618     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3619     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3620
3621
3622     proto.parseColor = function(s) {
3623         if (s.length == 3) {
3624             return s;
3625         }
3626
3627         var c = this.patterns.hex.exec(s);
3628         if (c && c.length == 4) {
3629             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3630         }
3631
3632         c = this.patterns.rgb.exec(s);
3633         if (c && c.length == 4) {
3634             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3635         }
3636
3637         c = this.patterns.hex3.exec(s);
3638         if (c && c.length == 4) {
3639             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3640         }
3641
3642         return null;
3643     };
3644     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3645     proto.getAttribute = function(attr) {
3646         var el = this.getEl();
3647         if (this.patterns.color.test(attr)) {
3648             var val = fly(el).getStyle(attr);
3649
3650             if (this.patterns.transparent.test(val)) {
3651                 var parent = el.parentNode;
3652                 val = fly(parent).getStyle(attr);
3653
3654                 while (parent && this.patterns.transparent.test(val)) {
3655                     parent = parent.parentNode;
3656                     val = fly(parent).getStyle(attr);
3657                     if (parent.tagName.toUpperCase() == 'HTML') {
3658                         val = '#fff';
3659                     }
3660                 }
3661             }
3662         } else {
3663             val = superclass.getAttribute.call(this, attr);
3664         }
3665
3666         return val;
3667     };
3668     proto.getAttribute = function(attr) {
3669         var el = this.getEl();
3670         if (this.patterns.color.test(attr)) {
3671             var val = fly(el).getStyle(attr);
3672
3673             if (this.patterns.transparent.test(val)) {
3674                 var parent = el.parentNode;
3675                 val = fly(parent).getStyle(attr);
3676
3677                 while (parent && this.patterns.transparent.test(val)) {
3678                     parent = parent.parentNode;
3679                     val = fly(parent).getStyle(attr);
3680                     if (parent.tagName.toUpperCase() == 'HTML') {
3681                         val = '#fff';
3682                     }
3683                 }
3684             }
3685         } else {
3686             val = superclass.getAttribute.call(this, attr);
3687         }
3688
3689         return val;
3690     };
3691
3692     proto.doMethod = function(attr, start, end) {
3693         var val;
3694
3695         if (this.patterns.color.test(attr)) {
3696             val = [];
3697             for (var i = 0, len = start.length; i < len; ++i) {
3698                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3699             }
3700
3701             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3702         }
3703         else {
3704             val = superclass.doMethod.call(this, attr, start, end);
3705         }
3706
3707         return val;
3708     };
3709
3710     proto.setRuntimeAttribute = function(attr) {
3711         superclass.setRuntimeAttribute.call(this, attr);
3712
3713         if (this.patterns.color.test(attr)) {
3714             var attributes = this.attributes;
3715             var start = this.parseColor(this.runtimeAttributes[attr].start);
3716             var end = this.parseColor(this.runtimeAttributes[attr].end);
3717
3718             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3719                 end = this.parseColor(attributes[attr].by);
3720
3721                 for (var i = 0, len = start.length; i < len; ++i) {
3722                     end[i] = start[i] + end[i];
3723                 }
3724             }
3725
3726             this.runtimeAttributes[attr].start = start;
3727             this.runtimeAttributes[attr].end = end;
3728         }
3729     };
3730 })();
3731
3732 /*
3733  * Portions of this file are based on pieces of Yahoo User Interface Library
3734  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3735  * YUI licensed under the BSD License:
3736  * http://developer.yahoo.net/yui/license.txt
3737  * <script type="text/javascript">
3738  *
3739  */
3740 Roo.lib.Easing = {
3741
3742
3743     easeNone: function (t, b, c, d) {
3744         return c * t / d + b;
3745     },
3746
3747
3748     easeIn: function (t, b, c, d) {
3749         return c * (t /= d) * t + b;
3750     },
3751
3752
3753     easeOut: function (t, b, c, d) {
3754         return -c * (t /= d) * (t - 2) + b;
3755     },
3756
3757
3758     easeBoth: function (t, b, c, d) {
3759         if ((t /= d / 2) < 1) {
3760             return c / 2 * t * t + b;
3761         }
3762
3763         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3764     },
3765
3766
3767     easeInStrong: function (t, b, c, d) {
3768         return c * (t /= d) * t * t * t + b;
3769     },
3770
3771
3772     easeOutStrong: function (t, b, c, d) {
3773         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3774     },
3775
3776
3777     easeBothStrong: function (t, b, c, d) {
3778         if ((t /= d / 2) < 1) {
3779             return c / 2 * t * t * t * t + b;
3780         }
3781
3782         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3783     },
3784
3785
3786
3787     elasticIn: function (t, b, c, d, a, p) {
3788         if (t == 0) {
3789             return b;
3790         }
3791         if ((t /= d) == 1) {
3792             return b + c;
3793         }
3794         if (!p) {
3795             p = d * .3;
3796         }
3797
3798         if (!a || a < Math.abs(c)) {
3799             a = c;
3800             var s = p / 4;
3801         }
3802         else {
3803             var s = p / (2 * Math.PI) * Math.asin(c / a);
3804         }
3805
3806         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3807     },
3808
3809
3810     elasticOut: function (t, b, c, d, a, p) {
3811         if (t == 0) {
3812             return b;
3813         }
3814         if ((t /= d) == 1) {
3815             return b + c;
3816         }
3817         if (!p) {
3818             p = d * .3;
3819         }
3820
3821         if (!a || a < Math.abs(c)) {
3822             a = c;
3823             var s = p / 4;
3824         }
3825         else {
3826             var s = p / (2 * Math.PI) * Math.asin(c / a);
3827         }
3828
3829         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3830     },
3831
3832
3833     elasticBoth: function (t, b, c, d, a, p) {
3834         if (t == 0) {
3835             return b;
3836         }
3837
3838         if ((t /= d / 2) == 2) {
3839             return b + c;
3840         }
3841
3842         if (!p) {
3843             p = d * (.3 * 1.5);
3844         }
3845
3846         if (!a || a < Math.abs(c)) {
3847             a = c;
3848             var s = p / 4;
3849         }
3850         else {
3851             var s = p / (2 * Math.PI) * Math.asin(c / a);
3852         }
3853
3854         if (t < 1) {
3855             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3856                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3857         }
3858         return a * Math.pow(2, -10 * (t -= 1)) *
3859                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3860     },
3861
3862
3863
3864     backIn: function (t, b, c, d, s) {
3865         if (typeof s == 'undefined') {
3866             s = 1.70158;
3867         }
3868         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3869     },
3870
3871
3872     backOut: function (t, b, c, d, s) {
3873         if (typeof s == 'undefined') {
3874             s = 1.70158;
3875         }
3876         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3877     },
3878
3879
3880     backBoth: function (t, b, c, d, s) {
3881         if (typeof s == 'undefined') {
3882             s = 1.70158;
3883         }
3884
3885         if ((t /= d / 2 ) < 1) {
3886             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3887         }
3888         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3889     },
3890
3891
3892     bounceIn: function (t, b, c, d) {
3893         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3894     },
3895
3896
3897     bounceOut: function (t, b, c, d) {
3898         if ((t /= d) < (1 / 2.75)) {
3899             return c * (7.5625 * t * t) + b;
3900         } else if (t < (2 / 2.75)) {
3901             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3902         } else if (t < (2.5 / 2.75)) {
3903             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3904         }
3905         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3906     },
3907
3908
3909     bounceBoth: function (t, b, c, d) {
3910         if (t < d / 2) {
3911             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3912         }
3913         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3914     }
3915 };/*
3916  * Portions of this file are based on pieces of Yahoo User Interface Library
3917  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3918  * YUI licensed under the BSD License:
3919  * http://developer.yahoo.net/yui/license.txt
3920  * <script type="text/javascript">
3921  *
3922  */
3923     (function() {
3924         Roo.lib.Motion = function(el, attributes, duration, method) {
3925             if (el) {
3926                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3927             }
3928         };
3929
3930         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3931
3932
3933         var Y = Roo.lib;
3934         var superclass = Y.Motion.superclass;
3935         var proto = Y.Motion.prototype;
3936
3937         proto.toString = function() {
3938             var el = this.getEl();
3939             var id = el.id || el.tagName;
3940             return ("Motion " + id);
3941         };
3942
3943         proto.patterns.points = /^points$/i;
3944
3945         proto.setAttribute = function(attr, val, unit) {
3946             if (this.patterns.points.test(attr)) {
3947                 unit = unit || 'px';
3948                 superclass.setAttribute.call(this, 'left', val[0], unit);
3949                 superclass.setAttribute.call(this, 'top', val[1], unit);
3950             } else {
3951                 superclass.setAttribute.call(this, attr, val, unit);
3952             }
3953         };
3954
3955         proto.getAttribute = function(attr) {
3956             if (this.patterns.points.test(attr)) {
3957                 var val = [
3958                         superclass.getAttribute.call(this, 'left'),
3959                         superclass.getAttribute.call(this, 'top')
3960                         ];
3961             } else {
3962                 val = superclass.getAttribute.call(this, attr);
3963             }
3964
3965             return val;
3966         };
3967
3968         proto.doMethod = function(attr, start, end) {
3969             var val = null;
3970
3971             if (this.patterns.points.test(attr)) {
3972                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3973                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3974             } else {
3975                 val = superclass.doMethod.call(this, attr, start, end);
3976             }
3977             return val;
3978         };
3979
3980         proto.setRuntimeAttribute = function(attr) {
3981             if (this.patterns.points.test(attr)) {
3982                 var el = this.getEl();
3983                 var attributes = this.attributes;
3984                 var start;
3985                 var control = attributes['points']['control'] || [];
3986                 var end;
3987                 var i, len;
3988
3989                 if (control.length > 0 && !(control[0] instanceof Array)) {
3990                     control = [control];
3991                 } else {
3992                     var tmp = [];
3993                     for (i = 0,len = control.length; i < len; ++i) {
3994                         tmp[i] = control[i];
3995                     }
3996                     control = tmp;
3997                 }
3998
3999                 Roo.fly(el).position();
4000
4001                 if (isset(attributes['points']['from'])) {
4002                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
4003                 }
4004                 else {
4005                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4006                 }
4007
4008                 start = this.getAttribute('points');
4009
4010
4011                 if (isset(attributes['points']['to'])) {
4012                     end = translateValues.call(this, attributes['points']['to'], start);
4013
4014                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4015                     for (i = 0,len = control.length; i < len; ++i) {
4016                         control[i] = translateValues.call(this, control[i], start);
4017                     }
4018
4019
4020                 } else if (isset(attributes['points']['by'])) {
4021                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4022
4023                     for (i = 0,len = control.length; i < len; ++i) {
4024                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4025                     }
4026                 }
4027
4028                 this.runtimeAttributes[attr] = [start];
4029
4030                 if (control.length > 0) {
4031                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4032                 }
4033
4034                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4035             }
4036             else {
4037                 superclass.setRuntimeAttribute.call(this, attr);
4038             }
4039         };
4040
4041         var translateValues = function(val, start) {
4042             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4043             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4044
4045             return val;
4046         };
4047
4048         var isset = function(prop) {
4049             return (typeof prop !== 'undefined');
4050         };
4051     })();
4052 /*
4053  * Portions of this file are based on pieces of Yahoo User Interface Library
4054  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4055  * YUI licensed under the BSD License:
4056  * http://developer.yahoo.net/yui/license.txt
4057  * <script type="text/javascript">
4058  *
4059  */
4060     (function() {
4061         Roo.lib.Scroll = function(el, attributes, duration, method) {
4062             if (el) {
4063                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4064             }
4065         };
4066
4067         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4068
4069
4070         var Y = Roo.lib;
4071         var superclass = Y.Scroll.superclass;
4072         var proto = Y.Scroll.prototype;
4073
4074         proto.toString = function() {
4075             var el = this.getEl();
4076             var id = el.id || el.tagName;
4077             return ("Scroll " + id);
4078         };
4079
4080         proto.doMethod = function(attr, start, end) {
4081             var val = null;
4082
4083             if (attr == 'scroll') {
4084                 val = [
4085                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4086                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4087                         ];
4088
4089             } else {
4090                 val = superclass.doMethod.call(this, attr, start, end);
4091             }
4092             return val;
4093         };
4094
4095         proto.getAttribute = function(attr) {
4096             var val = null;
4097             var el = this.getEl();
4098
4099             if (attr == 'scroll') {
4100                 val = [ el.scrollLeft, el.scrollTop ];
4101             } else {
4102                 val = superclass.getAttribute.call(this, attr);
4103             }
4104
4105             return val;
4106         };
4107
4108         proto.setAttribute = function(attr, val, unit) {
4109             var el = this.getEl();
4110
4111             if (attr == 'scroll') {
4112                 el.scrollLeft = val[0];
4113                 el.scrollTop = val[1];
4114             } else {
4115                 superclass.setAttribute.call(this, attr, val, unit);
4116             }
4117         };
4118     })();
4119 /*
4120  * Based on:
4121  * Ext JS Library 1.1.1
4122  * Copyright(c) 2006-2007, Ext JS, LLC.
4123  *
4124  * Originally Released Under LGPL - original licence link has changed is not relivant.
4125  *
4126  * Fork - LGPL
4127  * <script type="text/javascript">
4128  */
4129
4130
4131 // nasty IE9 hack - what a pile of crap that is..
4132
4133  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4134     Range.prototype.createContextualFragment = function (html) {
4135         var doc = window.document;
4136         var container = doc.createElement("div");
4137         container.innerHTML = html;
4138         var frag = doc.createDocumentFragment(), n;
4139         while ((n = container.firstChild)) {
4140             frag.appendChild(n);
4141         }
4142         return frag;
4143     };
4144 }
4145
4146 /**
4147  * @class Roo.DomHelper
4148  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4149  * 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>.
4150  * @singleton
4151  */
4152 Roo.DomHelper = function(){
4153     var tempTableEl = null;
4154     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4155     var tableRe = /^table|tbody|tr|td$/i;
4156     var xmlns = {};
4157     // build as innerHTML where available
4158     /** @ignore */
4159     var createHtml = function(o){
4160         if(typeof o == 'string'){
4161             return o;
4162         }
4163         var b = "";
4164         if(!o.tag){
4165             o.tag = "div";
4166         }
4167         b += "<" + o.tag;
4168         for(var attr in o){
4169             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4170             if(attr == "style"){
4171                 var s = o["style"];
4172                 if(typeof s == "function"){
4173                     s = s.call();
4174                 }
4175                 if(typeof s == "string"){
4176                     b += ' style="' + s + '"';
4177                 }else if(typeof s == "object"){
4178                     b += ' style="';
4179                     for(var key in s){
4180                         if(typeof s[key] != "function"){
4181                             b += key + ":" + s[key] + ";";
4182                         }
4183                     }
4184                     b += '"';
4185                 }
4186             }else{
4187                 if(attr == "cls"){
4188                     b += ' class="' + o["cls"] + '"';
4189                 }else if(attr == "htmlFor"){
4190                     b += ' for="' + o["htmlFor"] + '"';
4191                 }else{
4192                     b += " " + attr + '="' + o[attr] + '"';
4193                 }
4194             }
4195         }
4196         if(emptyTags.test(o.tag)){
4197             b += "/>";
4198         }else{
4199             b += ">";
4200             var cn = o.children || o.cn;
4201             if(cn){
4202                 //http://bugs.kde.org/show_bug.cgi?id=71506
4203                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4204                     for(var i = 0, len = cn.length; i < len; i++) {
4205                         b += createHtml(cn[i], b);
4206                     }
4207                 }else{
4208                     b += createHtml(cn, b);
4209                 }
4210             }
4211             if(o.html){
4212                 b += o.html;
4213             }
4214             b += "</" + o.tag + ">";
4215         }
4216         return b;
4217     };
4218
4219     // build as dom
4220     /** @ignore */
4221     var createDom = function(o, parentNode){
4222          
4223         // defininition craeted..
4224         var ns = false;
4225         if (o.ns && o.ns != 'html') {
4226                
4227             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4228                 xmlns[o.ns] = o.xmlns;
4229                 ns = o.xmlns;
4230             }
4231             if (typeof(xmlns[o.ns]) == 'undefined') {
4232                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4233             }
4234             ns = xmlns[o.ns];
4235         }
4236         
4237         
4238         if (typeof(o) == 'string') {
4239             return parentNode.appendChild(document.createTextNode(o));
4240         }
4241         o.tag = o.tag || div;
4242         if (o.ns && Roo.isIE) {
4243             ns = false;
4244             o.tag = o.ns + ':' + o.tag;
4245             
4246         }
4247         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4248         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4249         for(var attr in o){
4250             
4251             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4252                     attr == "style" || typeof o[attr] == "function") { continue; }
4253                     
4254             if(attr=="cls" && Roo.isIE){
4255                 el.className = o["cls"];
4256             }else{
4257                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4258                 else { 
4259                     el[attr] = o[attr];
4260                 }
4261             }
4262         }
4263         Roo.DomHelper.applyStyles(el, o.style);
4264         var cn = o.children || o.cn;
4265         if(cn){
4266             //http://bugs.kde.org/show_bug.cgi?id=71506
4267              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4268                 for(var i = 0, len = cn.length; i < len; i++) {
4269                     createDom(cn[i], el);
4270                 }
4271             }else{
4272                 createDom(cn, el);
4273             }
4274         }
4275         if(o.html){
4276             el.innerHTML = o.html;
4277         }
4278         if(parentNode){
4279            parentNode.appendChild(el);
4280         }
4281         return el;
4282     };
4283
4284     var ieTable = function(depth, s, h, e){
4285         tempTableEl.innerHTML = [s, h, e].join('');
4286         var i = -1, el = tempTableEl;
4287         while(++i < depth){
4288             el = el.firstChild;
4289         }
4290         return el;
4291     };
4292
4293     // kill repeat to save bytes
4294     var ts = '<table>',
4295         te = '</table>',
4296         tbs = ts+'<tbody>',
4297         tbe = '</tbody>'+te,
4298         trs = tbs + '<tr>',
4299         tre = '</tr>'+tbe;
4300
4301     /**
4302      * @ignore
4303      * Nasty code for IE's broken table implementation
4304      */
4305     var insertIntoTable = function(tag, where, el, html){
4306         if(!tempTableEl){
4307             tempTableEl = document.createElement('div');
4308         }
4309         var node;
4310         var before = null;
4311         if(tag == 'td'){
4312             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4313                 return;
4314             }
4315             if(where == 'beforebegin'){
4316                 before = el;
4317                 el = el.parentNode;
4318             } else{
4319                 before = el.nextSibling;
4320                 el = el.parentNode;
4321             }
4322             node = ieTable(4, trs, html, tre);
4323         }
4324         else if(tag == 'tr'){
4325             if(where == 'beforebegin'){
4326                 before = el;
4327                 el = el.parentNode;
4328                 node = ieTable(3, tbs, html, tbe);
4329             } else if(where == 'afterend'){
4330                 before = el.nextSibling;
4331                 el = el.parentNode;
4332                 node = ieTable(3, tbs, html, tbe);
4333             } else{ // INTO a TR
4334                 if(where == 'afterbegin'){
4335                     before = el.firstChild;
4336                 }
4337                 node = ieTable(4, trs, html, tre);
4338             }
4339         } else if(tag == 'tbody'){
4340             if(where == 'beforebegin'){
4341                 before = el;
4342                 el = el.parentNode;
4343                 node = ieTable(2, ts, html, te);
4344             } else if(where == 'afterend'){
4345                 before = el.nextSibling;
4346                 el = el.parentNode;
4347                 node = ieTable(2, ts, html, te);
4348             } else{
4349                 if(where == 'afterbegin'){
4350                     before = el.firstChild;
4351                 }
4352                 node = ieTable(3, tbs, html, tbe);
4353             }
4354         } else{ // TABLE
4355             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4356                 return;
4357             }
4358             if(where == 'afterbegin'){
4359                 before = el.firstChild;
4360             }
4361             node = ieTable(2, ts, html, te);
4362         }
4363         el.insertBefore(node, before);
4364         return node;
4365     };
4366
4367     return {
4368     /** True to force the use of DOM instead of html fragments @type Boolean */
4369     useDom : false,
4370
4371     /**
4372      * Returns the markup for the passed Element(s) config
4373      * @param {Object} o The Dom object spec (and children)
4374      * @return {String}
4375      */
4376     markup : function(o){
4377         return createHtml(o);
4378     },
4379
4380     /**
4381      * Applies a style specification to an element
4382      * @param {String/HTMLElement} el The element to apply styles to
4383      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4384      * a function which returns such a specification.
4385      */
4386     applyStyles : function(el, styles){
4387         if(styles){
4388            el = Roo.fly(el);
4389            if(typeof styles == "string"){
4390                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4391                var matches;
4392                while ((matches = re.exec(styles)) != null){
4393                    el.setStyle(matches[1], matches[2]);
4394                }
4395            }else if (typeof styles == "object"){
4396                for (var style in styles){
4397                   el.setStyle(style, styles[style]);
4398                }
4399            }else if (typeof styles == "function"){
4400                 Roo.DomHelper.applyStyles(el, styles.call());
4401            }
4402         }
4403     },
4404
4405     /**
4406      * Inserts an HTML fragment into the Dom
4407      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4408      * @param {HTMLElement} el The context element
4409      * @param {String} html The HTML fragmenet
4410      * @return {HTMLElement} The new node
4411      */
4412     insertHtml : function(where, el, html){
4413         where = where.toLowerCase();
4414         if(el.insertAdjacentHTML){
4415             if(tableRe.test(el.tagName)){
4416                 var rs;
4417                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4418                     return rs;
4419                 }
4420             }
4421             switch(where){
4422                 case "beforebegin":
4423                     el.insertAdjacentHTML('BeforeBegin', html);
4424                     return el.previousSibling;
4425                 case "afterbegin":
4426                     el.insertAdjacentHTML('AfterBegin', html);
4427                     return el.firstChild;
4428                 case "beforeend":
4429                     el.insertAdjacentHTML('BeforeEnd', html);
4430                     return el.lastChild;
4431                 case "afterend":
4432                     el.insertAdjacentHTML('AfterEnd', html);
4433                     return el.nextSibling;
4434             }
4435             throw 'Illegal insertion point -> "' + where + '"';
4436         }
4437         var range = el.ownerDocument.createRange();
4438         var frag;
4439         switch(where){
4440              case "beforebegin":
4441                 range.setStartBefore(el);
4442                 frag = range.createContextualFragment(html);
4443                 el.parentNode.insertBefore(frag, el);
4444                 return el.previousSibling;
4445              case "afterbegin":
4446                 if(el.firstChild){
4447                     range.setStartBefore(el.firstChild);
4448                     frag = range.createContextualFragment(html);
4449                     el.insertBefore(frag, el.firstChild);
4450                     return el.firstChild;
4451                 }else{
4452                     el.innerHTML = html;
4453                     return el.firstChild;
4454                 }
4455             case "beforeend":
4456                 if(el.lastChild){
4457                     range.setStartAfter(el.lastChild);
4458                     frag = range.createContextualFragment(html);
4459                     el.appendChild(frag);
4460                     return el.lastChild;
4461                 }else{
4462                     el.innerHTML = html;
4463                     return el.lastChild;
4464                 }
4465             case "afterend":
4466                 range.setStartAfter(el);
4467                 frag = range.createContextualFragment(html);
4468                 el.parentNode.insertBefore(frag, el.nextSibling);
4469                 return el.nextSibling;
4470             }
4471             throw 'Illegal insertion point -> "' + where + '"';
4472     },
4473
4474     /**
4475      * Creates new Dom element(s) and inserts them before el
4476      * @param {String/HTMLElement/Element} el The context element
4477      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4478      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4479      * @return {HTMLElement/Roo.Element} The new node
4480      */
4481     insertBefore : function(el, o, returnElement){
4482         return this.doInsert(el, o, returnElement, "beforeBegin");
4483     },
4484
4485     /**
4486      * Creates new Dom element(s) and inserts them after el
4487      * @param {String/HTMLElement/Element} el The context element
4488      * @param {Object} o The Dom object spec (and children)
4489      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4490      * @return {HTMLElement/Roo.Element} The new node
4491      */
4492     insertAfter : function(el, o, returnElement){
4493         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4494     },
4495
4496     /**
4497      * Creates new Dom element(s) and inserts them as the first child of el
4498      * @param {String/HTMLElement/Element} el The context element
4499      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4500      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4501      * @return {HTMLElement/Roo.Element} The new node
4502      */
4503     insertFirst : function(el, o, returnElement){
4504         return this.doInsert(el, o, returnElement, "afterBegin");
4505     },
4506
4507     // private
4508     doInsert : function(el, o, returnElement, pos, sibling){
4509         el = Roo.getDom(el);
4510         var newNode;
4511         if(this.useDom || o.ns){
4512             newNode = createDom(o, null);
4513             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4514         }else{
4515             var html = createHtml(o);
4516             newNode = this.insertHtml(pos, el, html);
4517         }
4518         return returnElement ? Roo.get(newNode, true) : newNode;
4519     },
4520
4521     /**
4522      * Creates new Dom element(s) and appends them to el
4523      * @param {String/HTMLElement/Element} el The context element
4524      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4525      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4526      * @return {HTMLElement/Roo.Element} The new node
4527      */
4528     append : function(el, o, returnElement){
4529         el = Roo.getDom(el);
4530         var newNode;
4531         if(this.useDom || o.ns){
4532             newNode = createDom(o, null);
4533             el.appendChild(newNode);
4534         }else{
4535             var html = createHtml(o);
4536             newNode = this.insertHtml("beforeEnd", el, html);
4537         }
4538         return returnElement ? Roo.get(newNode, true) : newNode;
4539     },
4540
4541     /**
4542      * Creates new Dom element(s) and overwrites the contents of el with them
4543      * @param {String/HTMLElement/Element} el The context element
4544      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4545      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4546      * @return {HTMLElement/Roo.Element} The new node
4547      */
4548     overwrite : function(el, o, returnElement){
4549         el = Roo.getDom(el);
4550         if (o.ns) {
4551           
4552             while (el.childNodes.length) {
4553                 el.removeChild(el.firstChild);
4554             }
4555             createDom(o, el);
4556         } else {
4557             el.innerHTML = createHtml(o);   
4558         }
4559         
4560         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4561     },
4562
4563     /**
4564      * Creates a new Roo.DomHelper.Template from the Dom object spec
4565      * @param {Object} o The Dom object spec (and children)
4566      * @return {Roo.DomHelper.Template} The new template
4567      */
4568     createTemplate : function(o){
4569         var html = createHtml(o);
4570         return new Roo.Template(html);
4571     }
4572     };
4573 }();
4574 /*
4575  * Based on:
4576  * Ext JS Library 1.1.1
4577  * Copyright(c) 2006-2007, Ext JS, LLC.
4578  *
4579  * Originally Released Under LGPL - original licence link has changed is not relivant.
4580  *
4581  * Fork - LGPL
4582  * <script type="text/javascript">
4583  */
4584  
4585 /**
4586 * @class Roo.Template
4587 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4588 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4589 * Usage:
4590 <pre><code>
4591 var t = new Roo.Template({
4592     html :  '&lt;div name="{id}"&gt;' + 
4593         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4594         '&lt;/div&gt;',
4595     myformat: function (value, allValues) {
4596         return 'XX' + value;
4597     }
4598 });
4599 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4600 </code></pre>
4601 * For more information see this blog post with examples:
4602 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4603      - Create Elements using DOM, HTML fragments and Templates</a>. 
4604 * @constructor
4605 * @param {Object} cfg - Configuration object.
4606 */
4607 Roo.Template = function(cfg){
4608     // BC!
4609     if(cfg instanceof Array){
4610         cfg = cfg.join("");
4611     }else if(arguments.length > 1){
4612         cfg = Array.prototype.join.call(arguments, "");
4613     }
4614     
4615     
4616     if (typeof(cfg) == 'object') {
4617         Roo.apply(this,cfg)
4618     } else {
4619         // bc
4620         this.html = cfg;
4621     }
4622     if (this.url) {
4623         this.load();
4624     }
4625     
4626 };
4627 Roo.Template.prototype = {
4628     
4629     /**
4630      * @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..
4631      *                    it should be fixed so that template is observable...
4632      */
4633     url : false,
4634     /**
4635      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4636      */
4637     html : '',
4638     /**
4639      * Returns an HTML fragment of this template with the specified values applied.
4640      * @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'})
4641      * @return {String} The HTML fragment
4642      */
4643     applyTemplate : function(values){
4644         try {
4645            
4646             if(this.compiled){
4647                 return this.compiled(values);
4648             }
4649             var useF = this.disableFormats !== true;
4650             var fm = Roo.util.Format, tpl = this;
4651             var fn = function(m, name, format, args){
4652                 if(format && useF){
4653                     if(format.substr(0, 5) == "this."){
4654                         return tpl.call(format.substr(5), values[name], values);
4655                     }else{
4656                         if(args){
4657                             // quoted values are required for strings in compiled templates, 
4658                             // but for non compiled we need to strip them
4659                             // quoted reversed for jsmin
4660                             var re = /^\s*['"](.*)["']\s*$/;
4661                             args = args.split(',');
4662                             for(var i = 0, len = args.length; i < len; i++){
4663                                 args[i] = args[i].replace(re, "$1");
4664                             }
4665                             args = [values[name]].concat(args);
4666                         }else{
4667                             args = [values[name]];
4668                         }
4669                         return fm[format].apply(fm, args);
4670                     }
4671                 }else{
4672                     return values[name] !== undefined ? values[name] : "";
4673                 }
4674             };
4675             return this.html.replace(this.re, fn);
4676         } catch (e) {
4677             Roo.log(e);
4678             throw e;
4679         }
4680          
4681     },
4682     
4683     loading : false,
4684       
4685     load : function ()
4686     {
4687          
4688         if (this.loading) {
4689             return;
4690         }
4691         var _t = this;
4692         
4693         this.loading = true;
4694         this.compiled = false;
4695         
4696         var cx = new Roo.data.Connection();
4697         cx.request({
4698             url : this.url,
4699             method : 'GET',
4700             success : function (response) {
4701                 _t.loading = false;
4702                 _t.html = response.responseText;
4703                 _t.url = false;
4704                 _t.compile();
4705              },
4706             failure : function(response) {
4707                 Roo.log("Template failed to load from " + _t.url);
4708                 _t.loading = false;
4709             }
4710         });
4711     },
4712
4713     /**
4714      * Sets the HTML used as the template and optionally compiles it.
4715      * @param {String} html
4716      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4717      * @return {Roo.Template} this
4718      */
4719     set : function(html, compile){
4720         this.html = html;
4721         this.compiled = null;
4722         if(compile){
4723             this.compile();
4724         }
4725         return this;
4726     },
4727     
4728     /**
4729      * True to disable format functions (defaults to false)
4730      * @type Boolean
4731      */
4732     disableFormats : false,
4733     
4734     /**
4735     * The regular expression used to match template variables 
4736     * @type RegExp
4737     * @property 
4738     */
4739     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4740     
4741     /**
4742      * Compiles the template into an internal function, eliminating the RegEx overhead.
4743      * @return {Roo.Template} this
4744      */
4745     compile : function(){
4746         var fm = Roo.util.Format;
4747         var useF = this.disableFormats !== true;
4748         var sep = Roo.isGecko ? "+" : ",";
4749         var fn = function(m, name, format, args){
4750             if(format && useF){
4751                 args = args ? ',' + args : "";
4752                 if(format.substr(0, 5) != "this."){
4753                     format = "fm." + format + '(';
4754                 }else{
4755                     format = 'this.call("'+ format.substr(5) + '", ';
4756                     args = ", values";
4757                 }
4758             }else{
4759                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4760             }
4761             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4762         };
4763         var body;
4764         // branched to use + in gecko and [].join() in others
4765         if(Roo.isGecko){
4766             body = "this.compiled = function(values){ return '" +
4767                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4768                     "';};";
4769         }else{
4770             body = ["this.compiled = function(values){ return ['"];
4771             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4772             body.push("'].join('');};");
4773             body = body.join('');
4774         }
4775         /**
4776          * eval:var:values
4777          * eval:var:fm
4778          */
4779         eval(body);
4780         return this;
4781     },
4782     
4783     // private function used to call members
4784     call : function(fnName, value, allValues){
4785         return this[fnName](value, allValues);
4786     },
4787     
4788     /**
4789      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4790      * @param {String/HTMLElement/Roo.Element} el The context element
4791      * @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'})
4792      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4793      * @return {HTMLElement/Roo.Element} The new node or Element
4794      */
4795     insertFirst: function(el, values, returnElement){
4796         return this.doInsert('afterBegin', el, values, returnElement);
4797     },
4798
4799     /**
4800      * Applies the supplied values to the template and inserts the new node(s) before el.
4801      * @param {String/HTMLElement/Roo.Element} el The context element
4802      * @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'})
4803      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4804      * @return {HTMLElement/Roo.Element} The new node or Element
4805      */
4806     insertBefore: function(el, values, returnElement){
4807         return this.doInsert('beforeBegin', el, values, returnElement);
4808     },
4809
4810     /**
4811      * Applies the supplied values to the template and inserts the new node(s) after el.
4812      * @param {String/HTMLElement/Roo.Element} el The context element
4813      * @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'})
4814      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4815      * @return {HTMLElement/Roo.Element} The new node or Element
4816      */
4817     insertAfter : function(el, values, returnElement){
4818         return this.doInsert('afterEnd', el, values, returnElement);
4819     },
4820     
4821     /**
4822      * Applies the supplied values to the template and appends the new node(s) to el.
4823      * @param {String/HTMLElement/Roo.Element} el The context element
4824      * @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'})
4825      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4826      * @return {HTMLElement/Roo.Element} The new node or Element
4827      */
4828     append : function(el, values, returnElement){
4829         return this.doInsert('beforeEnd', el, values, returnElement);
4830     },
4831
4832     doInsert : function(where, el, values, returnEl){
4833         el = Roo.getDom(el);
4834         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4835         return returnEl ? Roo.get(newNode, true) : newNode;
4836     },
4837
4838     /**
4839      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4840      * @param {String/HTMLElement/Roo.Element} el The context element
4841      * @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'})
4842      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4843      * @return {HTMLElement/Roo.Element} The new node or Element
4844      */
4845     overwrite : function(el, values, returnElement){
4846         el = Roo.getDom(el);
4847         el.innerHTML = this.applyTemplate(values);
4848         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4849     }
4850 };
4851 /**
4852  * Alias for {@link #applyTemplate}
4853  * @method
4854  */
4855 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4856
4857 // backwards compat
4858 Roo.DomHelper.Template = Roo.Template;
4859
4860 /**
4861  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4862  * @param {String/HTMLElement} el A DOM element or its id
4863  * @returns {Roo.Template} The created template
4864  * @static
4865  */
4866 Roo.Template.from = function(el){
4867     el = Roo.getDom(el);
4868     return new Roo.Template(el.value || el.innerHTML);
4869 };/*
4870  * Based on:
4871  * Ext JS Library 1.1.1
4872  * Copyright(c) 2006-2007, Ext JS, LLC.
4873  *
4874  * Originally Released Under LGPL - original licence link has changed is not relivant.
4875  *
4876  * Fork - LGPL
4877  * <script type="text/javascript">
4878  */
4879  
4880
4881 /*
4882  * This is code is also distributed under MIT license for use
4883  * with jQuery and prototype JavaScript libraries.
4884  */
4885 /**
4886  * @class Roo.DomQuery
4887 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).
4888 <p>
4889 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>
4890
4891 <p>
4892 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.
4893 </p>
4894 <h4>Element Selectors:</h4>
4895 <ul class="list">
4896     <li> <b>*</b> any element</li>
4897     <li> <b>E</b> an element with the tag E</li>
4898     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4899     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4900     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4901     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4902 </ul>
4903 <h4>Attribute Selectors:</h4>
4904 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4905 <ul class="list">
4906     <li> <b>E[foo]</b> has an attribute "foo"</li>
4907     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4908     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4909     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4910     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4911     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4912     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4913 </ul>
4914 <h4>Pseudo Classes:</h4>
4915 <ul class="list">
4916     <li> <b>E:first-child</b> E is the first child of its parent</li>
4917     <li> <b>E:last-child</b> E is the last child of its parent</li>
4918     <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>
4919     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4920     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4921     <li> <b>E:only-child</b> E is the only child of its parent</li>
4922     <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>
4923     <li> <b>E:first</b> the first E in the resultset</li>
4924     <li> <b>E:last</b> the last E in the resultset</li>
4925     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4926     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4927     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4928     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4929     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4930     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4931     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4932     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4933     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4934 </ul>
4935 <h4>CSS Value Selectors:</h4>
4936 <ul class="list">
4937     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4938     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4939     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4940     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4941     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4942     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4943 </ul>
4944  * @singleton
4945  */
4946 Roo.DomQuery = function(){
4947     var cache = {}, simpleCache = {}, valueCache = {};
4948     var nonSpace = /\S/;
4949     var trimRe = /^\s+|\s+$/g;
4950     var tplRe = /\{(\d+)\}/g;
4951     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4952     var tagTokenRe = /^(#)?([\w-\*]+)/;
4953     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4954
4955     function child(p, index){
4956         var i = 0;
4957         var n = p.firstChild;
4958         while(n){
4959             if(n.nodeType == 1){
4960                if(++i == index){
4961                    return n;
4962                }
4963             }
4964             n = n.nextSibling;
4965         }
4966         return null;
4967     };
4968
4969     function next(n){
4970         while((n = n.nextSibling) && n.nodeType != 1);
4971         return n;
4972     };
4973
4974     function prev(n){
4975         while((n = n.previousSibling) && n.nodeType != 1);
4976         return n;
4977     };
4978
4979     function children(d){
4980         var n = d.firstChild, ni = -1;
4981             while(n){
4982                 var nx = n.nextSibling;
4983                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4984                     d.removeChild(n);
4985                 }else{
4986                     n.nodeIndex = ++ni;
4987                 }
4988                 n = nx;
4989             }
4990             return this;
4991         };
4992
4993     function byClassName(c, a, v){
4994         if(!v){
4995             return c;
4996         }
4997         var r = [], ri = -1, cn;
4998         for(var i = 0, ci; ci = c[i]; i++){
4999             if((' '+ci.className+' ').indexOf(v) != -1){
5000                 r[++ri] = ci;
5001             }
5002         }
5003         return r;
5004     };
5005
5006     function attrValue(n, attr){
5007         if(!n.tagName && typeof n.length != "undefined"){
5008             n = n[0];
5009         }
5010         if(!n){
5011             return null;
5012         }
5013         if(attr == "for"){
5014             return n.htmlFor;
5015         }
5016         if(attr == "class" || attr == "className"){
5017             return n.className;
5018         }
5019         return n.getAttribute(attr) || n[attr];
5020
5021     };
5022
5023     function getNodes(ns, mode, tagName){
5024         var result = [], ri = -1, cs;
5025         if(!ns){
5026             return result;
5027         }
5028         tagName = tagName || "*";
5029         if(typeof ns.getElementsByTagName != "undefined"){
5030             ns = [ns];
5031         }
5032         if(!mode){
5033             for(var i = 0, ni; ni = ns[i]; i++){
5034                 cs = ni.getElementsByTagName(tagName);
5035                 for(var j = 0, ci; ci = cs[j]; j++){
5036                     result[++ri] = ci;
5037                 }
5038             }
5039         }else if(mode == "/" || mode == ">"){
5040             var utag = tagName.toUpperCase();
5041             for(var i = 0, ni, cn; ni = ns[i]; i++){
5042                 cn = ni.children || ni.childNodes;
5043                 for(var j = 0, cj; cj = cn[j]; j++){
5044                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5045                         result[++ri] = cj;
5046                     }
5047                 }
5048             }
5049         }else if(mode == "+"){
5050             var utag = tagName.toUpperCase();
5051             for(var i = 0, n; n = ns[i]; i++){
5052                 while((n = n.nextSibling) && n.nodeType != 1);
5053                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5054                     result[++ri] = n;
5055                 }
5056             }
5057         }else if(mode == "~"){
5058             for(var i = 0, n; n = ns[i]; i++){
5059                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5060                 if(n){
5061                     result[++ri] = n;
5062                 }
5063             }
5064         }
5065         return result;
5066     };
5067
5068     function concat(a, b){
5069         if(b.slice){
5070             return a.concat(b);
5071         }
5072         for(var i = 0, l = b.length; i < l; i++){
5073             a[a.length] = b[i];
5074         }
5075         return a;
5076     }
5077
5078     function byTag(cs, tagName){
5079         if(cs.tagName || cs == document){
5080             cs = [cs];
5081         }
5082         if(!tagName){
5083             return cs;
5084         }
5085         var r = [], ri = -1;
5086         tagName = tagName.toLowerCase();
5087         for(var i = 0, ci; ci = cs[i]; i++){
5088             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5089                 r[++ri] = ci;
5090             }
5091         }
5092         return r;
5093     };
5094
5095     function byId(cs, attr, id){
5096         if(cs.tagName || cs == document){
5097             cs = [cs];
5098         }
5099         if(!id){
5100             return cs;
5101         }
5102         var r = [], ri = -1;
5103         for(var i = 0,ci; ci = cs[i]; i++){
5104             if(ci && ci.id == id){
5105                 r[++ri] = ci;
5106                 return r;
5107             }
5108         }
5109         return r;
5110     };
5111
5112     function byAttribute(cs, attr, value, op, custom){
5113         var r = [], ri = -1, st = custom=="{";
5114         var f = Roo.DomQuery.operators[op];
5115         for(var i = 0, ci; ci = cs[i]; i++){
5116             var a;
5117             if(st){
5118                 a = Roo.DomQuery.getStyle(ci, attr);
5119             }
5120             else if(attr == "class" || attr == "className"){
5121                 a = ci.className;
5122             }else if(attr == "for"){
5123                 a = ci.htmlFor;
5124             }else if(attr == "href"){
5125                 a = ci.getAttribute("href", 2);
5126             }else{
5127                 a = ci.getAttribute(attr);
5128             }
5129             if((f && f(a, value)) || (!f && a)){
5130                 r[++ri] = ci;
5131             }
5132         }
5133         return r;
5134     };
5135
5136     function byPseudo(cs, name, value){
5137         return Roo.DomQuery.pseudos[name](cs, value);
5138     };
5139
5140     // This is for IE MSXML which does not support expandos.
5141     // IE runs the same speed using setAttribute, however FF slows way down
5142     // and Safari completely fails so they need to continue to use expandos.
5143     var isIE = window.ActiveXObject ? true : false;
5144
5145     // this eval is stop the compressor from
5146     // renaming the variable to something shorter
5147     
5148     /** eval:var:batch */
5149     var batch = 30803; 
5150
5151     var key = 30803;
5152
5153     function nodupIEXml(cs){
5154         var d = ++key;
5155         cs[0].setAttribute("_nodup", d);
5156         var r = [cs[0]];
5157         for(var i = 1, len = cs.length; i < len; i++){
5158             var c = cs[i];
5159             if(!c.getAttribute("_nodup") != d){
5160                 c.setAttribute("_nodup", d);
5161                 r[r.length] = c;
5162             }
5163         }
5164         for(var i = 0, len = cs.length; i < len; i++){
5165             cs[i].removeAttribute("_nodup");
5166         }
5167         return r;
5168     }
5169
5170     function nodup(cs){
5171         if(!cs){
5172             return [];
5173         }
5174         var len = cs.length, c, i, r = cs, cj, ri = -1;
5175         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5176             return cs;
5177         }
5178         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5179             return nodupIEXml(cs);
5180         }
5181         var d = ++key;
5182         cs[0]._nodup = d;
5183         for(i = 1; c = cs[i]; i++){
5184             if(c._nodup != d){
5185                 c._nodup = d;
5186             }else{
5187                 r = [];
5188                 for(var j = 0; j < i; j++){
5189                     r[++ri] = cs[j];
5190                 }
5191                 for(j = i+1; cj = cs[j]; j++){
5192                     if(cj._nodup != d){
5193                         cj._nodup = d;
5194                         r[++ri] = cj;
5195                     }
5196                 }
5197                 return r;
5198             }
5199         }
5200         return r;
5201     }
5202
5203     function quickDiffIEXml(c1, c2){
5204         var d = ++key;
5205         for(var i = 0, len = c1.length; i < len; i++){
5206             c1[i].setAttribute("_qdiff", d);
5207         }
5208         var r = [];
5209         for(var i = 0, len = c2.length; i < len; i++){
5210             if(c2[i].getAttribute("_qdiff") != d){
5211                 r[r.length] = c2[i];
5212             }
5213         }
5214         for(var i = 0, len = c1.length; i < len; i++){
5215            c1[i].removeAttribute("_qdiff");
5216         }
5217         return r;
5218     }
5219
5220     function quickDiff(c1, c2){
5221         var len1 = c1.length;
5222         if(!len1){
5223             return c2;
5224         }
5225         if(isIE && c1[0].selectSingleNode){
5226             return quickDiffIEXml(c1, c2);
5227         }
5228         var d = ++key;
5229         for(var i = 0; i < len1; i++){
5230             c1[i]._qdiff = d;
5231         }
5232         var r = [];
5233         for(var i = 0, len = c2.length; i < len; i++){
5234             if(c2[i]._qdiff != d){
5235                 r[r.length] = c2[i];
5236             }
5237         }
5238         return r;
5239     }
5240
5241     function quickId(ns, mode, root, id){
5242         if(ns == root){
5243            var d = root.ownerDocument || root;
5244            return d.getElementById(id);
5245         }
5246         ns = getNodes(ns, mode, "*");
5247         return byId(ns, null, id);
5248     }
5249
5250     return {
5251         getStyle : function(el, name){
5252             return Roo.fly(el).getStyle(name);
5253         },
5254         /**
5255          * Compiles a selector/xpath query into a reusable function. The returned function
5256          * takes one parameter "root" (optional), which is the context node from where the query should start.
5257          * @param {String} selector The selector/xpath query
5258          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5259          * @return {Function}
5260          */
5261         compile : function(path, type){
5262             type = type || "select";
5263             
5264             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5265             var q = path, mode, lq;
5266             var tk = Roo.DomQuery.matchers;
5267             var tklen = tk.length;
5268             var mm;
5269
5270             // accept leading mode switch
5271             var lmode = q.match(modeRe);
5272             if(lmode && lmode[1]){
5273                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5274                 q = q.replace(lmode[1], "");
5275             }
5276             // strip leading slashes
5277             while(path.substr(0, 1)=="/"){
5278                 path = path.substr(1);
5279             }
5280
5281             while(q && lq != q){
5282                 lq = q;
5283                 var tm = q.match(tagTokenRe);
5284                 if(type == "select"){
5285                     if(tm){
5286                         if(tm[1] == "#"){
5287                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5288                         }else{
5289                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5290                         }
5291                         q = q.replace(tm[0], "");
5292                     }else if(q.substr(0, 1) != '@'){
5293                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5294                     }
5295                 }else{
5296                     if(tm){
5297                         if(tm[1] == "#"){
5298                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5299                         }else{
5300                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5301                         }
5302                         q = q.replace(tm[0], "");
5303                     }
5304                 }
5305                 while(!(mm = q.match(modeRe))){
5306                     var matched = false;
5307                     for(var j = 0; j < tklen; j++){
5308                         var t = tk[j];
5309                         var m = q.match(t.re);
5310                         if(m){
5311                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5312                                                     return m[i];
5313                                                 });
5314                             q = q.replace(m[0], "");
5315                             matched = true;
5316                             break;
5317                         }
5318                     }
5319                     // prevent infinite loop on bad selector
5320                     if(!matched){
5321                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5322                     }
5323                 }
5324                 if(mm[1]){
5325                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5326                     q = q.replace(mm[1], "");
5327                 }
5328             }
5329             fn[fn.length] = "return nodup(n);\n}";
5330             
5331              /** 
5332               * list of variables that need from compression as they are used by eval.
5333              *  eval:var:batch 
5334              *  eval:var:nodup
5335              *  eval:var:byTag
5336              *  eval:var:ById
5337              *  eval:var:getNodes
5338              *  eval:var:quickId
5339              *  eval:var:mode
5340              *  eval:var:root
5341              *  eval:var:n
5342              *  eval:var:byClassName
5343              *  eval:var:byPseudo
5344              *  eval:var:byAttribute
5345              *  eval:var:attrValue
5346              * 
5347              **/ 
5348             eval(fn.join(""));
5349             return f;
5350         },
5351
5352         /**
5353          * Selects a group of elements.
5354          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5355          * @param {Node} root (optional) The start of the query (defaults to document).
5356          * @return {Array}
5357          */
5358         select : function(path, root, type){
5359             if(!root || root == document){
5360                 root = document;
5361             }
5362             if(typeof root == "string"){
5363                 root = document.getElementById(root);
5364             }
5365             var paths = path.split(",");
5366             var results = [];
5367             for(var i = 0, len = paths.length; i < len; i++){
5368                 var p = paths[i].replace(trimRe, "");
5369                 if(!cache[p]){
5370                     cache[p] = Roo.DomQuery.compile(p);
5371                     if(!cache[p]){
5372                         throw p + " is not a valid selector";
5373                     }
5374                 }
5375                 var result = cache[p](root);
5376                 if(result && result != document){
5377                     results = results.concat(result);
5378                 }
5379             }
5380             if(paths.length > 1){
5381                 return nodup(results);
5382             }
5383             return results;
5384         },
5385
5386         /**
5387          * Selects a single element.
5388          * @param {String} selector The selector/xpath query
5389          * @param {Node} root (optional) The start of the query (defaults to document).
5390          * @return {Element}
5391          */
5392         selectNode : function(path, root){
5393             return Roo.DomQuery.select(path, root)[0];
5394         },
5395
5396         /**
5397          * Selects the value of a node, optionally replacing null with the defaultValue.
5398          * @param {String} selector The selector/xpath query
5399          * @param {Node} root (optional) The start of the query (defaults to document).
5400          * @param {String} defaultValue
5401          */
5402         selectValue : function(path, root, defaultValue){
5403             path = path.replace(trimRe, "");
5404             if(!valueCache[path]){
5405                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5406             }
5407             var n = valueCache[path](root);
5408             n = n[0] ? n[0] : n;
5409             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5410             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5411         },
5412
5413         /**
5414          * Selects the value of a node, parsing integers and floats.
5415          * @param {String} selector The selector/xpath query
5416          * @param {Node} root (optional) The start of the query (defaults to document).
5417          * @param {Number} defaultValue
5418          * @return {Number}
5419          */
5420         selectNumber : function(path, root, defaultValue){
5421             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5422             return parseFloat(v);
5423         },
5424
5425         /**
5426          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5427          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5428          * @param {String} selector The simple selector to test
5429          * @return {Boolean}
5430          */
5431         is : function(el, ss){
5432             if(typeof el == "string"){
5433                 el = document.getElementById(el);
5434             }
5435             var isArray = (el instanceof Array);
5436             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5437             return isArray ? (result.length == el.length) : (result.length > 0);
5438         },
5439
5440         /**
5441          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5442          * @param {Array} el An array of elements to filter
5443          * @param {String} selector The simple selector to test
5444          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5445          * the selector instead of the ones that match
5446          * @return {Array}
5447          */
5448         filter : function(els, ss, nonMatches){
5449             ss = ss.replace(trimRe, "");
5450             if(!simpleCache[ss]){
5451                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5452             }
5453             var result = simpleCache[ss](els);
5454             return nonMatches ? quickDiff(result, els) : result;
5455         },
5456
5457         /**
5458          * Collection of matching regular expressions and code snippets.
5459          */
5460         matchers : [{
5461                 re: /^\.([\w-]+)/,
5462                 select: 'n = byClassName(n, null, " {1} ");'
5463             }, {
5464                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5465                 select: 'n = byPseudo(n, "{1}", "{2}");'
5466             },{
5467                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5468                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5469             }, {
5470                 re: /^#([\w-]+)/,
5471                 select: 'n = byId(n, null, "{1}");'
5472             },{
5473                 re: /^@([\w-]+)/,
5474                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5475             }
5476         ],
5477
5478         /**
5479          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5480          * 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;.
5481          */
5482         operators : {
5483             "=" : function(a, v){
5484                 return a == v;
5485             },
5486             "!=" : function(a, v){
5487                 return a != v;
5488             },
5489             "^=" : function(a, v){
5490                 return a && a.substr(0, v.length) == v;
5491             },
5492             "$=" : function(a, v){
5493                 return a && a.substr(a.length-v.length) == v;
5494             },
5495             "*=" : function(a, v){
5496                 return a && a.indexOf(v) !== -1;
5497             },
5498             "%=" : function(a, v){
5499                 return (a % v) == 0;
5500             },
5501             "|=" : function(a, v){
5502                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5503             },
5504             "~=" : function(a, v){
5505                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5506             }
5507         },
5508
5509         /**
5510          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5511          * and the argument (if any) supplied in the selector.
5512          */
5513         pseudos : {
5514             "first-child" : function(c){
5515                 var r = [], ri = -1, n;
5516                 for(var i = 0, ci; ci = n = c[i]; i++){
5517                     while((n = n.previousSibling) && n.nodeType != 1);
5518                     if(!n){
5519                         r[++ri] = ci;
5520                     }
5521                 }
5522                 return r;
5523             },
5524
5525             "last-child" : function(c){
5526                 var r = [], ri = -1, n;
5527                 for(var i = 0, ci; ci = n = c[i]; i++){
5528                     while((n = n.nextSibling) && n.nodeType != 1);
5529                     if(!n){
5530                         r[++ri] = ci;
5531                     }
5532                 }
5533                 return r;
5534             },
5535
5536             "nth-child" : function(c, a) {
5537                 var r = [], ri = -1;
5538                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5539                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5540                 for(var i = 0, n; n = c[i]; i++){
5541                     var pn = n.parentNode;
5542                     if (batch != pn._batch) {
5543                         var j = 0;
5544                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5545                             if(cn.nodeType == 1){
5546                                cn.nodeIndex = ++j;
5547                             }
5548                         }
5549                         pn._batch = batch;
5550                     }
5551                     if (f == 1) {
5552                         if (l == 0 || n.nodeIndex == l){
5553                             r[++ri] = n;
5554                         }
5555                     } else if ((n.nodeIndex + l) % f == 0){
5556                         r[++ri] = n;
5557                     }
5558                 }
5559
5560                 return r;
5561             },
5562
5563             "only-child" : function(c){
5564                 var r = [], ri = -1;;
5565                 for(var i = 0, ci; ci = c[i]; i++){
5566                     if(!prev(ci) && !next(ci)){
5567                         r[++ri] = ci;
5568                     }
5569                 }
5570                 return r;
5571             },
5572
5573             "empty" : function(c){
5574                 var r = [], ri = -1;
5575                 for(var i = 0, ci; ci = c[i]; i++){
5576                     var cns = ci.childNodes, j = 0, cn, empty = true;
5577                     while(cn = cns[j]){
5578                         ++j;
5579                         if(cn.nodeType == 1 || cn.nodeType == 3){
5580                             empty = false;
5581                             break;
5582                         }
5583                     }
5584                     if(empty){
5585                         r[++ri] = ci;
5586                     }
5587                 }
5588                 return r;
5589             },
5590
5591             "contains" : function(c, v){
5592                 var r = [], ri = -1;
5593                 for(var i = 0, ci; ci = c[i]; i++){
5594                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5595                         r[++ri] = ci;
5596                     }
5597                 }
5598                 return r;
5599             },
5600
5601             "nodeValue" : function(c, v){
5602                 var r = [], ri = -1;
5603                 for(var i = 0, ci; ci = c[i]; i++){
5604                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5605                         r[++ri] = ci;
5606                     }
5607                 }
5608                 return r;
5609             },
5610
5611             "checked" : function(c){
5612                 var r = [], ri = -1;
5613                 for(var i = 0, ci; ci = c[i]; i++){
5614                     if(ci.checked == true){
5615                         r[++ri] = ci;
5616                     }
5617                 }
5618                 return r;
5619             },
5620
5621             "not" : function(c, ss){
5622                 return Roo.DomQuery.filter(c, ss, true);
5623             },
5624
5625             "odd" : function(c){
5626                 return this["nth-child"](c, "odd");
5627             },
5628
5629             "even" : function(c){
5630                 return this["nth-child"](c, "even");
5631             },
5632
5633             "nth" : function(c, a){
5634                 return c[a-1] || [];
5635             },
5636
5637             "first" : function(c){
5638                 return c[0] || [];
5639             },
5640
5641             "last" : function(c){
5642                 return c[c.length-1] || [];
5643             },
5644
5645             "has" : function(c, ss){
5646                 var s = Roo.DomQuery.select;
5647                 var r = [], ri = -1;
5648                 for(var i = 0, ci; ci = c[i]; i++){
5649                     if(s(ss, ci).length > 0){
5650                         r[++ri] = ci;
5651                     }
5652                 }
5653                 return r;
5654             },
5655
5656             "next" : function(c, ss){
5657                 var is = Roo.DomQuery.is;
5658                 var r = [], ri = -1;
5659                 for(var i = 0, ci; ci = c[i]; i++){
5660                     var n = next(ci);
5661                     if(n && is(n, ss)){
5662                         r[++ri] = ci;
5663                     }
5664                 }
5665                 return r;
5666             },
5667
5668             "prev" : function(c, ss){
5669                 var is = Roo.DomQuery.is;
5670                 var r = [], ri = -1;
5671                 for(var i = 0, ci; ci = c[i]; i++){
5672                     var n = prev(ci);
5673                     if(n && is(n, ss)){
5674                         r[++ri] = ci;
5675                     }
5676                 }
5677                 return r;
5678             }
5679         }
5680     };
5681 }();
5682
5683 /**
5684  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5685  * @param {String} path The selector/xpath query
5686  * @param {Node} root (optional) The start of the query (defaults to document).
5687  * @return {Array}
5688  * @member Roo
5689  * @method query
5690  */
5691 Roo.query = Roo.DomQuery.select;
5692 /*
5693  * Based on:
5694  * Ext JS Library 1.1.1
5695  * Copyright(c) 2006-2007, Ext JS, LLC.
5696  *
5697  * Originally Released Under LGPL - original licence link has changed is not relivant.
5698  *
5699  * Fork - LGPL
5700  * <script type="text/javascript">
5701  */
5702
5703 /**
5704  * @class Roo.util.Observable
5705  * Base class that provides a common interface for publishing events. Subclasses are expected to
5706  * to have a property "events" with all the events defined.<br>
5707  * For example:
5708  * <pre><code>
5709  Employee = function(name){
5710     this.name = name;
5711     this.addEvents({
5712         "fired" : true,
5713         "quit" : true
5714     });
5715  }
5716  Roo.extend(Employee, Roo.util.Observable);
5717 </code></pre>
5718  * @param {Object} config properties to use (incuding events / listeners)
5719  */
5720
5721 Roo.util.Observable = function(cfg){
5722     
5723     cfg = cfg|| {};
5724     this.addEvents(cfg.events || {});
5725     if (cfg.events) {
5726         delete cfg.events; // make sure
5727     }
5728      
5729     Roo.apply(this, cfg);
5730     
5731     if(this.listeners){
5732         this.on(this.listeners);
5733         delete this.listeners;
5734     }
5735 };
5736 Roo.util.Observable.prototype = {
5737     /** 
5738  * @cfg {Object} listeners  list of events and functions to call for this object, 
5739  * For example :
5740  * <pre><code>
5741     listeners :  { 
5742        'click' : function(e) {
5743            ..... 
5744         } ,
5745         .... 
5746     } 
5747   </code></pre>
5748  */
5749     
5750     
5751     /**
5752      * Fires the specified event with the passed parameters (minus the event name).
5753      * @param {String} eventName
5754      * @param {Object...} args Variable number of parameters are passed to handlers
5755      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5756      */
5757     fireEvent : function(){
5758         var ce = this.events[arguments[0].toLowerCase()];
5759         if(typeof ce == "object"){
5760             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5761         }else{
5762             return true;
5763         }
5764     },
5765
5766     // private
5767     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5768
5769     /**
5770      * Appends an event handler to this component
5771      * @param {String}   eventName The type of event to listen for
5772      * @param {Function} handler The method the event invokes
5773      * @param {Object}   scope (optional) The scope in which to execute the handler
5774      * function. The handler function's "this" context.
5775      * @param {Object}   options (optional) An object containing handler configuration
5776      * properties. This may contain any of the following properties:<ul>
5777      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5778      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5779      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5780      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5781      * by the specified number of milliseconds. If the event fires again within that time, the original
5782      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5783      * </ul><br>
5784      * <p>
5785      * <b>Combining Options</b><br>
5786      * Using the options argument, it is possible to combine different types of listeners:<br>
5787      * <br>
5788      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5789                 <pre><code>
5790                 el.on('click', this.onClick, this, {
5791                         single: true,
5792                 delay: 100,
5793                 forumId: 4
5794                 });
5795                 </code></pre>
5796      * <p>
5797      * <b>Attaching multiple handlers in 1 call</b><br>
5798      * The method also allows for a single argument to be passed which is a config object containing properties
5799      * which specify multiple handlers.
5800      * <pre><code>
5801                 el.on({
5802                         'click': {
5803                         fn: this.onClick,
5804                         scope: this,
5805                         delay: 100
5806                 }, 
5807                 'mouseover': {
5808                         fn: this.onMouseOver,
5809                         scope: this
5810                 },
5811                 'mouseout': {
5812                         fn: this.onMouseOut,
5813                         scope: this
5814                 }
5815                 });
5816                 </code></pre>
5817      * <p>
5818      * Or a shorthand syntax which passes the same scope object to all handlers:
5819         <pre><code>
5820                 el.on({
5821                         'click': this.onClick,
5822                 'mouseover': this.onMouseOver,
5823                 'mouseout': this.onMouseOut,
5824                 scope: this
5825                 });
5826                 </code></pre>
5827      */
5828     addListener : function(eventName, fn, scope, o){
5829         if(typeof eventName == "object"){
5830             o = eventName;
5831             for(var e in o){
5832                 if(this.filterOptRe.test(e)){
5833                     continue;
5834                 }
5835                 if(typeof o[e] == "function"){
5836                     // shared options
5837                     this.addListener(e, o[e], o.scope,  o);
5838                 }else{
5839                     // individual options
5840                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5841                 }
5842             }
5843             return;
5844         }
5845         o = (!o || typeof o == "boolean") ? {} : o;
5846         eventName = eventName.toLowerCase();
5847         var ce = this.events[eventName] || true;
5848         if(typeof ce == "boolean"){
5849             ce = new Roo.util.Event(this, eventName);
5850             this.events[eventName] = ce;
5851         }
5852         ce.addListener(fn, scope, o);
5853     },
5854
5855     /**
5856      * Removes a listener
5857      * @param {String}   eventName     The type of event to listen for
5858      * @param {Function} handler        The handler to remove
5859      * @param {Object}   scope  (optional) The scope (this object) for the handler
5860      */
5861     removeListener : function(eventName, fn, scope){
5862         var ce = this.events[eventName.toLowerCase()];
5863         if(typeof ce == "object"){
5864             ce.removeListener(fn, scope);
5865         }
5866     },
5867
5868     /**
5869      * Removes all listeners for this object
5870      */
5871     purgeListeners : function(){
5872         for(var evt in this.events){
5873             if(typeof this.events[evt] == "object"){
5874                  this.events[evt].clearListeners();
5875             }
5876         }
5877     },
5878
5879     relayEvents : function(o, events){
5880         var createHandler = function(ename){
5881             return function(){
5882                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5883             };
5884         };
5885         for(var i = 0, len = events.length; i < len; i++){
5886             var ename = events[i];
5887             if(!this.events[ename]){ this.events[ename] = true; };
5888             o.on(ename, createHandler(ename), this);
5889         }
5890     },
5891
5892     /**
5893      * Used to define events on this Observable
5894      * @param {Object} object The object with the events defined
5895      */
5896     addEvents : function(o){
5897         if(!this.events){
5898             this.events = {};
5899         }
5900         Roo.applyIf(this.events, o);
5901     },
5902
5903     /**
5904      * Checks to see if this object has any listeners for a specified event
5905      * @param {String} eventName The name of the event to check for
5906      * @return {Boolean} True if the event is being listened for, else false
5907      */
5908     hasListener : function(eventName){
5909         var e = this.events[eventName];
5910         return typeof e == "object" && e.listeners.length > 0;
5911     }
5912 };
5913 /**
5914  * Appends an event handler to this element (shorthand for addListener)
5915  * @param {String}   eventName     The type of event to listen for
5916  * @param {Function} handler        The method the event invokes
5917  * @param {Object}   scope (optional) The scope in which to execute the handler
5918  * function. The handler function's "this" context.
5919  * @param {Object}   options  (optional)
5920  * @method
5921  */
5922 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5923 /**
5924  * Removes a listener (shorthand for removeListener)
5925  * @param {String}   eventName     The type of event to listen for
5926  * @param {Function} handler        The handler to remove
5927  * @param {Object}   scope  (optional) The scope (this object) for the handler
5928  * @method
5929  */
5930 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5931
5932 /**
5933  * Starts capture on the specified Observable. All events will be passed
5934  * to the supplied function with the event name + standard signature of the event
5935  * <b>before</b> the event is fired. If the supplied function returns false,
5936  * the event will not fire.
5937  * @param {Observable} o The Observable to capture
5938  * @param {Function} fn The function to call
5939  * @param {Object} scope (optional) The scope (this object) for the fn
5940  * @static
5941  */
5942 Roo.util.Observable.capture = function(o, fn, scope){
5943     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5944 };
5945
5946 /**
5947  * Removes <b>all</b> added captures from the Observable.
5948  * @param {Observable} o The Observable to release
5949  * @static
5950  */
5951 Roo.util.Observable.releaseCapture = function(o){
5952     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5953 };
5954
5955 (function(){
5956
5957     var createBuffered = function(h, o, scope){
5958         var task = new Roo.util.DelayedTask();
5959         return function(){
5960             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5961         };
5962     };
5963
5964     var createSingle = function(h, e, fn, scope){
5965         return function(){
5966             e.removeListener(fn, scope);
5967             return h.apply(scope, arguments);
5968         };
5969     };
5970
5971     var createDelayed = function(h, o, scope){
5972         return function(){
5973             var args = Array.prototype.slice.call(arguments, 0);
5974             setTimeout(function(){
5975                 h.apply(scope, args);
5976             }, o.delay || 10);
5977         };
5978     };
5979
5980     Roo.util.Event = function(obj, name){
5981         this.name = name;
5982         this.obj = obj;
5983         this.listeners = [];
5984     };
5985
5986     Roo.util.Event.prototype = {
5987         addListener : function(fn, scope, options){
5988             var o = options || {};
5989             scope = scope || this.obj;
5990             if(!this.isListening(fn, scope)){
5991                 var l = {fn: fn, scope: scope, options: o};
5992                 var h = fn;
5993                 if(o.delay){
5994                     h = createDelayed(h, o, scope);
5995                 }
5996                 if(o.single){
5997                     h = createSingle(h, this, fn, scope);
5998                 }
5999                 if(o.buffer){
6000                     h = createBuffered(h, o, scope);
6001                 }
6002                 l.fireFn = h;
6003                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6004                     this.listeners.push(l);
6005                 }else{
6006                     this.listeners = this.listeners.slice(0);
6007                     this.listeners.push(l);
6008                 }
6009             }
6010         },
6011
6012         findListener : function(fn, scope){
6013             scope = scope || this.obj;
6014             var ls = this.listeners;
6015             for(var i = 0, len = ls.length; i < len; i++){
6016                 var l = ls[i];
6017                 if(l.fn == fn && l.scope == scope){
6018                     return i;
6019                 }
6020             }
6021             return -1;
6022         },
6023
6024         isListening : function(fn, scope){
6025             return this.findListener(fn, scope) != -1;
6026         },
6027
6028         removeListener : function(fn, scope){
6029             var index;
6030             if((index = this.findListener(fn, scope)) != -1){
6031                 if(!this.firing){
6032                     this.listeners.splice(index, 1);
6033                 }else{
6034                     this.listeners = this.listeners.slice(0);
6035                     this.listeners.splice(index, 1);
6036                 }
6037                 return true;
6038             }
6039             return false;
6040         },
6041
6042         clearListeners : function(){
6043             this.listeners = [];
6044         },
6045
6046         fire : function(){
6047             var ls = this.listeners, scope, len = ls.length;
6048             if(len > 0){
6049                 this.firing = true;
6050                 var args = Array.prototype.slice.call(arguments, 0);
6051                 for(var i = 0; i < len; i++){
6052                     var l = ls[i];
6053                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6054                         this.firing = false;
6055                         return false;
6056                     }
6057                 }
6058                 this.firing = false;
6059             }
6060             return true;
6061         }
6062     };
6063 })();/*
6064  * RooJS Library 
6065  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6066  *
6067  * Licence LGPL 
6068  *
6069  */
6070  
6071 /**
6072  * @class Roo.Document
6073  * @extends Roo.util.Observable
6074  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6075  * 
6076  * @param {Object} config the methods and properties of the 'base' class for the application.
6077  * 
6078  *  Generic Page handler - implement this to start your app..
6079  * 
6080  * eg.
6081  *  MyProject = new Roo.Document({
6082         events : {
6083             'load' : true // your events..
6084         },
6085         listeners : {
6086             'ready' : function() {
6087                 // fired on Roo.onReady()
6088             }
6089         }
6090  * 
6091  */
6092 Roo.Document = function(cfg) {
6093      
6094     this.addEvents({ 
6095         'ready' : true
6096     });
6097     Roo.util.Observable.call(this,cfg);
6098     
6099     var _this = this;
6100     
6101     Roo.onReady(function() {
6102         _this.fireEvent('ready');
6103     },null,false);
6104     
6105     
6106 }
6107
6108 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6109  * Based on:
6110  * Ext JS Library 1.1.1
6111  * Copyright(c) 2006-2007, Ext JS, LLC.
6112  *
6113  * Originally Released Under LGPL - original licence link has changed is not relivant.
6114  *
6115  * Fork - LGPL
6116  * <script type="text/javascript">
6117  */
6118
6119 /**
6120  * @class Roo.EventManager
6121  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6122  * several useful events directly.
6123  * See {@link Roo.EventObject} for more details on normalized event objects.
6124  * @singleton
6125  */
6126 Roo.EventManager = function(){
6127     var docReadyEvent, docReadyProcId, docReadyState = false;
6128     var resizeEvent, resizeTask, textEvent, textSize;
6129     var E = Roo.lib.Event;
6130     var D = Roo.lib.Dom;
6131
6132     
6133     
6134
6135     var fireDocReady = function(){
6136         if(!docReadyState){
6137             docReadyState = true;
6138             Roo.isReady = true;
6139             if(docReadyProcId){
6140                 clearInterval(docReadyProcId);
6141             }
6142             if(Roo.isGecko || Roo.isOpera) {
6143                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6144             }
6145             if(Roo.isIE){
6146                 var defer = document.getElementById("ie-deferred-loader");
6147                 if(defer){
6148                     defer.onreadystatechange = null;
6149                     defer.parentNode.removeChild(defer);
6150                 }
6151             }
6152             if(docReadyEvent){
6153                 docReadyEvent.fire();
6154                 docReadyEvent.clearListeners();
6155             }
6156         }
6157     };
6158     
6159     var initDocReady = function(){
6160         docReadyEvent = new Roo.util.Event();
6161         if(Roo.isGecko || Roo.isOpera) {
6162             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6163         }else if(Roo.isIE){
6164             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6165             var defer = document.getElementById("ie-deferred-loader");
6166             defer.onreadystatechange = function(){
6167                 if(this.readyState == "complete"){
6168                     fireDocReady();
6169                 }
6170             };
6171         }else if(Roo.isSafari){ 
6172             docReadyProcId = setInterval(function(){
6173                 var rs = document.readyState;
6174                 if(rs == "complete") {
6175                     fireDocReady();     
6176                  }
6177             }, 10);
6178         }
6179         // no matter what, make sure it fires on load
6180         E.on(window, "load", fireDocReady);
6181     };
6182
6183     var createBuffered = function(h, o){
6184         var task = new Roo.util.DelayedTask(h);
6185         return function(e){
6186             // create new event object impl so new events don't wipe out properties
6187             e = new Roo.EventObjectImpl(e);
6188             task.delay(o.buffer, h, null, [e]);
6189         };
6190     };
6191
6192     var createSingle = function(h, el, ename, fn){
6193         return function(e){
6194             Roo.EventManager.removeListener(el, ename, fn);
6195             h(e);
6196         };
6197     };
6198
6199     var createDelayed = function(h, o){
6200         return function(e){
6201             // create new event object impl so new events don't wipe out properties
6202             e = new Roo.EventObjectImpl(e);
6203             setTimeout(function(){
6204                 h(e);
6205             }, o.delay || 10);
6206         };
6207     };
6208     var transitionEndVal = false;
6209     
6210     var transitionEnd = function()
6211     {
6212         if (transitionEndVal) {
6213             return transitionEndVal;
6214         }
6215         var el = document.createElement('div');
6216
6217         var transEndEventNames = {
6218             WebkitTransition : 'webkitTransitionEnd',
6219             MozTransition    : 'transitionend',
6220             OTransition      : 'oTransitionEnd otransitionend',
6221             transition       : 'transitionend'
6222         };
6223     
6224         for (var name in transEndEventNames) {
6225             if (el.style[name] !== undefined) {
6226                 transitionEndVal = transEndEventNames[name];
6227                 return  transitionEndVal ;
6228             }
6229         }
6230     }
6231     
6232
6233     var listen = function(element, ename, opt, fn, scope){
6234         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6235         fn = fn || o.fn; scope = scope || o.scope;
6236         var el = Roo.getDom(element);
6237         
6238         
6239         if(!el){
6240             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6241         }
6242         
6243         if (ename == 'transitionend') {
6244             ename = transitionEnd();
6245         }
6246         var h = function(e){
6247             e = Roo.EventObject.setEvent(e);
6248             var t;
6249             if(o.delegate){
6250                 t = e.getTarget(o.delegate, el);
6251                 if(!t){
6252                     return;
6253                 }
6254             }else{
6255                 t = e.target;
6256             }
6257             if(o.stopEvent === true){
6258                 e.stopEvent();
6259             }
6260             if(o.preventDefault === true){
6261                e.preventDefault();
6262             }
6263             if(o.stopPropagation === true){
6264                 e.stopPropagation();
6265             }
6266
6267             if(o.normalized === false){
6268                 e = e.browserEvent;
6269             }
6270
6271             fn.call(scope || el, e, t, o);
6272         };
6273         if(o.delay){
6274             h = createDelayed(h, o);
6275         }
6276         if(o.single){
6277             h = createSingle(h, el, ename, fn);
6278         }
6279         if(o.buffer){
6280             h = createBuffered(h, o);
6281         }
6282         
6283         fn._handlers = fn._handlers || [];
6284         
6285         
6286         fn._handlers.push([Roo.id(el), ename, h]);
6287         
6288         
6289          
6290         E.on(el, ename, h);
6291         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6292             el.addEventListener("DOMMouseScroll", h, false);
6293             E.on(window, 'unload', function(){
6294                 el.removeEventListener("DOMMouseScroll", h, false);
6295             });
6296         }
6297         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6298             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6299         }
6300         return h;
6301     };
6302
6303     var stopListening = function(el, ename, fn){
6304         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6305         if(hds){
6306             for(var i = 0, len = hds.length; i < len; i++){
6307                 var h = hds[i];
6308                 if(h[0] == id && h[1] == ename){
6309                     hd = h[2];
6310                     hds.splice(i, 1);
6311                     break;
6312                 }
6313             }
6314         }
6315         E.un(el, ename, hd);
6316         el = Roo.getDom(el);
6317         if(ename == "mousewheel" && el.addEventListener){
6318             el.removeEventListener("DOMMouseScroll", hd, false);
6319         }
6320         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6321             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6322         }
6323     };
6324
6325     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6326     
6327     var pub = {
6328         
6329         
6330         /** 
6331          * Fix for doc tools
6332          * @scope Roo.EventManager
6333          */
6334         
6335         
6336         /** 
6337          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6338          * object with a Roo.EventObject
6339          * @param {Function} fn        The method the event invokes
6340          * @param {Object}   scope    An object that becomes the scope of the handler
6341          * @param {boolean}  override If true, the obj passed in becomes
6342          *                             the execution scope of the listener
6343          * @return {Function} The wrapped function
6344          * @deprecated
6345          */
6346         wrap : function(fn, scope, override){
6347             return function(e){
6348                 Roo.EventObject.setEvent(e);
6349                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6350             };
6351         },
6352         
6353         /**
6354      * Appends an event handler to an element (shorthand for addListener)
6355      * @param {String/HTMLElement}   element        The html element or id to assign the
6356      * @param {String}   eventName The type of event to listen for
6357      * @param {Function} handler The method the event invokes
6358      * @param {Object}   scope (optional) The scope in which to execute the handler
6359      * function. The handler function's "this" context.
6360      * @param {Object}   options (optional) An object containing handler configuration
6361      * properties. This may contain any of the following properties:<ul>
6362      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6363      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6364      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6365      * <li>preventDefault {Boolean} True to prevent the default action</li>
6366      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6367      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6368      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6369      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6370      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6371      * by the specified number of milliseconds. If the event fires again within that time, the original
6372      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6373      * </ul><br>
6374      * <p>
6375      * <b>Combining Options</b><br>
6376      * Using the options argument, it is possible to combine different types of listeners:<br>
6377      * <br>
6378      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6379      * Code:<pre><code>
6380 el.on('click', this.onClick, this, {
6381     single: true,
6382     delay: 100,
6383     stopEvent : true,
6384     forumId: 4
6385 });</code></pre>
6386      * <p>
6387      * <b>Attaching multiple handlers in 1 call</b><br>
6388       * The method also allows for a single argument to be passed which is a config object containing properties
6389      * which specify multiple handlers.
6390      * <p>
6391      * Code:<pre><code>
6392 el.on({
6393     'click' : {
6394         fn: this.onClick
6395         scope: this,
6396         delay: 100
6397     },
6398     'mouseover' : {
6399         fn: this.onMouseOver
6400         scope: this
6401     },
6402     'mouseout' : {
6403         fn: this.onMouseOut
6404         scope: this
6405     }
6406 });</code></pre>
6407      * <p>
6408      * Or a shorthand syntax:<br>
6409      * Code:<pre><code>
6410 el.on({
6411     'click' : this.onClick,
6412     'mouseover' : this.onMouseOver,
6413     'mouseout' : this.onMouseOut
6414     scope: this
6415 });</code></pre>
6416      */
6417         addListener : function(element, eventName, fn, scope, options){
6418             if(typeof eventName == "object"){
6419                 var o = eventName;
6420                 for(var e in o){
6421                     if(propRe.test(e)){
6422                         continue;
6423                     }
6424                     if(typeof o[e] == "function"){
6425                         // shared options
6426                         listen(element, e, o, o[e], o.scope);
6427                     }else{
6428                         // individual options
6429                         listen(element, e, o[e]);
6430                     }
6431                 }
6432                 return;
6433             }
6434             return listen(element, eventName, options, fn, scope);
6435         },
6436         
6437         /**
6438          * Removes an event handler
6439          *
6440          * @param {String/HTMLElement}   element        The id or html element to remove the 
6441          *                             event from
6442          * @param {String}   eventName     The type of event
6443          * @param {Function} fn
6444          * @return {Boolean} True if a listener was actually removed
6445          */
6446         removeListener : function(element, eventName, fn){
6447             return stopListening(element, eventName, fn);
6448         },
6449         
6450         /**
6451          * Fires when the document is ready (before onload and before images are loaded). Can be 
6452          * accessed shorthanded Roo.onReady().
6453          * @param {Function} fn        The method the event invokes
6454          * @param {Object}   scope    An  object that becomes the scope of the handler
6455          * @param {boolean}  options
6456          */
6457         onDocumentReady : function(fn, scope, options){
6458             if(docReadyState){ // if it already fired
6459                 docReadyEvent.addListener(fn, scope, options);
6460                 docReadyEvent.fire();
6461                 docReadyEvent.clearListeners();
6462                 return;
6463             }
6464             if(!docReadyEvent){
6465                 initDocReady();
6466             }
6467             docReadyEvent.addListener(fn, scope, options);
6468         },
6469         
6470         /**
6471          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6472          * @param {Function} fn        The method the event invokes
6473          * @param {Object}   scope    An object that becomes the scope of the handler
6474          * @param {boolean}  options
6475          */
6476         onWindowResize : function(fn, scope, options){
6477             if(!resizeEvent){
6478                 resizeEvent = new Roo.util.Event();
6479                 resizeTask = new Roo.util.DelayedTask(function(){
6480                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6481                 });
6482                 E.on(window, "resize", function(){
6483                     if(Roo.isIE){
6484                         resizeTask.delay(50);
6485                     }else{
6486                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6487                     }
6488                 });
6489             }
6490             resizeEvent.addListener(fn, scope, options);
6491         },
6492
6493         /**
6494          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6495          * @param {Function} fn        The method the event invokes
6496          * @param {Object}   scope    An object that becomes the scope of the handler
6497          * @param {boolean}  options
6498          */
6499         onTextResize : function(fn, scope, options){
6500             if(!textEvent){
6501                 textEvent = new Roo.util.Event();
6502                 var textEl = new Roo.Element(document.createElement('div'));
6503                 textEl.dom.className = 'x-text-resize';
6504                 textEl.dom.innerHTML = 'X';
6505                 textEl.appendTo(document.body);
6506                 textSize = textEl.dom.offsetHeight;
6507                 setInterval(function(){
6508                     if(textEl.dom.offsetHeight != textSize){
6509                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6510                     }
6511                 }, this.textResizeInterval);
6512             }
6513             textEvent.addListener(fn, scope, options);
6514         },
6515
6516         /**
6517          * Removes the passed window resize listener.
6518          * @param {Function} fn        The method the event invokes
6519          * @param {Object}   scope    The scope of handler
6520          */
6521         removeResizeListener : function(fn, scope){
6522             if(resizeEvent){
6523                 resizeEvent.removeListener(fn, scope);
6524             }
6525         },
6526
6527         // private
6528         fireResize : function(){
6529             if(resizeEvent){
6530                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6531             }   
6532         },
6533         /**
6534          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6535          */
6536         ieDeferSrc : false,
6537         /**
6538          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6539          */
6540         textResizeInterval : 50
6541     };
6542     
6543     /**
6544      * Fix for doc tools
6545      * @scopeAlias pub=Roo.EventManager
6546      */
6547     
6548      /**
6549      * Appends an event handler to an element (shorthand for addListener)
6550      * @param {String/HTMLElement}   element        The html element or id to assign the
6551      * @param {String}   eventName The type of event to listen for
6552      * @param {Function} handler The method the event invokes
6553      * @param {Object}   scope (optional) The scope in which to execute the handler
6554      * function. The handler function's "this" context.
6555      * @param {Object}   options (optional) An object containing handler configuration
6556      * properties. This may contain any of the following properties:<ul>
6557      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6558      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6559      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6560      * <li>preventDefault {Boolean} True to prevent the default action</li>
6561      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6562      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6563      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6564      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6565      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6566      * by the specified number of milliseconds. If the event fires again within that time, the original
6567      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6568      * </ul><br>
6569      * <p>
6570      * <b>Combining Options</b><br>
6571      * Using the options argument, it is possible to combine different types of listeners:<br>
6572      * <br>
6573      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6574      * Code:<pre><code>
6575 el.on('click', this.onClick, this, {
6576     single: true,
6577     delay: 100,
6578     stopEvent : true,
6579     forumId: 4
6580 });</code></pre>
6581      * <p>
6582      * <b>Attaching multiple handlers in 1 call</b><br>
6583       * The method also allows for a single argument to be passed which is a config object containing properties
6584      * which specify multiple handlers.
6585      * <p>
6586      * Code:<pre><code>
6587 el.on({
6588     'click' : {
6589         fn: this.onClick
6590         scope: this,
6591         delay: 100
6592     },
6593     'mouseover' : {
6594         fn: this.onMouseOver
6595         scope: this
6596     },
6597     'mouseout' : {
6598         fn: this.onMouseOut
6599         scope: this
6600     }
6601 });</code></pre>
6602      * <p>
6603      * Or a shorthand syntax:<br>
6604      * Code:<pre><code>
6605 el.on({
6606     'click' : this.onClick,
6607     'mouseover' : this.onMouseOver,
6608     'mouseout' : this.onMouseOut
6609     scope: this
6610 });</code></pre>
6611      */
6612     pub.on = pub.addListener;
6613     pub.un = pub.removeListener;
6614
6615     pub.stoppedMouseDownEvent = new Roo.util.Event();
6616     return pub;
6617 }();
6618 /**
6619   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6620   * @param {Function} fn        The method the event invokes
6621   * @param {Object}   scope    An  object that becomes the scope of the handler
6622   * @param {boolean}  override If true, the obj passed in becomes
6623   *                             the execution scope of the listener
6624   * @member Roo
6625   * @method onReady
6626  */
6627 Roo.onReady = Roo.EventManager.onDocumentReady;
6628
6629 Roo.onReady(function(){
6630     var bd = Roo.get(document.body);
6631     if(!bd){ return; }
6632
6633     var cls = [
6634             Roo.isIE ? "roo-ie"
6635             : Roo.isIE11 ? "roo-ie11"
6636             : Roo.isEdge ? "roo-edge"
6637             : Roo.isGecko ? "roo-gecko"
6638             : Roo.isOpera ? "roo-opera"
6639             : Roo.isSafari ? "roo-safari" : ""];
6640
6641     if(Roo.isMac){
6642         cls.push("roo-mac");
6643     }
6644     if(Roo.isLinux){
6645         cls.push("roo-linux");
6646     }
6647     if(Roo.isIOS){
6648         cls.push("roo-ios");
6649     }
6650     if(Roo.isTouch){
6651         cls.push("roo-touch");
6652     }
6653     if(Roo.isBorderBox){
6654         cls.push('roo-border-box');
6655     }
6656     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6657         var p = bd.dom.parentNode;
6658         if(p){
6659             p.className += ' roo-strict';
6660         }
6661     }
6662     bd.addClass(cls.join(' '));
6663 });
6664
6665 /**
6666  * @class Roo.EventObject
6667  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6668  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6669  * Example:
6670  * <pre><code>
6671  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6672     e.preventDefault();
6673     var target = e.getTarget();
6674     ...
6675  }
6676  var myDiv = Roo.get("myDiv");
6677  myDiv.on("click", handleClick);
6678  //or
6679  Roo.EventManager.on("myDiv", 'click', handleClick);
6680  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6681  </code></pre>
6682  * @singleton
6683  */
6684 Roo.EventObject = function(){
6685     
6686     var E = Roo.lib.Event;
6687     
6688     // safari keypress events for special keys return bad keycodes
6689     var safariKeys = {
6690         63234 : 37, // left
6691         63235 : 39, // right
6692         63232 : 38, // up
6693         63233 : 40, // down
6694         63276 : 33, // page up
6695         63277 : 34, // page down
6696         63272 : 46, // delete
6697         63273 : 36, // home
6698         63275 : 35  // end
6699     };
6700
6701     // normalize button clicks
6702     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6703                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6704
6705     Roo.EventObjectImpl = function(e){
6706         if(e){
6707             this.setEvent(e.browserEvent || e);
6708         }
6709     };
6710     Roo.EventObjectImpl.prototype = {
6711         /**
6712          * Used to fix doc tools.
6713          * @scope Roo.EventObject.prototype
6714          */
6715             
6716
6717         
6718         
6719         /** The normal browser event */
6720         browserEvent : null,
6721         /** The button pressed in a mouse event */
6722         button : -1,
6723         /** True if the shift key was down during the event */
6724         shiftKey : false,
6725         /** True if the control key was down during the event */
6726         ctrlKey : false,
6727         /** True if the alt key was down during the event */
6728         altKey : false,
6729
6730         /** Key constant 
6731         * @type Number */
6732         BACKSPACE : 8,
6733         /** Key constant 
6734         * @type Number */
6735         TAB : 9,
6736         /** Key constant 
6737         * @type Number */
6738         RETURN : 13,
6739         /** Key constant 
6740         * @type Number */
6741         ENTER : 13,
6742         /** Key constant 
6743         * @type Number */
6744         SHIFT : 16,
6745         /** Key constant 
6746         * @type Number */
6747         CONTROL : 17,
6748         /** Key constant 
6749         * @type Number */
6750         ESC : 27,
6751         /** Key constant 
6752         * @type Number */
6753         SPACE : 32,
6754         /** Key constant 
6755         * @type Number */
6756         PAGEUP : 33,
6757         /** Key constant 
6758         * @type Number */
6759         PAGEDOWN : 34,
6760         /** Key constant 
6761         * @type Number */
6762         END : 35,
6763         /** Key constant 
6764         * @type Number */
6765         HOME : 36,
6766         /** Key constant 
6767         * @type Number */
6768         LEFT : 37,
6769         /** Key constant 
6770         * @type Number */
6771         UP : 38,
6772         /** Key constant 
6773         * @type Number */
6774         RIGHT : 39,
6775         /** Key constant 
6776         * @type Number */
6777         DOWN : 40,
6778         /** Key constant 
6779         * @type Number */
6780         DELETE : 46,
6781         /** Key constant 
6782         * @type Number */
6783         F5 : 116,
6784
6785            /** @private */
6786         setEvent : function(e){
6787             if(e == this || (e && e.browserEvent)){ // already wrapped
6788                 return e;
6789             }
6790             this.browserEvent = e;
6791             if(e){
6792                 // normalize buttons
6793                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6794                 if(e.type == 'click' && this.button == -1){
6795                     this.button = 0;
6796                 }
6797                 this.type = e.type;
6798                 this.shiftKey = e.shiftKey;
6799                 // mac metaKey behaves like ctrlKey
6800                 this.ctrlKey = e.ctrlKey || e.metaKey;
6801                 this.altKey = e.altKey;
6802                 // in getKey these will be normalized for the mac
6803                 this.keyCode = e.keyCode;
6804                 // keyup warnings on firefox.
6805                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6806                 // cache the target for the delayed and or buffered events
6807                 this.target = E.getTarget(e);
6808                 // same for XY
6809                 this.xy = E.getXY(e);
6810             }else{
6811                 this.button = -1;
6812                 this.shiftKey = false;
6813                 this.ctrlKey = false;
6814                 this.altKey = false;
6815                 this.keyCode = 0;
6816                 this.charCode =0;
6817                 this.target = null;
6818                 this.xy = [0, 0];
6819             }
6820             return this;
6821         },
6822
6823         /**
6824          * Stop the event (preventDefault and stopPropagation)
6825          */
6826         stopEvent : function(){
6827             if(this.browserEvent){
6828                 if(this.browserEvent.type == 'mousedown'){
6829                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6830                 }
6831                 E.stopEvent(this.browserEvent);
6832             }
6833         },
6834
6835         /**
6836          * Prevents the browsers default handling of the event.
6837          */
6838         preventDefault : function(){
6839             if(this.browserEvent){
6840                 E.preventDefault(this.browserEvent);
6841             }
6842         },
6843
6844         /** @private */
6845         isNavKeyPress : function(){
6846             var k = this.keyCode;
6847             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6848             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6849         },
6850
6851         isSpecialKey : function(){
6852             var k = this.keyCode;
6853             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6854             (k == 16) || (k == 17) ||
6855             (k >= 18 && k <= 20) ||
6856             (k >= 33 && k <= 35) ||
6857             (k >= 36 && k <= 39) ||
6858             (k >= 44 && k <= 45);
6859         },
6860         /**
6861          * Cancels bubbling of the event.
6862          */
6863         stopPropagation : function(){
6864             if(this.browserEvent){
6865                 if(this.type == 'mousedown'){
6866                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6867                 }
6868                 E.stopPropagation(this.browserEvent);
6869             }
6870         },
6871
6872         /**
6873          * Gets the key code for the event.
6874          * @return {Number}
6875          */
6876         getCharCode : function(){
6877             return this.charCode || this.keyCode;
6878         },
6879
6880         /**
6881          * Returns a normalized keyCode for the event.
6882          * @return {Number} The key code
6883          */
6884         getKey : function(){
6885             var k = this.keyCode || this.charCode;
6886             return Roo.isSafari ? (safariKeys[k] || k) : k;
6887         },
6888
6889         /**
6890          * Gets the x coordinate of the event.
6891          * @return {Number}
6892          */
6893         getPageX : function(){
6894             return this.xy[0];
6895         },
6896
6897         /**
6898          * Gets the y coordinate of the event.
6899          * @return {Number}
6900          */
6901         getPageY : function(){
6902             return this.xy[1];
6903         },
6904
6905         /**
6906          * Gets the time of the event.
6907          * @return {Number}
6908          */
6909         getTime : function(){
6910             if(this.browserEvent){
6911                 return E.getTime(this.browserEvent);
6912             }
6913             return null;
6914         },
6915
6916         /**
6917          * Gets the page coordinates of the event.
6918          * @return {Array} The xy values like [x, y]
6919          */
6920         getXY : function(){
6921             return this.xy;
6922         },
6923
6924         /**
6925          * Gets the target for the event.
6926          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6927          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6928                 search as a number or element (defaults to 10 || document.body)
6929          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6930          * @return {HTMLelement}
6931          */
6932         getTarget : function(selector, maxDepth, returnEl){
6933             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6934         },
6935         /**
6936          * Gets the related target.
6937          * @return {HTMLElement}
6938          */
6939         getRelatedTarget : function(){
6940             if(this.browserEvent){
6941                 return E.getRelatedTarget(this.browserEvent);
6942             }
6943             return null;
6944         },
6945
6946         /**
6947          * Normalizes mouse wheel delta across browsers
6948          * @return {Number} The delta
6949          */
6950         getWheelDelta : function(){
6951             var e = this.browserEvent;
6952             var delta = 0;
6953             if(e.wheelDelta){ /* IE/Opera. */
6954                 delta = e.wheelDelta/120;
6955             }else if(e.detail){ /* Mozilla case. */
6956                 delta = -e.detail/3;
6957             }
6958             return delta;
6959         },
6960
6961         /**
6962          * Returns true if the control, meta, shift or alt key was pressed during this event.
6963          * @return {Boolean}
6964          */
6965         hasModifier : function(){
6966             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6967         },
6968
6969         /**
6970          * Returns true if the target of this event equals el or is a child of el
6971          * @param {String/HTMLElement/Element} el
6972          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6973          * @return {Boolean}
6974          */
6975         within : function(el, related){
6976             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6977             return t && Roo.fly(el).contains(t);
6978         },
6979
6980         getPoint : function(){
6981             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6982         }
6983     };
6984
6985     return new Roo.EventObjectImpl();
6986 }();
6987             
6988     /*
6989  * Based on:
6990  * Ext JS Library 1.1.1
6991  * Copyright(c) 2006-2007, Ext JS, LLC.
6992  *
6993  * Originally Released Under LGPL - original licence link has changed is not relivant.
6994  *
6995  * Fork - LGPL
6996  * <script type="text/javascript">
6997  */
6998
6999  
7000 // was in Composite Element!??!?!
7001  
7002 (function(){
7003     var D = Roo.lib.Dom;
7004     var E = Roo.lib.Event;
7005     var A = Roo.lib.Anim;
7006
7007     // local style camelizing for speed
7008     var propCache = {};
7009     var camelRe = /(-[a-z])/gi;
7010     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7011     var view = document.defaultView;
7012
7013 /**
7014  * @class Roo.Element
7015  * Represents an Element in the DOM.<br><br>
7016  * Usage:<br>
7017 <pre><code>
7018 var el = Roo.get("my-div");
7019
7020 // or with getEl
7021 var el = getEl("my-div");
7022
7023 // or with a DOM element
7024 var el = Roo.get(myDivElement);
7025 </code></pre>
7026  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7027  * each call instead of constructing a new one.<br><br>
7028  * <b>Animations</b><br />
7029  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7030  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7031 <pre>
7032 Option    Default   Description
7033 --------- --------  ---------------------------------------------
7034 duration  .35       The duration of the animation in seconds
7035 easing    easeOut   The YUI easing method
7036 callback  none      A function to execute when the anim completes
7037 scope     this      The scope (this) of the callback function
7038 </pre>
7039 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7040 * manipulate the animation. Here's an example:
7041 <pre><code>
7042 var el = Roo.get("my-div");
7043
7044 // no animation
7045 el.setWidth(100);
7046
7047 // default animation
7048 el.setWidth(100, true);
7049
7050 // animation with some options set
7051 el.setWidth(100, {
7052     duration: 1,
7053     callback: this.foo,
7054     scope: this
7055 });
7056
7057 // using the "anim" property to get the Anim object
7058 var opt = {
7059     duration: 1,
7060     callback: this.foo,
7061     scope: this
7062 };
7063 el.setWidth(100, opt);
7064 ...
7065 if(opt.anim.isAnimated()){
7066     opt.anim.stop();
7067 }
7068 </code></pre>
7069 * <b> Composite (Collections of) Elements</b><br />
7070  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7071  * @constructor Create a new Element directly.
7072  * @param {String/HTMLElement} element
7073  * @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).
7074  */
7075     Roo.Element = function(element, forceNew){
7076         var dom = typeof element == "string" ?
7077                 document.getElementById(element) : element;
7078         if(!dom){ // invalid id/element
7079             return null;
7080         }
7081         var id = dom.id;
7082         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7083             return Roo.Element.cache[id];
7084         }
7085
7086         /**
7087          * The DOM element
7088          * @type HTMLElement
7089          */
7090         this.dom = dom;
7091
7092         /**
7093          * The DOM element ID
7094          * @type String
7095          */
7096         this.id = id || Roo.id(dom);
7097     };
7098
7099     var El = Roo.Element;
7100
7101     El.prototype = {
7102         /**
7103          * The element's default display mode  (defaults to "")
7104          * @type String
7105          */
7106         originalDisplay : "",
7107
7108         visibilityMode : 1,
7109         /**
7110          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7111          * @type String
7112          */
7113         defaultUnit : "px",
7114         
7115         /**
7116          * Sets the element's visibility mode. When setVisible() is called it
7117          * will use this to determine whether to set the visibility or the display property.
7118          * @param visMode Element.VISIBILITY or Element.DISPLAY
7119          * @return {Roo.Element} this
7120          */
7121         setVisibilityMode : function(visMode){
7122             this.visibilityMode = visMode;
7123             return this;
7124         },
7125         /**
7126          * Convenience method for setVisibilityMode(Element.DISPLAY)
7127          * @param {String} display (optional) What to set display to when visible
7128          * @return {Roo.Element} this
7129          */
7130         enableDisplayMode : function(display){
7131             this.setVisibilityMode(El.DISPLAY);
7132             if(typeof display != "undefined") { this.originalDisplay = display; }
7133             return this;
7134         },
7135
7136         /**
7137          * 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)
7138          * @param {String} selector The simple selector to test
7139          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7140                 search as a number or element (defaults to 10 || document.body)
7141          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7142          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7143          */
7144         findParent : function(simpleSelector, maxDepth, returnEl){
7145             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7146             maxDepth = maxDepth || 50;
7147             if(typeof maxDepth != "number"){
7148                 stopEl = Roo.getDom(maxDepth);
7149                 maxDepth = 10;
7150             }
7151             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7152                 if(dq.is(p, simpleSelector)){
7153                     return returnEl ? Roo.get(p) : p;
7154                 }
7155                 depth++;
7156                 p = p.parentNode;
7157             }
7158             return null;
7159         },
7160
7161
7162         /**
7163          * Looks 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         findParentNode : function(simpleSelector, maxDepth, returnEl){
7171             var p = Roo.fly(this.dom.parentNode, '_internal');
7172             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7173         },
7174         
7175         /**
7176          * Looks at  the scrollable parent element
7177          */
7178         findScrollableParent : function()
7179         {
7180             var overflowRegex = /(auto|scroll)/;
7181             
7182             if(this.getStyle('position') === 'fixed'){
7183                 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7184             }
7185             
7186             var excludeStaticParent = this.getStyle('position') === "absolute";
7187             
7188             for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7189                 
7190                 if (excludeStaticParent && parent.getStyle('position') === "static") {
7191                     continue;
7192                 }
7193                 
7194                 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7195                     return parent;
7196                 }
7197                 
7198                 if(parent.dom.nodeName.toLowerCase() == 'body'){
7199                     return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7200                 }
7201             }
7202             
7203             return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7204         },
7205
7206         /**
7207          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7208          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7209          * @param {String} selector The simple selector to test
7210          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7211                 search as a number or element (defaults to 10 || document.body)
7212          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7213          */
7214         up : function(simpleSelector, maxDepth){
7215             return this.findParentNode(simpleSelector, maxDepth, true);
7216         },
7217
7218
7219
7220         /**
7221          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7222          * @param {String} selector The simple selector to test
7223          * @return {Boolean} True if this element matches the selector, else false
7224          */
7225         is : function(simpleSelector){
7226             return Roo.DomQuery.is(this.dom, simpleSelector);
7227         },
7228
7229         /**
7230          * Perform animation on this element.
7231          * @param {Object} args The YUI animation control args
7232          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7233          * @param {Function} onComplete (optional) Function to call when animation completes
7234          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7235          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7236          * @return {Roo.Element} this
7237          */
7238         animate : function(args, duration, onComplete, easing, animType){
7239             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7240             return this;
7241         },
7242
7243         /*
7244          * @private Internal animation call
7245          */
7246         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7247             animType = animType || 'run';
7248             opt = opt || {};
7249             var anim = Roo.lib.Anim[animType](
7250                 this.dom, args,
7251                 (opt.duration || defaultDur) || .35,
7252                 (opt.easing || defaultEase) || 'easeOut',
7253                 function(){
7254                     Roo.callback(cb, this);
7255                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7256                 },
7257                 this
7258             );
7259             opt.anim = anim;
7260             return anim;
7261         },
7262
7263         // private legacy anim prep
7264         preanim : function(a, i){
7265             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7266         },
7267
7268         /**
7269          * Removes worthless text nodes
7270          * @param {Boolean} forceReclean (optional) By default the element
7271          * keeps track if it has been cleaned already so
7272          * you can call this over and over. However, if you update the element and
7273          * need to force a reclean, you can pass true.
7274          */
7275         clean : function(forceReclean){
7276             if(this.isCleaned && forceReclean !== true){
7277                 return this;
7278             }
7279             var ns = /\S/;
7280             var d = this.dom, n = d.firstChild, ni = -1;
7281             while(n){
7282                 var nx = n.nextSibling;
7283                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7284                     d.removeChild(n);
7285                 }else{
7286                     n.nodeIndex = ++ni;
7287                 }
7288                 n = nx;
7289             }
7290             this.isCleaned = true;
7291             return this;
7292         },
7293
7294         // private
7295         calcOffsetsTo : function(el){
7296             el = Roo.get(el);
7297             var d = el.dom;
7298             var restorePos = false;
7299             if(el.getStyle('position') == 'static'){
7300                 el.position('relative');
7301                 restorePos = true;
7302             }
7303             var x = 0, y =0;
7304             var op = this.dom;
7305             while(op && op != d && op.tagName != 'HTML'){
7306                 x+= op.offsetLeft;
7307                 y+= op.offsetTop;
7308                 op = op.offsetParent;
7309             }
7310             if(restorePos){
7311                 el.position('static');
7312             }
7313             return [x, y];
7314         },
7315
7316         /**
7317          * Scrolls this element into view within the passed container.
7318          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7319          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7320          * @return {Roo.Element} this
7321          */
7322         scrollIntoView : function(container, hscroll){
7323             var c = Roo.getDom(container) || document.body;
7324             var el = this.dom;
7325
7326             var o = this.calcOffsetsTo(c),
7327                 l = o[0],
7328                 t = o[1],
7329                 b = t+el.offsetHeight,
7330                 r = l+el.offsetWidth;
7331
7332             var ch = c.clientHeight;
7333             var ct = parseInt(c.scrollTop, 10);
7334             var cl = parseInt(c.scrollLeft, 10);
7335             var cb = ct + ch;
7336             var cr = cl + c.clientWidth;
7337
7338             if(t < ct){
7339                 c.scrollTop = t;
7340             }else if(b > cb){
7341                 c.scrollTop = b-ch;
7342             }
7343
7344             if(hscroll !== false){
7345                 if(l < cl){
7346                     c.scrollLeft = l;
7347                 }else if(r > cr){
7348                     c.scrollLeft = r-c.clientWidth;
7349                 }
7350             }
7351             return this;
7352         },
7353
7354         // private
7355         scrollChildIntoView : function(child, hscroll){
7356             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7357         },
7358
7359         /**
7360          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7361          * the new height may not be available immediately.
7362          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7363          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7364          * @param {Function} onComplete (optional) Function to call when animation completes
7365          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7366          * @return {Roo.Element} this
7367          */
7368         autoHeight : function(animate, duration, onComplete, easing){
7369             var oldHeight = this.getHeight();
7370             this.clip();
7371             this.setHeight(1); // force clipping
7372             setTimeout(function(){
7373                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7374                 if(!animate){
7375                     this.setHeight(height);
7376                     this.unclip();
7377                     if(typeof onComplete == "function"){
7378                         onComplete();
7379                     }
7380                 }else{
7381                     this.setHeight(oldHeight); // restore original height
7382                     this.setHeight(height, animate, duration, function(){
7383                         this.unclip();
7384                         if(typeof onComplete == "function") { onComplete(); }
7385                     }.createDelegate(this), easing);
7386                 }
7387             }.createDelegate(this), 0);
7388             return this;
7389         },
7390
7391         /**
7392          * Returns true if this element is an ancestor of the passed element
7393          * @param {HTMLElement/String} el The element to check
7394          * @return {Boolean} True if this element is an ancestor of el, else false
7395          */
7396         contains : function(el){
7397             if(!el){return false;}
7398             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7399         },
7400
7401         /**
7402          * Checks whether the element is currently visible using both visibility and display properties.
7403          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7404          * @return {Boolean} True if the element is currently visible, else false
7405          */
7406         isVisible : function(deep) {
7407             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7408             if(deep !== true || !vis){
7409                 return vis;
7410             }
7411             var p = this.dom.parentNode;
7412             while(p && p.tagName.toLowerCase() != "body"){
7413                 if(!Roo.fly(p, '_isVisible').isVisible()){
7414                     return false;
7415                 }
7416                 p = p.parentNode;
7417             }
7418             return true;
7419         },
7420
7421         /**
7422          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7423          * @param {String} selector The CSS selector
7424          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7425          * @return {CompositeElement/CompositeElementLite} The composite element
7426          */
7427         select : function(selector, unique){
7428             return El.select(selector, unique, this.dom);
7429         },
7430
7431         /**
7432          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7433          * @param {String} selector The CSS selector
7434          * @return {Array} An array of the matched nodes
7435          */
7436         query : function(selector, unique){
7437             return Roo.DomQuery.select(selector, this.dom);
7438         },
7439
7440         /**
7441          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7442          * @param {String} selector The CSS selector
7443          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7444          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7445          */
7446         child : function(selector, returnDom){
7447             var n = Roo.DomQuery.selectNode(selector, this.dom);
7448             return returnDom ? n : Roo.get(n);
7449         },
7450
7451         /**
7452          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7453          * @param {String} selector The CSS selector
7454          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7455          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7456          */
7457         down : function(selector, returnDom){
7458             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7459             return returnDom ? n : Roo.get(n);
7460         },
7461
7462         /**
7463          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7464          * @param {String} group The group the DD object is member of
7465          * @param {Object} config The DD config object
7466          * @param {Object} overrides An object containing methods to override/implement on the DD object
7467          * @return {Roo.dd.DD} The DD object
7468          */
7469         initDD : function(group, config, overrides){
7470             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7471             return Roo.apply(dd, overrides);
7472         },
7473
7474         /**
7475          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7476          * @param {String} group The group the DDProxy object is member of
7477          * @param {Object} config The DDProxy config object
7478          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7479          * @return {Roo.dd.DDProxy} The DDProxy object
7480          */
7481         initDDProxy : function(group, config, overrides){
7482             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7483             return Roo.apply(dd, overrides);
7484         },
7485
7486         /**
7487          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7488          * @param {String} group The group the DDTarget object is member of
7489          * @param {Object} config The DDTarget config object
7490          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7491          * @return {Roo.dd.DDTarget} The DDTarget object
7492          */
7493         initDDTarget : function(group, config, overrides){
7494             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7495             return Roo.apply(dd, overrides);
7496         },
7497
7498         /**
7499          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7500          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7501          * @param {Boolean} visible Whether the element is visible
7502          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7503          * @return {Roo.Element} this
7504          */
7505          setVisible : function(visible, animate){
7506             if(!animate || !A){
7507                 if(this.visibilityMode == El.DISPLAY){
7508                     this.setDisplayed(visible);
7509                 }else{
7510                     this.fixDisplay();
7511                     this.dom.style.visibility = visible ? "visible" : "hidden";
7512                 }
7513             }else{
7514                 // closure for composites
7515                 var dom = this.dom;
7516                 var visMode = this.visibilityMode;
7517                 if(visible){
7518                     this.setOpacity(.01);
7519                     this.setVisible(true);
7520                 }
7521                 this.anim({opacity: { to: (visible?1:0) }},
7522                       this.preanim(arguments, 1),
7523                       null, .35, 'easeIn', function(){
7524                          if(!visible){
7525                              if(visMode == El.DISPLAY){
7526                                  dom.style.display = "none";
7527                              }else{
7528                                  dom.style.visibility = "hidden";
7529                              }
7530                              Roo.get(dom).setOpacity(1);
7531                          }
7532                      });
7533             }
7534             return this;
7535         },
7536
7537         /**
7538          * Returns true if display is not "none"
7539          * @return {Boolean}
7540          */
7541         isDisplayed : function() {
7542             return this.getStyle("display") != "none";
7543         },
7544
7545         /**
7546          * Toggles the element's visibility or display, depending on visibility mode.
7547          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7548          * @return {Roo.Element} this
7549          */
7550         toggle : function(animate){
7551             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7552             return this;
7553         },
7554
7555         /**
7556          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7557          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7558          * @return {Roo.Element} this
7559          */
7560         setDisplayed : function(value) {
7561             if(typeof value == "boolean"){
7562                value = value ? this.originalDisplay : "none";
7563             }
7564             this.setStyle("display", value);
7565             return this;
7566         },
7567
7568         /**
7569          * Tries to focus the element. Any exceptions are caught and ignored.
7570          * @return {Roo.Element} this
7571          */
7572         focus : function() {
7573             try{
7574                 this.dom.focus();
7575             }catch(e){}
7576             return this;
7577         },
7578
7579         /**
7580          * Tries to blur the element. Any exceptions are caught and ignored.
7581          * @return {Roo.Element} this
7582          */
7583         blur : function() {
7584             try{
7585                 this.dom.blur();
7586             }catch(e){}
7587             return this;
7588         },
7589
7590         /**
7591          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7592          * @param {String/Array} className The CSS class to add, or an array of classes
7593          * @return {Roo.Element} this
7594          */
7595         addClass : function(className){
7596             if(className instanceof Array){
7597                 for(var i = 0, len = className.length; i < len; i++) {
7598                     this.addClass(className[i]);
7599                 }
7600             }else{
7601                 if(className && !this.hasClass(className)){
7602                     this.dom.className = this.dom.className + " " + className;
7603                 }
7604             }
7605             return this;
7606         },
7607
7608         /**
7609          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7610          * @param {String/Array} className The CSS class to add, or an array of classes
7611          * @return {Roo.Element} this
7612          */
7613         radioClass : function(className){
7614             var siblings = this.dom.parentNode.childNodes;
7615             for(var i = 0; i < siblings.length; i++) {
7616                 var s = siblings[i];
7617                 if(s.nodeType == 1){
7618                     Roo.get(s).removeClass(className);
7619                 }
7620             }
7621             this.addClass(className);
7622             return this;
7623         },
7624
7625         /**
7626          * Removes one or more CSS classes from the element.
7627          * @param {String/Array} className The CSS class to remove, or an array of classes
7628          * @return {Roo.Element} this
7629          */
7630         removeClass : function(className){
7631             if(!className || !this.dom.className){
7632                 return this;
7633             }
7634             if(className instanceof Array){
7635                 for(var i = 0, len = className.length; i < len; i++) {
7636                     this.removeClass(className[i]);
7637                 }
7638             }else{
7639                 if(this.hasClass(className)){
7640                     var re = this.classReCache[className];
7641                     if (!re) {
7642                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7643                        this.classReCache[className] = re;
7644                     }
7645                     this.dom.className =
7646                         this.dom.className.replace(re, " ");
7647                 }
7648             }
7649             return this;
7650         },
7651
7652         // private
7653         classReCache: {},
7654
7655         /**
7656          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7657          * @param {String} className The CSS class to toggle
7658          * @return {Roo.Element} this
7659          */
7660         toggleClass : function(className){
7661             if(this.hasClass(className)){
7662                 this.removeClass(className);
7663             }else{
7664                 this.addClass(className);
7665             }
7666             return this;
7667         },
7668
7669         /**
7670          * Checks if the specified CSS class exists on this element's DOM node.
7671          * @param {String} className The CSS class to check for
7672          * @return {Boolean} True if the class exists, else false
7673          */
7674         hasClass : function(className){
7675             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7676         },
7677
7678         /**
7679          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7680          * @param {String} oldClassName The CSS class to replace
7681          * @param {String} newClassName The replacement CSS class
7682          * @return {Roo.Element} this
7683          */
7684         replaceClass : function(oldClassName, newClassName){
7685             this.removeClass(oldClassName);
7686             this.addClass(newClassName);
7687             return this;
7688         },
7689
7690         /**
7691          * Returns an object with properties matching the styles requested.
7692          * For example, el.getStyles('color', 'font-size', 'width') might return
7693          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7694          * @param {String} style1 A style name
7695          * @param {String} style2 A style name
7696          * @param {String} etc.
7697          * @return {Object} The style object
7698          */
7699         getStyles : function(){
7700             var a = arguments, len = a.length, r = {};
7701             for(var i = 0; i < len; i++){
7702                 r[a[i]] = this.getStyle(a[i]);
7703             }
7704             return r;
7705         },
7706
7707         /**
7708          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7709          * @param {String} property The style property whose value is returned.
7710          * @return {String} The current value of the style property for this element.
7711          */
7712         getStyle : function(){
7713             return view && view.getComputedStyle ?
7714                 function(prop){
7715                     var el = this.dom, v, cs, camel;
7716                     if(prop == 'float'){
7717                         prop = "cssFloat";
7718                     }
7719                     if(el.style && (v = el.style[prop])){
7720                         return v;
7721                     }
7722                     if(cs = view.getComputedStyle(el, "")){
7723                         if(!(camel = propCache[prop])){
7724                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7725                         }
7726                         return cs[camel];
7727                     }
7728                     return null;
7729                 } :
7730                 function(prop){
7731                     var el = this.dom, v, cs, camel;
7732                     if(prop == 'opacity'){
7733                         if(typeof el.style.filter == 'string'){
7734                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7735                             if(m){
7736                                 var fv = parseFloat(m[1]);
7737                                 if(!isNaN(fv)){
7738                                     return fv ? fv / 100 : 0;
7739                                 }
7740                             }
7741                         }
7742                         return 1;
7743                     }else if(prop == 'float'){
7744                         prop = "styleFloat";
7745                     }
7746                     if(!(camel = propCache[prop])){
7747                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7748                     }
7749                     if(v = el.style[camel]){
7750                         return v;
7751                     }
7752                     if(cs = el.currentStyle){
7753                         return cs[camel];
7754                     }
7755                     return null;
7756                 };
7757         }(),
7758
7759         /**
7760          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7761          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7762          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7763          * @return {Roo.Element} this
7764          */
7765         setStyle : function(prop, value){
7766             if(typeof prop == "string"){
7767                 
7768                 if (prop == 'float') {
7769                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7770                     return this;
7771                 }
7772                 
7773                 var camel;
7774                 if(!(camel = propCache[prop])){
7775                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7776                 }
7777                 
7778                 if(camel == 'opacity') {
7779                     this.setOpacity(value);
7780                 }else{
7781                     this.dom.style[camel] = value;
7782                 }
7783             }else{
7784                 for(var style in prop){
7785                     if(typeof prop[style] != "function"){
7786                        this.setStyle(style, prop[style]);
7787                     }
7788                 }
7789             }
7790             return this;
7791         },
7792
7793         /**
7794          * More flexible version of {@link #setStyle} for setting style properties.
7795          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7796          * a function which returns such a specification.
7797          * @return {Roo.Element} this
7798          */
7799         applyStyles : function(style){
7800             Roo.DomHelper.applyStyles(this.dom, style);
7801             return this;
7802         },
7803
7804         /**
7805           * 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).
7806           * @return {Number} The X position of the element
7807           */
7808         getX : function(){
7809             return D.getX(this.dom);
7810         },
7811
7812         /**
7813           * 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).
7814           * @return {Number} The Y position of the element
7815           */
7816         getY : function(){
7817             return D.getY(this.dom);
7818         },
7819
7820         /**
7821           * 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).
7822           * @return {Array} The XY position of the element
7823           */
7824         getXY : function(){
7825             return D.getXY(this.dom);
7826         },
7827
7828         /**
7829          * 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).
7830          * @param {Number} The X position of the element
7831          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7832          * @return {Roo.Element} this
7833          */
7834         setX : function(x, animate){
7835             if(!animate || !A){
7836                 D.setX(this.dom, x);
7837             }else{
7838                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7839             }
7840             return this;
7841         },
7842
7843         /**
7844          * 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).
7845          * @param {Number} The Y position of the element
7846          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7847          * @return {Roo.Element} this
7848          */
7849         setY : function(y, animate){
7850             if(!animate || !A){
7851                 D.setY(this.dom, y);
7852             }else{
7853                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7854             }
7855             return this;
7856         },
7857
7858         /**
7859          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7860          * @param {String} left The left CSS property value
7861          * @return {Roo.Element} this
7862          */
7863         setLeft : function(left){
7864             this.setStyle("left", this.addUnits(left));
7865             return this;
7866         },
7867
7868         /**
7869          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7870          * @param {String} top The top CSS property value
7871          * @return {Roo.Element} this
7872          */
7873         setTop : function(top){
7874             this.setStyle("top", this.addUnits(top));
7875             return this;
7876         },
7877
7878         /**
7879          * Sets the element's CSS right style.
7880          * @param {String} right The right CSS property value
7881          * @return {Roo.Element} this
7882          */
7883         setRight : function(right){
7884             this.setStyle("right", this.addUnits(right));
7885             return this;
7886         },
7887
7888         /**
7889          * Sets the element's CSS bottom style.
7890          * @param {String} bottom The bottom CSS property value
7891          * @return {Roo.Element} this
7892          */
7893         setBottom : function(bottom){
7894             this.setStyle("bottom", this.addUnits(bottom));
7895             return this;
7896         },
7897
7898         /**
7899          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7900          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7901          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7902          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7903          * @return {Roo.Element} this
7904          */
7905         setXY : function(pos, animate){
7906             if(!animate || !A){
7907                 D.setXY(this.dom, pos);
7908             }else{
7909                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7910             }
7911             return this;
7912         },
7913
7914         /**
7915          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7916          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7917          * @param {Number} x X value for new position (coordinates are page-based)
7918          * @param {Number} y Y value for new position (coordinates are page-based)
7919          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7920          * @return {Roo.Element} this
7921          */
7922         setLocation : function(x, y, animate){
7923             this.setXY([x, y], this.preanim(arguments, 2));
7924             return this;
7925         },
7926
7927         /**
7928          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7929          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7930          * @param {Number} x X value for new position (coordinates are page-based)
7931          * @param {Number} y Y value for new position (coordinates are page-based)
7932          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7933          * @return {Roo.Element} this
7934          */
7935         moveTo : function(x, y, animate){
7936             this.setXY([x, y], this.preanim(arguments, 2));
7937             return this;
7938         },
7939
7940         /**
7941          * Returns the region of the given element.
7942          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7943          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7944          */
7945         getRegion : function(){
7946             return D.getRegion(this.dom);
7947         },
7948
7949         /**
7950          * Returns the offset height of the element
7951          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7952          * @return {Number} The element's height
7953          */
7954         getHeight : function(contentHeight){
7955             var h = this.dom.offsetHeight || 0;
7956             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7957         },
7958
7959         /**
7960          * Returns the offset width of the element
7961          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7962          * @return {Number} The element's width
7963          */
7964         getWidth : function(contentWidth){
7965             var w = this.dom.offsetWidth || 0;
7966             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7967         },
7968
7969         /**
7970          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7971          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7972          * if a height has not been set using CSS.
7973          * @return {Number}
7974          */
7975         getComputedHeight : function(){
7976             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7977             if(!h){
7978                 h = parseInt(this.getStyle('height'), 10) || 0;
7979                 if(!this.isBorderBox()){
7980                     h += this.getFrameWidth('tb');
7981                 }
7982             }
7983             return h;
7984         },
7985
7986         /**
7987          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7988          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7989          * if a width has not been set using CSS.
7990          * @return {Number}
7991          */
7992         getComputedWidth : function(){
7993             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7994             if(!w){
7995                 w = parseInt(this.getStyle('width'), 10) || 0;
7996                 if(!this.isBorderBox()){
7997                     w += this.getFrameWidth('lr');
7998                 }
7999             }
8000             return w;
8001         },
8002
8003         /**
8004          * Returns the size of the element.
8005          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8006          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8007          */
8008         getSize : function(contentSize){
8009             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8010         },
8011
8012         /**
8013          * Returns the width and height of the viewport.
8014          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8015          */
8016         getViewSize : function(){
8017             var d = this.dom, doc = document, aw = 0, ah = 0;
8018             if(d == doc || d == doc.body){
8019                 return {width : D.getViewWidth(), height: D.getViewHeight()};
8020             }else{
8021                 return {
8022                     width : d.clientWidth,
8023                     height: d.clientHeight
8024                 };
8025             }
8026         },
8027
8028         /**
8029          * Returns the value of the "value" attribute
8030          * @param {Boolean} asNumber true to parse the value as a number
8031          * @return {String/Number}
8032          */
8033         getValue : function(asNumber){
8034             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8035         },
8036
8037         // private
8038         adjustWidth : function(width){
8039             if(typeof width == "number"){
8040                 if(this.autoBoxAdjust && !this.isBorderBox()){
8041                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8042                 }
8043                 if(width < 0){
8044                     width = 0;
8045                 }
8046             }
8047             return width;
8048         },
8049
8050         // private
8051         adjustHeight : function(height){
8052             if(typeof height == "number"){
8053                if(this.autoBoxAdjust && !this.isBorderBox()){
8054                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8055                }
8056                if(height < 0){
8057                    height = 0;
8058                }
8059             }
8060             return height;
8061         },
8062
8063         /**
8064          * Set the width of the element
8065          * @param {Number} width The new width
8066          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8067          * @return {Roo.Element} this
8068          */
8069         setWidth : function(width, animate){
8070             width = this.adjustWidth(width);
8071             if(!animate || !A){
8072                 this.dom.style.width = this.addUnits(width);
8073             }else{
8074                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8075             }
8076             return this;
8077         },
8078
8079         /**
8080          * Set the height of the element
8081          * @param {Number} height The new height
8082          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8083          * @return {Roo.Element} this
8084          */
8085          setHeight : function(height, animate){
8086             height = this.adjustHeight(height);
8087             if(!animate || !A){
8088                 this.dom.style.height = this.addUnits(height);
8089             }else{
8090                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8091             }
8092             return this;
8093         },
8094
8095         /**
8096          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8097          * @param {Number} width The new width
8098          * @param {Number} height The new height
8099          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8100          * @return {Roo.Element} this
8101          */
8102          setSize : function(width, height, animate){
8103             if(typeof width == "object"){ // in case of object from getSize()
8104                 height = width.height; width = width.width;
8105             }
8106             width = this.adjustWidth(width); height = this.adjustHeight(height);
8107             if(!animate || !A){
8108                 this.dom.style.width = this.addUnits(width);
8109                 this.dom.style.height = this.addUnits(height);
8110             }else{
8111                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8112             }
8113             return this;
8114         },
8115
8116         /**
8117          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8118          * @param {Number} x X value for new position (coordinates are page-based)
8119          * @param {Number} y Y value for new position (coordinates are page-based)
8120          * @param {Number} width The new width
8121          * @param {Number} height The new height
8122          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8123          * @return {Roo.Element} this
8124          */
8125         setBounds : function(x, y, width, height, animate){
8126             if(!animate || !A){
8127                 this.setSize(width, height);
8128                 this.setLocation(x, y);
8129             }else{
8130                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8131                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8132                               this.preanim(arguments, 4), 'motion');
8133             }
8134             return this;
8135         },
8136
8137         /**
8138          * 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.
8139          * @param {Roo.lib.Region} region The region to fill
8140          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8141          * @return {Roo.Element} this
8142          */
8143         setRegion : function(region, animate){
8144             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8145             return this;
8146         },
8147
8148         /**
8149          * Appends an event handler
8150          *
8151          * @param {String}   eventName     The type of event to append
8152          * @param {Function} fn        The method the event invokes
8153          * @param {Object} scope       (optional) The scope (this object) of the fn
8154          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8155          */
8156         addListener : function(eventName, fn, scope, options){
8157             if (this.dom) {
8158                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8159             }
8160         },
8161
8162         /**
8163          * Removes an event handler from this element
8164          * @param {String} eventName the type of event to remove
8165          * @param {Function} fn the method the event invokes
8166          * @return {Roo.Element} this
8167          */
8168         removeListener : function(eventName, fn){
8169             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8170             return this;
8171         },
8172
8173         /**
8174          * Removes all previous added listeners from this element
8175          * @return {Roo.Element} this
8176          */
8177         removeAllListeners : function(){
8178             E.purgeElement(this.dom);
8179             return this;
8180         },
8181
8182         relayEvent : function(eventName, observable){
8183             this.on(eventName, function(e){
8184                 observable.fireEvent(eventName, e);
8185             });
8186         },
8187
8188         /**
8189          * Set the opacity of the element
8190          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8191          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8192          * @return {Roo.Element} this
8193          */
8194          setOpacity : function(opacity, animate){
8195             if(!animate || !A){
8196                 var s = this.dom.style;
8197                 if(Roo.isIE){
8198                     s.zoom = 1;
8199                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8200                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8201                 }else{
8202                     s.opacity = opacity;
8203                 }
8204             }else{
8205                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8206             }
8207             return this;
8208         },
8209
8210         /**
8211          * Gets the left X coordinate
8212          * @param {Boolean} local True to get the local css position instead of page coordinate
8213          * @return {Number}
8214          */
8215         getLeft : function(local){
8216             if(!local){
8217                 return this.getX();
8218             }else{
8219                 return parseInt(this.getStyle("left"), 10) || 0;
8220             }
8221         },
8222
8223         /**
8224          * Gets the right X coordinate of the element (element X position + element width)
8225          * @param {Boolean} local True to get the local css position instead of page coordinate
8226          * @return {Number}
8227          */
8228         getRight : function(local){
8229             if(!local){
8230                 return this.getX() + this.getWidth();
8231             }else{
8232                 return (this.getLeft(true) + this.getWidth()) || 0;
8233             }
8234         },
8235
8236         /**
8237          * Gets the top Y coordinate
8238          * @param {Boolean} local True to get the local css position instead of page coordinate
8239          * @return {Number}
8240          */
8241         getTop : function(local) {
8242             if(!local){
8243                 return this.getY();
8244             }else{
8245                 return parseInt(this.getStyle("top"), 10) || 0;
8246             }
8247         },
8248
8249         /**
8250          * Gets the bottom Y coordinate of the element (element Y position + element height)
8251          * @param {Boolean} local True to get the local css position instead of page coordinate
8252          * @return {Number}
8253          */
8254         getBottom : function(local){
8255             if(!local){
8256                 return this.getY() + this.getHeight();
8257             }else{
8258                 return (this.getTop(true) + this.getHeight()) || 0;
8259             }
8260         },
8261
8262         /**
8263         * Initializes positioning on this element. If a desired position is not passed, it will make the
8264         * the element positioned relative IF it is not already positioned.
8265         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8266         * @param {Number} zIndex (optional) The zIndex to apply
8267         * @param {Number} x (optional) Set the page X position
8268         * @param {Number} y (optional) Set the page Y position
8269         */
8270         position : function(pos, zIndex, x, y){
8271             if(!pos){
8272                if(this.getStyle('position') == 'static'){
8273                    this.setStyle('position', 'relative');
8274                }
8275             }else{
8276                 this.setStyle("position", pos);
8277             }
8278             if(zIndex){
8279                 this.setStyle("z-index", zIndex);
8280             }
8281             if(x !== undefined && y !== undefined){
8282                 this.setXY([x, y]);
8283             }else if(x !== undefined){
8284                 this.setX(x);
8285             }else if(y !== undefined){
8286                 this.setY(y);
8287             }
8288         },
8289
8290         /**
8291         * Clear positioning back to the default when the document was loaded
8292         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8293         * @return {Roo.Element} this
8294          */
8295         clearPositioning : function(value){
8296             value = value ||'';
8297             this.setStyle({
8298                 "left": value,
8299                 "right": value,
8300                 "top": value,
8301                 "bottom": value,
8302                 "z-index": "",
8303                 "position" : "static"
8304             });
8305             return this;
8306         },
8307
8308         /**
8309         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8310         * snapshot before performing an update and then restoring the element.
8311         * @return {Object}
8312         */
8313         getPositioning : function(){
8314             var l = this.getStyle("left");
8315             var t = this.getStyle("top");
8316             return {
8317                 "position" : this.getStyle("position"),
8318                 "left" : l,
8319                 "right" : l ? "" : this.getStyle("right"),
8320                 "top" : t,
8321                 "bottom" : t ? "" : this.getStyle("bottom"),
8322                 "z-index" : this.getStyle("z-index")
8323             };
8324         },
8325
8326         /**
8327          * Gets the width of the border(s) for the specified side(s)
8328          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8329          * passing lr would get the border (l)eft width + the border (r)ight width.
8330          * @return {Number} The width of the sides passed added together
8331          */
8332         getBorderWidth : function(side){
8333             return this.addStyles(side, El.borders);
8334         },
8335
8336         /**
8337          * Gets the width of the padding(s) for the specified side(s)
8338          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8339          * passing lr would get the padding (l)eft + the padding (r)ight.
8340          * @return {Number} The padding of the sides passed added together
8341          */
8342         getPadding : function(side){
8343             return this.addStyles(side, El.paddings);
8344         },
8345
8346         /**
8347         * Set positioning with an object returned by getPositioning().
8348         * @param {Object} posCfg
8349         * @return {Roo.Element} this
8350          */
8351         setPositioning : function(pc){
8352             this.applyStyles(pc);
8353             if(pc.right == "auto"){
8354                 this.dom.style.right = "";
8355             }
8356             if(pc.bottom == "auto"){
8357                 this.dom.style.bottom = "";
8358             }
8359             return this;
8360         },
8361
8362         // private
8363         fixDisplay : function(){
8364             if(this.getStyle("display") == "none"){
8365                 this.setStyle("visibility", "hidden");
8366                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8367                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8368                     this.setStyle("display", "block");
8369                 }
8370             }
8371         },
8372
8373         /**
8374          * Quick set left and top adding default units
8375          * @param {String} left The left CSS property value
8376          * @param {String} top The top CSS property value
8377          * @return {Roo.Element} this
8378          */
8379          setLeftTop : function(left, top){
8380             this.dom.style.left = this.addUnits(left);
8381             this.dom.style.top = this.addUnits(top);
8382             return this;
8383         },
8384
8385         /**
8386          * Move this element relative to its current position.
8387          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8388          * @param {Number} distance How far to move the element in pixels
8389          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8390          * @return {Roo.Element} this
8391          */
8392          move : function(direction, distance, animate){
8393             var xy = this.getXY();
8394             direction = direction.toLowerCase();
8395             switch(direction){
8396                 case "l":
8397                 case "left":
8398                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8399                     break;
8400                case "r":
8401                case "right":
8402                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8403                     break;
8404                case "t":
8405                case "top":
8406                case "up":
8407                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8408                     break;
8409                case "b":
8410                case "bottom":
8411                case "down":
8412                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8413                     break;
8414             }
8415             return this;
8416         },
8417
8418         /**
8419          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8420          * @return {Roo.Element} this
8421          */
8422         clip : function(){
8423             if(!this.isClipped){
8424                this.isClipped = true;
8425                this.originalClip = {
8426                    "o": this.getStyle("overflow"),
8427                    "x": this.getStyle("overflow-x"),
8428                    "y": this.getStyle("overflow-y")
8429                };
8430                this.setStyle("overflow", "hidden");
8431                this.setStyle("overflow-x", "hidden");
8432                this.setStyle("overflow-y", "hidden");
8433             }
8434             return this;
8435         },
8436
8437         /**
8438          *  Return clipping (overflow) to original clipping before clip() was called
8439          * @return {Roo.Element} this
8440          */
8441         unclip : function(){
8442             if(this.isClipped){
8443                 this.isClipped = false;
8444                 var o = this.originalClip;
8445                 if(o.o){this.setStyle("overflow", o.o);}
8446                 if(o.x){this.setStyle("overflow-x", o.x);}
8447                 if(o.y){this.setStyle("overflow-y", o.y);}
8448             }
8449             return this;
8450         },
8451
8452
8453         /**
8454          * Gets the x,y coordinates specified by the anchor position on the element.
8455          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8456          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8457          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8458          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8459          * @return {Array} [x, y] An array containing the element's x and y coordinates
8460          */
8461         getAnchorXY : function(anchor, local, s){
8462             //Passing a different size is useful for pre-calculating anchors,
8463             //especially for anchored animations that change the el size.
8464
8465             var w, h, vp = false;
8466             if(!s){
8467                 var d = this.dom;
8468                 if(d == document.body || d == document){
8469                     vp = true;
8470                     w = D.getViewWidth(); h = D.getViewHeight();
8471                 }else{
8472                     w = this.getWidth(); h = this.getHeight();
8473                 }
8474             }else{
8475                 w = s.width;  h = s.height;
8476             }
8477             var x = 0, y = 0, r = Math.round;
8478             switch((anchor || "tl").toLowerCase()){
8479                 case "c":
8480                     x = r(w*.5);
8481                     y = r(h*.5);
8482                 break;
8483                 case "t":
8484                     x = r(w*.5);
8485                     y = 0;
8486                 break;
8487                 case "l":
8488                     x = 0;
8489                     y = r(h*.5);
8490                 break;
8491                 case "r":
8492                     x = w;
8493                     y = r(h*.5);
8494                 break;
8495                 case "b":
8496                     x = r(w*.5);
8497                     y = h;
8498                 break;
8499                 case "tl":
8500                     x = 0;
8501                     y = 0;
8502                 break;
8503                 case "bl":
8504                     x = 0;
8505                     y = h;
8506                 break;
8507                 case "br":
8508                     x = w;
8509                     y = h;
8510                 break;
8511                 case "tr":
8512                     x = w;
8513                     y = 0;
8514                 break;
8515             }
8516             if(local === true){
8517                 return [x, y];
8518             }
8519             if(vp){
8520                 var sc = this.getScroll();
8521                 return [x + sc.left, y + sc.top];
8522             }
8523             //Add the element's offset xy
8524             var o = this.getXY();
8525             return [x+o[0], y+o[1]];
8526         },
8527
8528         /**
8529          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8530          * supported position values.
8531          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8532          * @param {String} position The position to align to.
8533          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8534          * @return {Array} [x, y]
8535          */
8536         getAlignToXY : function(el, p, o){
8537             el = Roo.get(el);
8538             var d = this.dom;
8539             if(!el.dom){
8540                 throw "Element.alignTo with an element that doesn't exist";
8541             }
8542             var c = false; //constrain to viewport
8543             var p1 = "", p2 = "";
8544             o = o || [0,0];
8545
8546             if(!p){
8547                 p = "tl-bl";
8548             }else if(p == "?"){
8549                 p = "tl-bl?";
8550             }else if(p.indexOf("-") == -1){
8551                 p = "tl-" + p;
8552             }
8553             p = p.toLowerCase();
8554             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8555             if(!m){
8556                throw "Element.alignTo with an invalid alignment " + p;
8557             }
8558             p1 = m[1]; p2 = m[2]; c = !!m[3];
8559
8560             //Subtract the aligned el's internal xy from the target's offset xy
8561             //plus custom offset to get the aligned el's new offset xy
8562             var a1 = this.getAnchorXY(p1, true);
8563             var a2 = el.getAnchorXY(p2, false);
8564             var x = a2[0] - a1[0] + o[0];
8565             var y = a2[1] - a1[1] + o[1];
8566             if(c){
8567                 //constrain the aligned el to viewport if necessary
8568                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8569                 // 5px of margin for ie
8570                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8571
8572                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8573                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8574                 //otherwise swap the aligned el to the opposite border of the target.
8575                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8576                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8577                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8578                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8579
8580                var doc = document;
8581                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8582                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8583
8584                if((x+w) > dw + scrollX){
8585                     x = swapX ? r.left-w : dw+scrollX-w;
8586                 }
8587                if(x < scrollX){
8588                    x = swapX ? r.right : scrollX;
8589                }
8590                if((y+h) > dh + scrollY){
8591                     y = swapY ? r.top-h : dh+scrollY-h;
8592                 }
8593                if (y < scrollY){
8594                    y = swapY ? r.bottom : scrollY;
8595                }
8596             }
8597             return [x,y];
8598         },
8599
8600         // private
8601         getConstrainToXY : function(){
8602             var os = {top:0, left:0, bottom:0, right: 0};
8603
8604             return function(el, local, offsets, proposedXY){
8605                 el = Roo.get(el);
8606                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8607
8608                 var vw, vh, vx = 0, vy = 0;
8609                 if(el.dom == document.body || el.dom == document){
8610                     vw = Roo.lib.Dom.getViewWidth();
8611                     vh = Roo.lib.Dom.getViewHeight();
8612                 }else{
8613                     vw = el.dom.clientWidth;
8614                     vh = el.dom.clientHeight;
8615                     if(!local){
8616                         var vxy = el.getXY();
8617                         vx = vxy[0];
8618                         vy = vxy[1];
8619                     }
8620                 }
8621
8622                 var s = el.getScroll();
8623
8624                 vx += offsets.left + s.left;
8625                 vy += offsets.top + s.top;
8626
8627                 vw -= offsets.right;
8628                 vh -= offsets.bottom;
8629
8630                 var vr = vx+vw;
8631                 var vb = vy+vh;
8632
8633                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8634                 var x = xy[0], y = xy[1];
8635                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8636
8637                 // only move it if it needs it
8638                 var moved = false;
8639
8640                 // first validate right/bottom
8641                 if((x + w) > vr){
8642                     x = vr - w;
8643                     moved = true;
8644                 }
8645                 if((y + h) > vb){
8646                     y = vb - h;
8647                     moved = true;
8648                 }
8649                 // then make sure top/left isn't negative
8650                 if(x < vx){
8651                     x = vx;
8652                     moved = true;
8653                 }
8654                 if(y < vy){
8655                     y = vy;
8656                     moved = true;
8657                 }
8658                 return moved ? [x, y] : false;
8659             };
8660         }(),
8661
8662         // private
8663         adjustForConstraints : function(xy, parent, offsets){
8664             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8665         },
8666
8667         /**
8668          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8669          * document it aligns it to the viewport.
8670          * The position parameter is optional, and can be specified in any one of the following formats:
8671          * <ul>
8672          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8673          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8674          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8675          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8676          *   <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
8677          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8678          * </ul>
8679          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8680          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8681          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8682          * that specified in order to enforce the viewport constraints.
8683          * Following are all of the supported anchor positions:
8684     <pre>
8685     Value  Description
8686     -----  -----------------------------
8687     tl     The top left corner (default)
8688     t      The center of the top edge
8689     tr     The top right corner
8690     l      The center of the left edge
8691     c      In the center of the element
8692     r      The center of the right edge
8693     bl     The bottom left corner
8694     b      The center of the bottom edge
8695     br     The bottom right corner
8696     </pre>
8697     Example Usage:
8698     <pre><code>
8699     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8700     el.alignTo("other-el");
8701
8702     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8703     el.alignTo("other-el", "tr?");
8704
8705     // align the bottom right corner of el with the center left edge of other-el
8706     el.alignTo("other-el", "br-l?");
8707
8708     // align the center of el with the bottom left corner of other-el and
8709     // adjust the x position by -6 pixels (and the y position by 0)
8710     el.alignTo("other-el", "c-bl", [-6, 0]);
8711     </code></pre>
8712          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8713          * @param {String} position The position to align to.
8714          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8715          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8716          * @return {Roo.Element} this
8717          */
8718         alignTo : function(element, position, offsets, animate){
8719             var xy = this.getAlignToXY(element, position, offsets);
8720             this.setXY(xy, this.preanim(arguments, 3));
8721             return this;
8722         },
8723
8724         /**
8725          * Anchors an element to another element and realigns it when the window is resized.
8726          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8727          * @param {String} position The position to align to.
8728          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8729          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8730          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8731          * is a number, it is used as the buffer delay (defaults to 50ms).
8732          * @param {Function} callback The function to call after the animation finishes
8733          * @return {Roo.Element} this
8734          */
8735         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8736             var action = function(){
8737                 this.alignTo(el, alignment, offsets, animate);
8738                 Roo.callback(callback, this);
8739             };
8740             Roo.EventManager.onWindowResize(action, this);
8741             var tm = typeof monitorScroll;
8742             if(tm != 'undefined'){
8743                 Roo.EventManager.on(window, 'scroll', action, this,
8744                     {buffer: tm == 'number' ? monitorScroll : 50});
8745             }
8746             action.call(this); // align immediately
8747             return this;
8748         },
8749         /**
8750          * Clears any opacity settings from this element. Required in some cases for IE.
8751          * @return {Roo.Element} this
8752          */
8753         clearOpacity : function(){
8754             if (window.ActiveXObject) {
8755                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8756                     this.dom.style.filter = "";
8757                 }
8758             } else {
8759                 this.dom.style.opacity = "";
8760                 this.dom.style["-moz-opacity"] = "";
8761                 this.dom.style["-khtml-opacity"] = "";
8762             }
8763             return this;
8764         },
8765
8766         /**
8767          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8768          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8769          * @return {Roo.Element} this
8770          */
8771         hide : function(animate){
8772             this.setVisible(false, this.preanim(arguments, 0));
8773             return this;
8774         },
8775
8776         /**
8777         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8778         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8779          * @return {Roo.Element} this
8780          */
8781         show : function(animate){
8782             this.setVisible(true, this.preanim(arguments, 0));
8783             return this;
8784         },
8785
8786         /**
8787          * @private Test if size has a unit, otherwise appends the default
8788          */
8789         addUnits : function(size){
8790             return Roo.Element.addUnits(size, this.defaultUnit);
8791         },
8792
8793         /**
8794          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8795          * @return {Roo.Element} this
8796          */
8797         beginMeasure : function(){
8798             var el = this.dom;
8799             if(el.offsetWidth || el.offsetHeight){
8800                 return this; // offsets work already
8801             }
8802             var changed = [];
8803             var p = this.dom, b = document.body; // start with this element
8804             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8805                 var pe = Roo.get(p);
8806                 if(pe.getStyle('display') == 'none'){
8807                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8808                     p.style.visibility = "hidden";
8809                     p.style.display = "block";
8810                 }
8811                 p = p.parentNode;
8812             }
8813             this._measureChanged = changed;
8814             return this;
8815
8816         },
8817
8818         /**
8819          * Restores displays to before beginMeasure was called
8820          * @return {Roo.Element} this
8821          */
8822         endMeasure : function(){
8823             var changed = this._measureChanged;
8824             if(changed){
8825                 for(var i = 0, len = changed.length; i < len; i++) {
8826                     var r = changed[i];
8827                     r.el.style.visibility = r.visibility;
8828                     r.el.style.display = "none";
8829                 }
8830                 this._measureChanged = null;
8831             }
8832             return this;
8833         },
8834
8835         /**
8836         * Update the innerHTML of this element, optionally searching for and processing scripts
8837         * @param {String} html The new HTML
8838         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8839         * @param {Function} callback For async script loading you can be noticed when the update completes
8840         * @return {Roo.Element} this
8841          */
8842         update : function(html, loadScripts, callback){
8843             if(typeof html == "undefined"){
8844                 html = "";
8845             }
8846             if(loadScripts !== true){
8847                 this.dom.innerHTML = html;
8848                 if(typeof callback == "function"){
8849                     callback();
8850                 }
8851                 return this;
8852             }
8853             var id = Roo.id();
8854             var dom = this.dom;
8855
8856             html += '<span id="' + id + '"></span>';
8857
8858             E.onAvailable(id, function(){
8859                 var hd = document.getElementsByTagName("head")[0];
8860                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8861                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8862                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8863
8864                 var match;
8865                 while(match = re.exec(html)){
8866                     var attrs = match[1];
8867                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8868                     if(srcMatch && srcMatch[2]){
8869                        var s = document.createElement("script");
8870                        s.src = srcMatch[2];
8871                        var typeMatch = attrs.match(typeRe);
8872                        if(typeMatch && typeMatch[2]){
8873                            s.type = typeMatch[2];
8874                        }
8875                        hd.appendChild(s);
8876                     }else if(match[2] && match[2].length > 0){
8877                         if(window.execScript) {
8878                            window.execScript(match[2]);
8879                         } else {
8880                             /**
8881                              * eval:var:id
8882                              * eval:var:dom
8883                              * eval:var:html
8884                              * 
8885                              */
8886                            window.eval(match[2]);
8887                         }
8888                     }
8889                 }
8890                 var el = document.getElementById(id);
8891                 if(el){el.parentNode.removeChild(el);}
8892                 if(typeof callback == "function"){
8893                     callback();
8894                 }
8895             });
8896             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8897             return this;
8898         },
8899
8900         /**
8901          * Direct access to the UpdateManager update() method (takes the same parameters).
8902          * @param {String/Function} url The url for this request or a function to call to get the url
8903          * @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}
8904          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8905          * @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.
8906          * @return {Roo.Element} this
8907          */
8908         load : function(){
8909             var um = this.getUpdateManager();
8910             um.update.apply(um, arguments);
8911             return this;
8912         },
8913
8914         /**
8915         * Gets this element's UpdateManager
8916         * @return {Roo.UpdateManager} The UpdateManager
8917         */
8918         getUpdateManager : function(){
8919             if(!this.updateManager){
8920                 this.updateManager = new Roo.UpdateManager(this);
8921             }
8922             return this.updateManager;
8923         },
8924
8925         /**
8926          * Disables text selection for this element (normalized across browsers)
8927          * @return {Roo.Element} this
8928          */
8929         unselectable : function(){
8930             this.dom.unselectable = "on";
8931             this.swallowEvent("selectstart", true);
8932             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8933             this.addClass("x-unselectable");
8934             return this;
8935         },
8936
8937         /**
8938         * Calculates the x, y to center this element on the screen
8939         * @return {Array} The x, y values [x, y]
8940         */
8941         getCenterXY : function(){
8942             return this.getAlignToXY(document, 'c-c');
8943         },
8944
8945         /**
8946         * Centers the Element in either the viewport, or another Element.
8947         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8948         */
8949         center : function(centerIn){
8950             this.alignTo(centerIn || document, 'c-c');
8951             return this;
8952         },
8953
8954         /**
8955          * Tests various css rules/browsers to determine if this element uses a border box
8956          * @return {Boolean}
8957          */
8958         isBorderBox : function(){
8959             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8960         },
8961
8962         /**
8963          * Return a box {x, y, width, height} that can be used to set another elements
8964          * size/location to match this element.
8965          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8966          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8967          * @return {Object} box An object in the format {x, y, width, height}
8968          */
8969         getBox : function(contentBox, local){
8970             var xy;
8971             if(!local){
8972                 xy = this.getXY();
8973             }else{
8974                 var left = parseInt(this.getStyle("left"), 10) || 0;
8975                 var top = parseInt(this.getStyle("top"), 10) || 0;
8976                 xy = [left, top];
8977             }
8978             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8979             if(!contentBox){
8980                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8981             }else{
8982                 var l = this.getBorderWidth("l")+this.getPadding("l");
8983                 var r = this.getBorderWidth("r")+this.getPadding("r");
8984                 var t = this.getBorderWidth("t")+this.getPadding("t");
8985                 var b = this.getBorderWidth("b")+this.getPadding("b");
8986                 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)};
8987             }
8988             bx.right = bx.x + bx.width;
8989             bx.bottom = bx.y + bx.height;
8990             return bx;
8991         },
8992
8993         /**
8994          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8995          for more information about the sides.
8996          * @param {String} sides
8997          * @return {Number}
8998          */
8999         getFrameWidth : function(sides, onlyContentBox){
9000             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9001         },
9002
9003         /**
9004          * 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.
9005          * @param {Object} box The box to fill {x, y, width, height}
9006          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9007          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9008          * @return {Roo.Element} this
9009          */
9010         setBox : function(box, adjust, animate){
9011             var w = box.width, h = box.height;
9012             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9013                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9014                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9015             }
9016             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9017             return this;
9018         },
9019
9020         /**
9021          * Forces the browser to repaint this element
9022          * @return {Roo.Element} this
9023          */
9024          repaint : function(){
9025             var dom = this.dom;
9026             this.addClass("x-repaint");
9027             setTimeout(function(){
9028                 Roo.get(dom).removeClass("x-repaint");
9029             }, 1);
9030             return this;
9031         },
9032
9033         /**
9034          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9035          * then it returns the calculated width of the sides (see getPadding)
9036          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9037          * @return {Object/Number}
9038          */
9039         getMargins : function(side){
9040             if(!side){
9041                 return {
9042                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9043                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9044                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9045                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9046                 };
9047             }else{
9048                 return this.addStyles(side, El.margins);
9049              }
9050         },
9051
9052         // private
9053         addStyles : function(sides, styles){
9054             var val = 0, v, w;
9055             for(var i = 0, len = sides.length; i < len; i++){
9056                 v = this.getStyle(styles[sides.charAt(i)]);
9057                 if(v){
9058                      w = parseInt(v, 10);
9059                      if(w){ val += w; }
9060                 }
9061             }
9062             return val;
9063         },
9064
9065         /**
9066          * Creates a proxy element of this element
9067          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9068          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9069          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9070          * @return {Roo.Element} The new proxy element
9071          */
9072         createProxy : function(config, renderTo, matchBox){
9073             if(renderTo){
9074                 renderTo = Roo.getDom(renderTo);
9075             }else{
9076                 renderTo = document.body;
9077             }
9078             config = typeof config == "object" ?
9079                 config : {tag : "div", cls: config};
9080             var proxy = Roo.DomHelper.append(renderTo, config, true);
9081             if(matchBox){
9082                proxy.setBox(this.getBox());
9083             }
9084             return proxy;
9085         },
9086
9087         /**
9088          * Puts a mask over this element to disable user interaction. Requires core.css.
9089          * This method can only be applied to elements which accept child nodes.
9090          * @param {String} msg (optional) A message to display in the mask
9091          * @param {String} msgCls (optional) A css class to apply to the msg element
9092          * @return {Element} The mask  element
9093          */
9094         mask : function(msg, msgCls)
9095         {
9096             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9097                 this.setStyle("position", "relative");
9098             }
9099             if(!this._mask){
9100                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9101             }
9102             this.addClass("x-masked");
9103             this._mask.setDisplayed(true);
9104             
9105             // we wander
9106             var z = 0;
9107             var dom = this.dom;
9108             while (dom && dom.style) {
9109                 if (!isNaN(parseInt(dom.style.zIndex))) {
9110                     z = Math.max(z, parseInt(dom.style.zIndex));
9111                 }
9112                 dom = dom.parentNode;
9113             }
9114             // if we are masking the body - then it hides everything..
9115             if (this.dom == document.body) {
9116                 z = 1000000;
9117                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9118                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9119             }
9120            
9121             if(typeof msg == 'string'){
9122                 if(!this._maskMsg){
9123                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9124                 }
9125                 var mm = this._maskMsg;
9126                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9127                 if (mm.dom.firstChild) { // weird IE issue?
9128                     mm.dom.firstChild.innerHTML = msg;
9129                 }
9130                 mm.setDisplayed(true);
9131                 mm.center(this);
9132                 mm.setStyle('z-index', z + 102);
9133             }
9134             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9135                 this._mask.setHeight(this.getHeight());
9136             }
9137             this._mask.setStyle('z-index', z + 100);
9138             
9139             return this._mask;
9140         },
9141
9142         /**
9143          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9144          * it is cached for reuse.
9145          */
9146         unmask : function(removeEl){
9147             if(this._mask){
9148                 if(removeEl === true){
9149                     this._mask.remove();
9150                     delete this._mask;
9151                     if(this._maskMsg){
9152                         this._maskMsg.remove();
9153                         delete this._maskMsg;
9154                     }
9155                 }else{
9156                     this._mask.setDisplayed(false);
9157                     if(this._maskMsg){
9158                         this._maskMsg.setDisplayed(false);
9159                     }
9160                 }
9161             }
9162             this.removeClass("x-masked");
9163         },
9164
9165         /**
9166          * Returns true if this element is masked
9167          * @return {Boolean}
9168          */
9169         isMasked : function(){
9170             return this._mask && this._mask.isVisible();
9171         },
9172
9173         /**
9174          * Creates an iframe shim for this element to keep selects and other windowed objects from
9175          * showing through.
9176          * @return {Roo.Element} The new shim element
9177          */
9178         createShim : function(){
9179             var el = document.createElement('iframe');
9180             el.frameBorder = 'no';
9181             el.className = 'roo-shim';
9182             if(Roo.isIE && Roo.isSecure){
9183                 el.src = Roo.SSL_SECURE_URL;
9184             }
9185             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9186             shim.autoBoxAdjust = false;
9187             return shim;
9188         },
9189
9190         /**
9191          * Removes this element from the DOM and deletes it from the cache
9192          */
9193         remove : function(){
9194             if(this.dom.parentNode){
9195                 this.dom.parentNode.removeChild(this.dom);
9196             }
9197             delete El.cache[this.dom.id];
9198         },
9199
9200         /**
9201          * Sets up event handlers to add and remove a css class when the mouse is over this element
9202          * @param {String} className
9203          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9204          * mouseout events for children elements
9205          * @return {Roo.Element} this
9206          */
9207         addClassOnOver : function(className, preventFlicker){
9208             this.on("mouseover", function(){
9209                 Roo.fly(this, '_internal').addClass(className);
9210             }, this.dom);
9211             var removeFn = function(e){
9212                 if(preventFlicker !== true || !e.within(this, true)){
9213                     Roo.fly(this, '_internal').removeClass(className);
9214                 }
9215             };
9216             this.on("mouseout", removeFn, this.dom);
9217             return this;
9218         },
9219
9220         /**
9221          * Sets up event handlers to add and remove a css class when this element has the focus
9222          * @param {String} className
9223          * @return {Roo.Element} this
9224          */
9225         addClassOnFocus : function(className){
9226             this.on("focus", function(){
9227                 Roo.fly(this, '_internal').addClass(className);
9228             }, this.dom);
9229             this.on("blur", function(){
9230                 Roo.fly(this, '_internal').removeClass(className);
9231             }, this.dom);
9232             return this;
9233         },
9234         /**
9235          * 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)
9236          * @param {String} className
9237          * @return {Roo.Element} this
9238          */
9239         addClassOnClick : function(className){
9240             var dom = this.dom;
9241             this.on("mousedown", function(){
9242                 Roo.fly(dom, '_internal').addClass(className);
9243                 var d = Roo.get(document);
9244                 var fn = function(){
9245                     Roo.fly(dom, '_internal').removeClass(className);
9246                     d.removeListener("mouseup", fn);
9247                 };
9248                 d.on("mouseup", fn);
9249             });
9250             return this;
9251         },
9252
9253         /**
9254          * Stops the specified event from bubbling and optionally prevents the default action
9255          * @param {String} eventName
9256          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9257          * @return {Roo.Element} this
9258          */
9259         swallowEvent : function(eventName, preventDefault){
9260             var fn = function(e){
9261                 e.stopPropagation();
9262                 if(preventDefault){
9263                     e.preventDefault();
9264                 }
9265             };
9266             if(eventName instanceof Array){
9267                 for(var i = 0, len = eventName.length; i < len; i++){
9268                      this.on(eventName[i], fn);
9269                 }
9270                 return this;
9271             }
9272             this.on(eventName, fn);
9273             return this;
9274         },
9275
9276         /**
9277          * @private
9278          */
9279       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9280
9281         /**
9282          * Sizes this element to its parent element's dimensions performing
9283          * neccessary box adjustments.
9284          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9285          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9286          * @return {Roo.Element} this
9287          */
9288         fitToParent : function(monitorResize, targetParent) {
9289           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9290           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9291           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9292             return;
9293           }
9294           var p = Roo.get(targetParent || this.dom.parentNode);
9295           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9296           if (monitorResize === true) {
9297             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9298             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9299           }
9300           return this;
9301         },
9302
9303         /**
9304          * Gets the next sibling, skipping text nodes
9305          * @return {HTMLElement} The next sibling or null
9306          */
9307         getNextSibling : function(){
9308             var n = this.dom.nextSibling;
9309             while(n && n.nodeType != 1){
9310                 n = n.nextSibling;
9311             }
9312             return n;
9313         },
9314
9315         /**
9316          * Gets the previous sibling, skipping text nodes
9317          * @return {HTMLElement} The previous sibling or null
9318          */
9319         getPrevSibling : function(){
9320             var n = this.dom.previousSibling;
9321             while(n && n.nodeType != 1){
9322                 n = n.previousSibling;
9323             }
9324             return n;
9325         },
9326
9327
9328         /**
9329          * Appends the passed element(s) to this element
9330          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9331          * @return {Roo.Element} this
9332          */
9333         appendChild: function(el){
9334             el = Roo.get(el);
9335             el.appendTo(this);
9336             return this;
9337         },
9338
9339         /**
9340          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9341          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9342          * automatically generated with the specified attributes.
9343          * @param {HTMLElement} insertBefore (optional) a child element of this element
9344          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9345          * @return {Roo.Element} The new child element
9346          */
9347         createChild: function(config, insertBefore, returnDom){
9348             config = config || {tag:'div'};
9349             if(insertBefore){
9350                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9351             }
9352             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9353         },
9354
9355         /**
9356          * Appends this element to the passed element
9357          * @param {String/HTMLElement/Element} el The new parent element
9358          * @return {Roo.Element} this
9359          */
9360         appendTo: function(el){
9361             el = Roo.getDom(el);
9362             el.appendChild(this.dom);
9363             return this;
9364         },
9365
9366         /**
9367          * Inserts this element before the passed element in the DOM
9368          * @param {String/HTMLElement/Element} el The element to insert before
9369          * @return {Roo.Element} this
9370          */
9371         insertBefore: function(el){
9372             el = Roo.getDom(el);
9373             el.parentNode.insertBefore(this.dom, el);
9374             return this;
9375         },
9376
9377         /**
9378          * Inserts this element after the passed element in the DOM
9379          * @param {String/HTMLElement/Element} el The element to insert after
9380          * @return {Roo.Element} this
9381          */
9382         insertAfter: function(el){
9383             el = Roo.getDom(el);
9384             el.parentNode.insertBefore(this.dom, el.nextSibling);
9385             return this;
9386         },
9387
9388         /**
9389          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9390          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9391          * @return {Roo.Element} The new child
9392          */
9393         insertFirst: function(el, returnDom){
9394             el = el || {};
9395             if(typeof el == 'object' && !el.nodeType){ // dh config
9396                 return this.createChild(el, this.dom.firstChild, returnDom);
9397             }else{
9398                 el = Roo.getDom(el);
9399                 this.dom.insertBefore(el, this.dom.firstChild);
9400                 return !returnDom ? Roo.get(el) : el;
9401             }
9402         },
9403
9404         /**
9405          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9406          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9407          * @param {String} where (optional) 'before' or 'after' defaults to before
9408          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9409          * @return {Roo.Element} the inserted Element
9410          */
9411         insertSibling: function(el, where, returnDom){
9412             where = where ? where.toLowerCase() : 'before';
9413             el = el || {};
9414             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9415
9416             if(typeof el == 'object' && !el.nodeType){ // dh config
9417                 if(where == 'after' && !this.dom.nextSibling){
9418                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9419                 }else{
9420                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9421                 }
9422
9423             }else{
9424                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9425                             where == 'before' ? this.dom : this.dom.nextSibling);
9426                 if(!returnDom){
9427                     rt = Roo.get(rt);
9428                 }
9429             }
9430             return rt;
9431         },
9432
9433         /**
9434          * Creates and wraps this element with another element
9435          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9436          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9437          * @return {HTMLElement/Element} The newly created wrapper element
9438          */
9439         wrap: function(config, returnDom){
9440             if(!config){
9441                 config = {tag: "div"};
9442             }
9443             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9444             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9445             return newEl;
9446         },
9447
9448         /**
9449          * Replaces the passed element with this element
9450          * @param {String/HTMLElement/Element} el The element to replace
9451          * @return {Roo.Element} this
9452          */
9453         replace: function(el){
9454             el = Roo.get(el);
9455             this.insertBefore(el);
9456             el.remove();
9457             return this;
9458         },
9459
9460         /**
9461          * Inserts an html fragment into this element
9462          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9463          * @param {String} html The HTML fragment
9464          * @param {Boolean} returnEl True to return an Roo.Element
9465          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9466          */
9467         insertHtml : function(where, html, returnEl){
9468             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9469             return returnEl ? Roo.get(el) : el;
9470         },
9471
9472         /**
9473          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9474          * @param {Object} o The object with the attributes
9475          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9476          * @return {Roo.Element} this
9477          */
9478         set : function(o, useSet){
9479             var el = this.dom;
9480             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9481             for(var attr in o){
9482                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9483                 if(attr=="cls"){
9484                     el.className = o["cls"];
9485                 }else{
9486                     if(useSet) {
9487                         el.setAttribute(attr, o[attr]);
9488                     } else {
9489                         el[attr] = o[attr];
9490                     }
9491                 }
9492             }
9493             if(o.style){
9494                 Roo.DomHelper.applyStyles(el, o.style);
9495             }
9496             return this;
9497         },
9498
9499         /**
9500          * Convenience method for constructing a KeyMap
9501          * @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:
9502          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9503          * @param {Function} fn The function to call
9504          * @param {Object} scope (optional) The scope of the function
9505          * @return {Roo.KeyMap} The KeyMap created
9506          */
9507         addKeyListener : function(key, fn, scope){
9508             var config;
9509             if(typeof key != "object" || key instanceof Array){
9510                 config = {
9511                     key: key,
9512                     fn: fn,
9513                     scope: scope
9514                 };
9515             }else{
9516                 config = {
9517                     key : key.key,
9518                     shift : key.shift,
9519                     ctrl : key.ctrl,
9520                     alt : key.alt,
9521                     fn: fn,
9522                     scope: scope
9523                 };
9524             }
9525             return new Roo.KeyMap(this, config);
9526         },
9527
9528         /**
9529          * Creates a KeyMap for this element
9530          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9531          * @return {Roo.KeyMap} The KeyMap created
9532          */
9533         addKeyMap : function(config){
9534             return new Roo.KeyMap(this, config);
9535         },
9536
9537         /**
9538          * Returns true if this element is scrollable.
9539          * @return {Boolean}
9540          */
9541          isScrollable : function(){
9542             var dom = this.dom;
9543             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9544         },
9545
9546         /**
9547          * 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().
9548          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9549          * @param {Number} value The new scroll value
9550          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9551          * @return {Element} this
9552          */
9553
9554         scrollTo : function(side, value, animate){
9555             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9556             if(!animate || !A){
9557                 this.dom[prop] = value;
9558             }else{
9559                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9560                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9561             }
9562             return this;
9563         },
9564
9565         /**
9566          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9567          * within this element's scrollable range.
9568          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9569          * @param {Number} distance How far to scroll the element in pixels
9570          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9571          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9572          * was scrolled as far as it could go.
9573          */
9574          scroll : function(direction, distance, animate){
9575              if(!this.isScrollable()){
9576                  return;
9577              }
9578              var el = this.dom;
9579              var l = el.scrollLeft, t = el.scrollTop;
9580              var w = el.scrollWidth, h = el.scrollHeight;
9581              var cw = el.clientWidth, ch = el.clientHeight;
9582              direction = direction.toLowerCase();
9583              var scrolled = false;
9584              var a = this.preanim(arguments, 2);
9585              switch(direction){
9586                  case "l":
9587                  case "left":
9588                      if(w - l > cw){
9589                          var v = Math.min(l + distance, w-cw);
9590                          this.scrollTo("left", v, a);
9591                          scrolled = true;
9592                      }
9593                      break;
9594                 case "r":
9595                 case "right":
9596                      if(l > 0){
9597                          var v = Math.max(l - distance, 0);
9598                          this.scrollTo("left", v, a);
9599                          scrolled = true;
9600                      }
9601                      break;
9602                 case "t":
9603                 case "top":
9604                 case "up":
9605                      if(t > 0){
9606                          var v = Math.max(t - distance, 0);
9607                          this.scrollTo("top", v, a);
9608                          scrolled = true;
9609                      }
9610                      break;
9611                 case "b":
9612                 case "bottom":
9613                 case "down":
9614                      if(h - t > ch){
9615                          var v = Math.min(t + distance, h-ch);
9616                          this.scrollTo("top", v, a);
9617                          scrolled = true;
9618                      }
9619                      break;
9620              }
9621              return scrolled;
9622         },
9623
9624         /**
9625          * Translates the passed page coordinates into left/top css values for this element
9626          * @param {Number/Array} x The page x or an array containing [x, y]
9627          * @param {Number} y The page y
9628          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9629          */
9630         translatePoints : function(x, y){
9631             if(typeof x == 'object' || x instanceof Array){
9632                 y = x[1]; x = x[0];
9633             }
9634             var p = this.getStyle('position');
9635             var o = this.getXY();
9636
9637             var l = parseInt(this.getStyle('left'), 10);
9638             var t = parseInt(this.getStyle('top'), 10);
9639
9640             if(isNaN(l)){
9641                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9642             }
9643             if(isNaN(t)){
9644                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9645             }
9646
9647             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9648         },
9649
9650         /**
9651          * Returns the current scroll position of the element.
9652          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9653          */
9654         getScroll : function(){
9655             var d = this.dom, doc = document;
9656             if(d == doc || d == doc.body){
9657                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9658                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9659                 return {left: l, top: t};
9660             }else{
9661                 return {left: d.scrollLeft, top: d.scrollTop};
9662             }
9663         },
9664
9665         /**
9666          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9667          * are convert to standard 6 digit hex color.
9668          * @param {String} attr The css attribute
9669          * @param {String} defaultValue The default value to use when a valid color isn't found
9670          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9671          * YUI color anims.
9672          */
9673         getColor : function(attr, defaultValue, prefix){
9674             var v = this.getStyle(attr);
9675             if(!v || v == "transparent" || v == "inherit") {
9676                 return defaultValue;
9677             }
9678             var color = typeof prefix == "undefined" ? "#" : prefix;
9679             if(v.substr(0, 4) == "rgb("){
9680                 var rvs = v.slice(4, v.length -1).split(",");
9681                 for(var i = 0; i < 3; i++){
9682                     var h = parseInt(rvs[i]).toString(16);
9683                     if(h < 16){
9684                         h = "0" + h;
9685                     }
9686                     color += h;
9687                 }
9688             } else {
9689                 if(v.substr(0, 1) == "#"){
9690                     if(v.length == 4) {
9691                         for(var i = 1; i < 4; i++){
9692                             var c = v.charAt(i);
9693                             color +=  c + c;
9694                         }
9695                     }else if(v.length == 7){
9696                         color += v.substr(1);
9697                     }
9698                 }
9699             }
9700             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9701         },
9702
9703         /**
9704          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9705          * gradient background, rounded corners and a 4-way shadow.
9706          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9707          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9708          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9709          * @return {Roo.Element} this
9710          */
9711         boxWrap : function(cls){
9712             cls = cls || 'x-box';
9713             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9714             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9715             return el;
9716         },
9717
9718         /**
9719          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9720          * @param {String} namespace The namespace in which to look for the attribute
9721          * @param {String} name The attribute name
9722          * @return {String} The attribute value
9723          */
9724         getAttributeNS : Roo.isIE ? function(ns, name){
9725             var d = this.dom;
9726             var type = typeof d[ns+":"+name];
9727             if(type != 'undefined' && type != 'unknown'){
9728                 return d[ns+":"+name];
9729             }
9730             return d[name];
9731         } : function(ns, name){
9732             var d = this.dom;
9733             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9734         },
9735         
9736         
9737         /**
9738          * Sets or Returns the value the dom attribute value
9739          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9740          * @param {String} value (optional) The value to set the attribute to
9741          * @return {String} The attribute value
9742          */
9743         attr : function(name){
9744             if (arguments.length > 1) {
9745                 this.dom.setAttribute(name, arguments[1]);
9746                 return arguments[1];
9747             }
9748             if (typeof(name) == 'object') {
9749                 for(var i in name) {
9750                     this.attr(i, name[i]);
9751                 }
9752                 return name;
9753             }
9754             
9755             
9756             if (!this.dom.hasAttribute(name)) {
9757                 return undefined;
9758             }
9759             return this.dom.getAttribute(name);
9760         }
9761         
9762         
9763         
9764     };
9765
9766     var ep = El.prototype;
9767
9768     /**
9769      * Appends an event handler (Shorthand for addListener)
9770      * @param {String}   eventName     The type of event to append
9771      * @param {Function} fn        The method the event invokes
9772      * @param {Object} scope       (optional) The scope (this object) of the fn
9773      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9774      * @method
9775      */
9776     ep.on = ep.addListener;
9777         // backwards compat
9778     ep.mon = ep.addListener;
9779
9780     /**
9781      * Removes an event handler from this element (shorthand for removeListener)
9782      * @param {String} eventName the type of event to remove
9783      * @param {Function} fn the method the event invokes
9784      * @return {Roo.Element} this
9785      * @method
9786      */
9787     ep.un = ep.removeListener;
9788
9789     /**
9790      * true to automatically adjust width and height settings for box-model issues (default to true)
9791      */
9792     ep.autoBoxAdjust = true;
9793
9794     // private
9795     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9796
9797     // private
9798     El.addUnits = function(v, defaultUnit){
9799         if(v === "" || v == "auto"){
9800             return v;
9801         }
9802         if(v === undefined){
9803             return '';
9804         }
9805         if(typeof v == "number" || !El.unitPattern.test(v)){
9806             return v + (defaultUnit || 'px');
9807         }
9808         return v;
9809     };
9810
9811     // special markup used throughout Roo when box wrapping elements
9812     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>';
9813     /**
9814      * Visibility mode constant - Use visibility to hide element
9815      * @static
9816      * @type Number
9817      */
9818     El.VISIBILITY = 1;
9819     /**
9820      * Visibility mode constant - Use display to hide element
9821      * @static
9822      * @type Number
9823      */
9824     El.DISPLAY = 2;
9825
9826     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9827     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9828     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9829
9830
9831
9832     /**
9833      * @private
9834      */
9835     El.cache = {};
9836
9837     var docEl;
9838
9839     /**
9840      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9841      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9842      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9843      * @return {Element} The Element object
9844      * @static
9845      */
9846     El.get = function(el){
9847         var ex, elm, id;
9848         if(!el){ return null; }
9849         if(typeof el == "string"){ // element id
9850             if(!(elm = document.getElementById(el))){
9851                 return null;
9852             }
9853             if(ex = El.cache[el]){
9854                 ex.dom = elm;
9855             }else{
9856                 ex = El.cache[el] = new El(elm);
9857             }
9858             return ex;
9859         }else if(el.tagName){ // dom element
9860             if(!(id = el.id)){
9861                 id = Roo.id(el);
9862             }
9863             if(ex = El.cache[id]){
9864                 ex.dom = el;
9865             }else{
9866                 ex = El.cache[id] = new El(el);
9867             }
9868             return ex;
9869         }else if(el instanceof El){
9870             if(el != docEl){
9871                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9872                                                               // catch case where it hasn't been appended
9873                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9874             }
9875             return el;
9876         }else if(el.isComposite){
9877             return el;
9878         }else if(el instanceof Array){
9879             return El.select(el);
9880         }else if(el == document){
9881             // create a bogus element object representing the document object
9882             if(!docEl){
9883                 var f = function(){};
9884                 f.prototype = El.prototype;
9885                 docEl = new f();
9886                 docEl.dom = document;
9887             }
9888             return docEl;
9889         }
9890         return null;
9891     };
9892
9893     // private
9894     El.uncache = function(el){
9895         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9896             if(a[i]){
9897                 delete El.cache[a[i].id || a[i]];
9898             }
9899         }
9900     };
9901
9902     // private
9903     // Garbage collection - uncache elements/purge listeners on orphaned elements
9904     // so we don't hold a reference and cause the browser to retain them
9905     El.garbageCollect = function(){
9906         if(!Roo.enableGarbageCollector){
9907             clearInterval(El.collectorThread);
9908             return;
9909         }
9910         for(var eid in El.cache){
9911             var el = El.cache[eid], d = el.dom;
9912             // -------------------------------------------------------
9913             // Determining what is garbage:
9914             // -------------------------------------------------------
9915             // !d
9916             // dom node is null, definitely garbage
9917             // -------------------------------------------------------
9918             // !d.parentNode
9919             // no parentNode == direct orphan, definitely garbage
9920             // -------------------------------------------------------
9921             // !d.offsetParent && !document.getElementById(eid)
9922             // display none elements have no offsetParent so we will
9923             // also try to look it up by it's id. However, check
9924             // offsetParent first so we don't do unneeded lookups.
9925             // This enables collection of elements that are not orphans
9926             // directly, but somewhere up the line they have an orphan
9927             // parent.
9928             // -------------------------------------------------------
9929             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9930                 delete El.cache[eid];
9931                 if(d && Roo.enableListenerCollection){
9932                     E.purgeElement(d);
9933                 }
9934             }
9935         }
9936     }
9937     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9938
9939
9940     // dom is optional
9941     El.Flyweight = function(dom){
9942         this.dom = dom;
9943     };
9944     El.Flyweight.prototype = El.prototype;
9945
9946     El._flyweights = {};
9947     /**
9948      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9949      * the dom node can be overwritten by other code.
9950      * @param {String/HTMLElement} el The dom node or id
9951      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9952      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9953      * @static
9954      * @return {Element} The shared Element object
9955      */
9956     El.fly = function(el, named){
9957         named = named || '_global';
9958         el = Roo.getDom(el);
9959         if(!el){
9960             return null;
9961         }
9962         if(!El._flyweights[named]){
9963             El._flyweights[named] = new El.Flyweight();
9964         }
9965         El._flyweights[named].dom = el;
9966         return El._flyweights[named];
9967     };
9968
9969     /**
9970      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9971      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9972      * Shorthand of {@link Roo.Element#get}
9973      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9974      * @return {Element} The Element object
9975      * @member Roo
9976      * @method get
9977      */
9978     Roo.get = El.get;
9979     /**
9980      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9981      * the dom node can be overwritten by other code.
9982      * Shorthand of {@link Roo.Element#fly}
9983      * @param {String/HTMLElement} el The dom node or id
9984      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9985      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9986      * @static
9987      * @return {Element} The shared Element object
9988      * @member Roo
9989      * @method fly
9990      */
9991     Roo.fly = El.fly;
9992
9993     // speedy lookup for elements never to box adjust
9994     var noBoxAdjust = Roo.isStrict ? {
9995         select:1
9996     } : {
9997         input:1, select:1, textarea:1
9998     };
9999     if(Roo.isIE || Roo.isGecko){
10000         noBoxAdjust['button'] = 1;
10001     }
10002
10003
10004     Roo.EventManager.on(window, 'unload', function(){
10005         delete El.cache;
10006         delete El._flyweights;
10007     });
10008 })();
10009
10010
10011
10012
10013 if(Roo.DomQuery){
10014     Roo.Element.selectorFunction = Roo.DomQuery.select;
10015 }
10016
10017 Roo.Element.select = function(selector, unique, root){
10018     var els;
10019     if(typeof selector == "string"){
10020         els = Roo.Element.selectorFunction(selector, root);
10021     }else if(selector.length !== undefined){
10022         els = selector;
10023     }else{
10024         throw "Invalid selector";
10025     }
10026     if(unique === true){
10027         return new Roo.CompositeElement(els);
10028     }else{
10029         return new Roo.CompositeElementLite(els);
10030     }
10031 };
10032 /**
10033  * Selects elements based on the passed CSS selector to enable working on them as 1.
10034  * @param {String/Array} selector The CSS selector or an array of elements
10035  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10036  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10037  * @return {CompositeElementLite/CompositeElement}
10038  * @member Roo
10039  * @method select
10040  */
10041 Roo.select = Roo.Element.select;
10042
10043
10044
10045
10046
10047
10048
10049
10050
10051
10052
10053
10054
10055
10056 /*
10057  * Based on:
10058  * Ext JS Library 1.1.1
10059  * Copyright(c) 2006-2007, Ext JS, LLC.
10060  *
10061  * Originally Released Under LGPL - original licence link has changed is not relivant.
10062  *
10063  * Fork - LGPL
10064  * <script type="text/javascript">
10065  */
10066
10067
10068
10069 //Notifies Element that fx methods are available
10070 Roo.enableFx = true;
10071
10072 /**
10073  * @class Roo.Fx
10074  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10075  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10076  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10077  * Element effects to work.</p><br/>
10078  *
10079  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10080  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10081  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10082  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10083  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10084  * expected results and should be done with care.</p><br/>
10085  *
10086  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10087  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10088 <pre>
10089 Value  Description
10090 -----  -----------------------------
10091 tl     The top left corner
10092 t      The center of the top edge
10093 tr     The top right corner
10094 l      The center of the left edge
10095 r      The center of the right edge
10096 bl     The bottom left corner
10097 b      The center of the bottom edge
10098 br     The bottom right corner
10099 </pre>
10100  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10101  * below are common options that can be passed to any Fx method.</b>
10102  * @cfg {Function} callback A function called when the effect is finished
10103  * @cfg {Object} scope The scope of the effect function
10104  * @cfg {String} easing A valid Easing value for the effect
10105  * @cfg {String} afterCls A css class to apply after the effect
10106  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10107  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10108  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10109  * effects that end with the element being visually hidden, ignored otherwise)
10110  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10111  * a function which returns such a specification that will be applied to the Element after the effect finishes
10112  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10113  * @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
10114  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10115  */
10116 Roo.Fx = {
10117         /**
10118          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10119          * origin for the slide effect.  This function automatically handles wrapping the element with
10120          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10121          * Usage:
10122          *<pre><code>
10123 // default: slide the element in from the top
10124 el.slideIn();
10125
10126 // custom: slide the element in from the right with a 2-second duration
10127 el.slideIn('r', { duration: 2 });
10128
10129 // common config options shown with default values
10130 el.slideIn('t', {
10131     easing: 'easeOut',
10132     duration: .5
10133 });
10134 </code></pre>
10135          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10136          * @param {Object} options (optional) Object literal with any of the Fx config options
10137          * @return {Roo.Element} The Element
10138          */
10139     slideIn : function(anchor, o){
10140         var el = this.getFxEl();
10141         o = o || {};
10142
10143         el.queueFx(o, function(){
10144
10145             anchor = anchor || "t";
10146
10147             // fix display to visibility
10148             this.fixDisplay();
10149
10150             // restore values after effect
10151             var r = this.getFxRestore();
10152             var b = this.getBox();
10153             // fixed size for slide
10154             this.setSize(b);
10155
10156             // wrap if needed
10157             var wrap = this.fxWrap(r.pos, o, "hidden");
10158
10159             var st = this.dom.style;
10160             st.visibility = "visible";
10161             st.position = "absolute";
10162
10163             // clear out temp styles after slide and unwrap
10164             var after = function(){
10165                 el.fxUnwrap(wrap, r.pos, o);
10166                 st.width = r.width;
10167                 st.height = r.height;
10168                 el.afterFx(o);
10169             };
10170             // time to calc the positions
10171             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10172
10173             switch(anchor.toLowerCase()){
10174                 case "t":
10175                     wrap.setSize(b.width, 0);
10176                     st.left = st.bottom = "0";
10177                     a = {height: bh};
10178                 break;
10179                 case "l":
10180                     wrap.setSize(0, b.height);
10181                     st.right = st.top = "0";
10182                     a = {width: bw};
10183                 break;
10184                 case "r":
10185                     wrap.setSize(0, b.height);
10186                     wrap.setX(b.right);
10187                     st.left = st.top = "0";
10188                     a = {width: bw, points: pt};
10189                 break;
10190                 case "b":
10191                     wrap.setSize(b.width, 0);
10192                     wrap.setY(b.bottom);
10193                     st.left = st.top = "0";
10194                     a = {height: bh, points: pt};
10195                 break;
10196                 case "tl":
10197                     wrap.setSize(0, 0);
10198                     st.right = st.bottom = "0";
10199                     a = {width: bw, height: bh};
10200                 break;
10201                 case "bl":
10202                     wrap.setSize(0, 0);
10203                     wrap.setY(b.y+b.height);
10204                     st.right = st.top = "0";
10205                     a = {width: bw, height: bh, points: pt};
10206                 break;
10207                 case "br":
10208                     wrap.setSize(0, 0);
10209                     wrap.setXY([b.right, b.bottom]);
10210                     st.left = st.top = "0";
10211                     a = {width: bw, height: bh, points: pt};
10212                 break;
10213                 case "tr":
10214                     wrap.setSize(0, 0);
10215                     wrap.setX(b.x+b.width);
10216                     st.left = st.bottom = "0";
10217                     a = {width: bw, height: bh, points: pt};
10218                 break;
10219             }
10220             this.dom.style.visibility = "visible";
10221             wrap.show();
10222
10223             arguments.callee.anim = wrap.fxanim(a,
10224                 o,
10225                 'motion',
10226                 .5,
10227                 'easeOut', after);
10228         });
10229         return this;
10230     },
10231     
10232         /**
10233          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10234          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10235          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10236          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10237          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10238          * Usage:
10239          *<pre><code>
10240 // default: slide the element out to the top
10241 el.slideOut();
10242
10243 // custom: slide the element out to the right with a 2-second duration
10244 el.slideOut('r', { duration: 2 });
10245
10246 // common config options shown with default values
10247 el.slideOut('t', {
10248     easing: 'easeOut',
10249     duration: .5,
10250     remove: false,
10251     useDisplay: false
10252 });
10253 </code></pre>
10254          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10255          * @param {Object} options (optional) Object literal with any of the Fx config options
10256          * @return {Roo.Element} The Element
10257          */
10258     slideOut : function(anchor, o){
10259         var el = this.getFxEl();
10260         o = o || {};
10261
10262         el.queueFx(o, function(){
10263
10264             anchor = anchor || "t";
10265
10266             // restore values after effect
10267             var r = this.getFxRestore();
10268             
10269             var b = this.getBox();
10270             // fixed size for slide
10271             this.setSize(b);
10272
10273             // wrap if needed
10274             var wrap = this.fxWrap(r.pos, o, "visible");
10275
10276             var st = this.dom.style;
10277             st.visibility = "visible";
10278             st.position = "absolute";
10279
10280             wrap.setSize(b);
10281
10282             var after = function(){
10283                 if(o.useDisplay){
10284                     el.setDisplayed(false);
10285                 }else{
10286                     el.hide();
10287                 }
10288
10289                 el.fxUnwrap(wrap, r.pos, o);
10290
10291                 st.width = r.width;
10292                 st.height = r.height;
10293
10294                 el.afterFx(o);
10295             };
10296
10297             var a, zero = {to: 0};
10298             switch(anchor.toLowerCase()){
10299                 case "t":
10300                     st.left = st.bottom = "0";
10301                     a = {height: zero};
10302                 break;
10303                 case "l":
10304                     st.right = st.top = "0";
10305                     a = {width: zero};
10306                 break;
10307                 case "r":
10308                     st.left = st.top = "0";
10309                     a = {width: zero, points: {to:[b.right, b.y]}};
10310                 break;
10311                 case "b":
10312                     st.left = st.top = "0";
10313                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10314                 break;
10315                 case "tl":
10316                     st.right = st.bottom = "0";
10317                     a = {width: zero, height: zero};
10318                 break;
10319                 case "bl":
10320                     st.right = st.top = "0";
10321                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10322                 break;
10323                 case "br":
10324                     st.left = st.top = "0";
10325                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10326                 break;
10327                 case "tr":
10328                     st.left = st.bottom = "0";
10329                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10330                 break;
10331             }
10332
10333             arguments.callee.anim = wrap.fxanim(a,
10334                 o,
10335                 'motion',
10336                 .5,
10337                 "easeOut", after);
10338         });
10339         return this;
10340     },
10341
10342         /**
10343          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10344          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10345          * The element must be removed from the DOM using the 'remove' config option if desired.
10346          * Usage:
10347          *<pre><code>
10348 // default
10349 el.puff();
10350
10351 // common config options shown with default values
10352 el.puff({
10353     easing: 'easeOut',
10354     duration: .5,
10355     remove: false,
10356     useDisplay: false
10357 });
10358 </code></pre>
10359          * @param {Object} options (optional) Object literal with any of the Fx config options
10360          * @return {Roo.Element} The Element
10361          */
10362     puff : function(o){
10363         var el = this.getFxEl();
10364         o = o || {};
10365
10366         el.queueFx(o, function(){
10367             this.clearOpacity();
10368             this.show();
10369
10370             // restore values after effect
10371             var r = this.getFxRestore();
10372             var st = this.dom.style;
10373
10374             var after = function(){
10375                 if(o.useDisplay){
10376                     el.setDisplayed(false);
10377                 }else{
10378                     el.hide();
10379                 }
10380
10381                 el.clearOpacity();
10382
10383                 el.setPositioning(r.pos);
10384                 st.width = r.width;
10385                 st.height = r.height;
10386                 st.fontSize = '';
10387                 el.afterFx(o);
10388             };
10389
10390             var width = this.getWidth();
10391             var height = this.getHeight();
10392
10393             arguments.callee.anim = this.fxanim({
10394                     width : {to: this.adjustWidth(width * 2)},
10395                     height : {to: this.adjustHeight(height * 2)},
10396                     points : {by: [-(width * .5), -(height * .5)]},
10397                     opacity : {to: 0},
10398                     fontSize: {to:200, unit: "%"}
10399                 },
10400                 o,
10401                 'motion',
10402                 .5,
10403                 "easeOut", after);
10404         });
10405         return this;
10406     },
10407
10408         /**
10409          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10410          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10411          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10412          * Usage:
10413          *<pre><code>
10414 // default
10415 el.switchOff();
10416
10417 // all config options shown with default values
10418 el.switchOff({
10419     easing: 'easeIn',
10420     duration: .3,
10421     remove: false,
10422     useDisplay: false
10423 });
10424 </code></pre>
10425          * @param {Object} options (optional) Object literal with any of the Fx config options
10426          * @return {Roo.Element} The Element
10427          */
10428     switchOff : function(o){
10429         var el = this.getFxEl();
10430         o = o || {};
10431
10432         el.queueFx(o, function(){
10433             this.clearOpacity();
10434             this.clip();
10435
10436             // restore values after effect
10437             var r = this.getFxRestore();
10438             var st = this.dom.style;
10439
10440             var after = function(){
10441                 if(o.useDisplay){
10442                     el.setDisplayed(false);
10443                 }else{
10444                     el.hide();
10445                 }
10446
10447                 el.clearOpacity();
10448                 el.setPositioning(r.pos);
10449                 st.width = r.width;
10450                 st.height = r.height;
10451
10452                 el.afterFx(o);
10453             };
10454
10455             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10456                 this.clearOpacity();
10457                 (function(){
10458                     this.fxanim({
10459                         height:{to:1},
10460                         points:{by:[0, this.getHeight() * .5]}
10461                     }, o, 'motion', 0.3, 'easeIn', after);
10462                 }).defer(100, this);
10463             });
10464         });
10465         return this;
10466     },
10467
10468     /**
10469      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10470      * changed using the "attr" config option) and then fading back to the original color. If no original
10471      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10472      * Usage:
10473 <pre><code>
10474 // default: highlight background to yellow
10475 el.highlight();
10476
10477 // custom: highlight foreground text to blue for 2 seconds
10478 el.highlight("0000ff", { attr: 'color', duration: 2 });
10479
10480 // common config options shown with default values
10481 el.highlight("ffff9c", {
10482     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10483     endColor: (current color) or "ffffff",
10484     easing: 'easeIn',
10485     duration: 1
10486 });
10487 </code></pre>
10488      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10489      * @param {Object} options (optional) Object literal with any of the Fx config options
10490      * @return {Roo.Element} The Element
10491      */ 
10492     highlight : function(color, o){
10493         var el = this.getFxEl();
10494         o = o || {};
10495
10496         el.queueFx(o, function(){
10497             color = color || "ffff9c";
10498             attr = o.attr || "backgroundColor";
10499
10500             this.clearOpacity();
10501             this.show();
10502
10503             var origColor = this.getColor(attr);
10504             var restoreColor = this.dom.style[attr];
10505             endColor = (o.endColor || origColor) || "ffffff";
10506
10507             var after = function(){
10508                 el.dom.style[attr] = restoreColor;
10509                 el.afterFx(o);
10510             };
10511
10512             var a = {};
10513             a[attr] = {from: color, to: endColor};
10514             arguments.callee.anim = this.fxanim(a,
10515                 o,
10516                 'color',
10517                 1,
10518                 'easeIn', after);
10519         });
10520         return this;
10521     },
10522
10523    /**
10524     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10525     * Usage:
10526 <pre><code>
10527 // default: a single light blue ripple
10528 el.frame();
10529
10530 // custom: 3 red ripples lasting 3 seconds total
10531 el.frame("ff0000", 3, { duration: 3 });
10532
10533 // common config options shown with default values
10534 el.frame("C3DAF9", 1, {
10535     duration: 1 //duration of entire animation (not each individual ripple)
10536     // Note: Easing is not configurable and will be ignored if included
10537 });
10538 </code></pre>
10539     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10540     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10541     * @param {Object} options (optional) Object literal with any of the Fx config options
10542     * @return {Roo.Element} The Element
10543     */
10544     frame : function(color, count, o){
10545         var el = this.getFxEl();
10546         o = o || {};
10547
10548         el.queueFx(o, function(){
10549             color = color || "#C3DAF9";
10550             if(color.length == 6){
10551                 color = "#" + color;
10552             }
10553             count = count || 1;
10554             duration = o.duration || 1;
10555             this.show();
10556
10557             var b = this.getBox();
10558             var animFn = function(){
10559                 var proxy = this.createProxy({
10560
10561                      style:{
10562                         visbility:"hidden",
10563                         position:"absolute",
10564                         "z-index":"35000", // yee haw
10565                         border:"0px solid " + color
10566                      }
10567                   });
10568                 var scale = Roo.isBorderBox ? 2 : 1;
10569                 proxy.animate({
10570                     top:{from:b.y, to:b.y - 20},
10571                     left:{from:b.x, to:b.x - 20},
10572                     borderWidth:{from:0, to:10},
10573                     opacity:{from:1, to:0},
10574                     height:{from:b.height, to:(b.height + (20*scale))},
10575                     width:{from:b.width, to:(b.width + (20*scale))}
10576                 }, duration, function(){
10577                     proxy.remove();
10578                 });
10579                 if(--count > 0){
10580                      animFn.defer((duration/2)*1000, this);
10581                 }else{
10582                     el.afterFx(o);
10583                 }
10584             };
10585             animFn.call(this);
10586         });
10587         return this;
10588     },
10589
10590    /**
10591     * Creates a pause before any subsequent queued effects begin.  If there are
10592     * no effects queued after the pause it will have no effect.
10593     * Usage:
10594 <pre><code>
10595 el.pause(1);
10596 </code></pre>
10597     * @param {Number} seconds The length of time to pause (in seconds)
10598     * @return {Roo.Element} The Element
10599     */
10600     pause : function(seconds){
10601         var el = this.getFxEl();
10602         var o = {};
10603
10604         el.queueFx(o, function(){
10605             setTimeout(function(){
10606                 el.afterFx(o);
10607             }, seconds * 1000);
10608         });
10609         return this;
10610     },
10611
10612    /**
10613     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10614     * using the "endOpacity" config option.
10615     * Usage:
10616 <pre><code>
10617 // default: fade in from opacity 0 to 100%
10618 el.fadeIn();
10619
10620 // custom: fade in from opacity 0 to 75% over 2 seconds
10621 el.fadeIn({ endOpacity: .75, duration: 2});
10622
10623 // common config options shown with default values
10624 el.fadeIn({
10625     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10626     easing: 'easeOut',
10627     duration: .5
10628 });
10629 </code></pre>
10630     * @param {Object} options (optional) Object literal with any of the Fx config options
10631     * @return {Roo.Element} The Element
10632     */
10633     fadeIn : function(o){
10634         var el = this.getFxEl();
10635         o = o || {};
10636         el.queueFx(o, function(){
10637             this.setOpacity(0);
10638             this.fixDisplay();
10639             this.dom.style.visibility = 'visible';
10640             var to = o.endOpacity || 1;
10641             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10642                 o, null, .5, "easeOut", function(){
10643                 if(to == 1){
10644                     this.clearOpacity();
10645                 }
10646                 el.afterFx(o);
10647             });
10648         });
10649         return this;
10650     },
10651
10652    /**
10653     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10654     * using the "endOpacity" config option.
10655     * Usage:
10656 <pre><code>
10657 // default: fade out from the element's current opacity to 0
10658 el.fadeOut();
10659
10660 // custom: fade out from the element's current opacity to 25% over 2 seconds
10661 el.fadeOut({ endOpacity: .25, duration: 2});
10662
10663 // common config options shown with default values
10664 el.fadeOut({
10665     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10666     easing: 'easeOut',
10667     duration: .5
10668     remove: false,
10669     useDisplay: false
10670 });
10671 </code></pre>
10672     * @param {Object} options (optional) Object literal with any of the Fx config options
10673     * @return {Roo.Element} The Element
10674     */
10675     fadeOut : function(o){
10676         var el = this.getFxEl();
10677         o = o || {};
10678         el.queueFx(o, function(){
10679             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10680                 o, null, .5, "easeOut", function(){
10681                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10682                      this.dom.style.display = "none";
10683                 }else{
10684                      this.dom.style.visibility = "hidden";
10685                 }
10686                 this.clearOpacity();
10687                 el.afterFx(o);
10688             });
10689         });
10690         return this;
10691     },
10692
10693    /**
10694     * Animates the transition of an element's dimensions from a starting height/width
10695     * to an ending height/width.
10696     * Usage:
10697 <pre><code>
10698 // change height and width to 100x100 pixels
10699 el.scale(100, 100);
10700
10701 // common config options shown with default values.  The height and width will default to
10702 // the element's existing values if passed as null.
10703 el.scale(
10704     [element's width],
10705     [element's height], {
10706     easing: 'easeOut',
10707     duration: .35
10708 });
10709 </code></pre>
10710     * @param {Number} width  The new width (pass undefined to keep the original width)
10711     * @param {Number} height  The new height (pass undefined to keep the original height)
10712     * @param {Object} options (optional) Object literal with any of the Fx config options
10713     * @return {Roo.Element} The Element
10714     */
10715     scale : function(w, h, o){
10716         this.shift(Roo.apply({}, o, {
10717             width: w,
10718             height: h
10719         }));
10720         return this;
10721     },
10722
10723    /**
10724     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10725     * Any of these properties not specified in the config object will not be changed.  This effect 
10726     * requires that at least one new dimension, position or opacity setting must be passed in on
10727     * the config object in order for the function to have any effect.
10728     * Usage:
10729 <pre><code>
10730 // slide the element horizontally to x position 200 while changing the height and opacity
10731 el.shift({ x: 200, height: 50, opacity: .8 });
10732
10733 // common config options shown with default values.
10734 el.shift({
10735     width: [element's width],
10736     height: [element's height],
10737     x: [element's x position],
10738     y: [element's y position],
10739     opacity: [element's opacity],
10740     easing: 'easeOut',
10741     duration: .35
10742 });
10743 </code></pre>
10744     * @param {Object} options  Object literal with any of the Fx config options
10745     * @return {Roo.Element} The Element
10746     */
10747     shift : function(o){
10748         var el = this.getFxEl();
10749         o = o || {};
10750         el.queueFx(o, function(){
10751             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10752             if(w !== undefined){
10753                 a.width = {to: this.adjustWidth(w)};
10754             }
10755             if(h !== undefined){
10756                 a.height = {to: this.adjustHeight(h)};
10757             }
10758             if(x !== undefined || y !== undefined){
10759                 a.points = {to: [
10760                     x !== undefined ? x : this.getX(),
10761                     y !== undefined ? y : this.getY()
10762                 ]};
10763             }
10764             if(op !== undefined){
10765                 a.opacity = {to: op};
10766             }
10767             if(o.xy !== undefined){
10768                 a.points = {to: o.xy};
10769             }
10770             arguments.callee.anim = this.fxanim(a,
10771                 o, 'motion', .35, "easeOut", function(){
10772                 el.afterFx(o);
10773             });
10774         });
10775         return this;
10776     },
10777
10778         /**
10779          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10780          * ending point of the effect.
10781          * Usage:
10782          *<pre><code>
10783 // default: slide the element downward while fading out
10784 el.ghost();
10785
10786 // custom: slide the element out to the right with a 2-second duration
10787 el.ghost('r', { duration: 2 });
10788
10789 // common config options shown with default values
10790 el.ghost('b', {
10791     easing: 'easeOut',
10792     duration: .5
10793     remove: false,
10794     useDisplay: false
10795 });
10796 </code></pre>
10797          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10798          * @param {Object} options (optional) Object literal with any of the Fx config options
10799          * @return {Roo.Element} The Element
10800          */
10801     ghost : function(anchor, o){
10802         var el = this.getFxEl();
10803         o = o || {};
10804
10805         el.queueFx(o, function(){
10806             anchor = anchor || "b";
10807
10808             // restore values after effect
10809             var r = this.getFxRestore();
10810             var w = this.getWidth(),
10811                 h = this.getHeight();
10812
10813             var st = this.dom.style;
10814
10815             var after = function(){
10816                 if(o.useDisplay){
10817                     el.setDisplayed(false);
10818                 }else{
10819                     el.hide();
10820                 }
10821
10822                 el.clearOpacity();
10823                 el.setPositioning(r.pos);
10824                 st.width = r.width;
10825                 st.height = r.height;
10826
10827                 el.afterFx(o);
10828             };
10829
10830             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10831             switch(anchor.toLowerCase()){
10832                 case "t":
10833                     pt.by = [0, -h];
10834                 break;
10835                 case "l":
10836                     pt.by = [-w, 0];
10837                 break;
10838                 case "r":
10839                     pt.by = [w, 0];
10840                 break;
10841                 case "b":
10842                     pt.by = [0, h];
10843                 break;
10844                 case "tl":
10845                     pt.by = [-w, -h];
10846                 break;
10847                 case "bl":
10848                     pt.by = [-w, h];
10849                 break;
10850                 case "br":
10851                     pt.by = [w, h];
10852                 break;
10853                 case "tr":
10854                     pt.by = [w, -h];
10855                 break;
10856             }
10857
10858             arguments.callee.anim = this.fxanim(a,
10859                 o,
10860                 'motion',
10861                 .5,
10862                 "easeOut", after);
10863         });
10864         return this;
10865     },
10866
10867         /**
10868          * Ensures that all effects queued after syncFx is called on the element are
10869          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10870          * @return {Roo.Element} The Element
10871          */
10872     syncFx : function(){
10873         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10874             block : false,
10875             concurrent : true,
10876             stopFx : false
10877         });
10878         return this;
10879     },
10880
10881         /**
10882          * Ensures that all effects queued after sequenceFx is called on the element are
10883          * run in sequence.  This is the opposite of {@link #syncFx}.
10884          * @return {Roo.Element} The Element
10885          */
10886     sequenceFx : function(){
10887         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10888             block : false,
10889             concurrent : false,
10890             stopFx : false
10891         });
10892         return this;
10893     },
10894
10895         /* @private */
10896     nextFx : function(){
10897         var ef = this.fxQueue[0];
10898         if(ef){
10899             ef.call(this);
10900         }
10901     },
10902
10903         /**
10904          * Returns true if the element has any effects actively running or queued, else returns false.
10905          * @return {Boolean} True if element has active effects, else false
10906          */
10907     hasActiveFx : function(){
10908         return this.fxQueue && this.fxQueue[0];
10909     },
10910
10911         /**
10912          * Stops any running effects and clears the element's internal effects queue if it contains
10913          * any additional effects that haven't started yet.
10914          * @return {Roo.Element} The Element
10915          */
10916     stopFx : function(){
10917         if(this.hasActiveFx()){
10918             var cur = this.fxQueue[0];
10919             if(cur && cur.anim && cur.anim.isAnimated()){
10920                 this.fxQueue = [cur]; // clear out others
10921                 cur.anim.stop(true);
10922             }
10923         }
10924         return this;
10925     },
10926
10927         /* @private */
10928     beforeFx : function(o){
10929         if(this.hasActiveFx() && !o.concurrent){
10930            if(o.stopFx){
10931                this.stopFx();
10932                return true;
10933            }
10934            return false;
10935         }
10936         return true;
10937     },
10938
10939         /**
10940          * Returns true if the element is currently blocking so that no other effect can be queued
10941          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10942          * used to ensure that an effect initiated by a user action runs to completion prior to the
10943          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10944          * @return {Boolean} True if blocking, else false
10945          */
10946     hasFxBlock : function(){
10947         var q = this.fxQueue;
10948         return q && q[0] && q[0].block;
10949     },
10950
10951         /* @private */
10952     queueFx : function(o, fn){
10953         if(!this.fxQueue){
10954             this.fxQueue = [];
10955         }
10956         if(!this.hasFxBlock()){
10957             Roo.applyIf(o, this.fxDefaults);
10958             if(!o.concurrent){
10959                 var run = this.beforeFx(o);
10960                 fn.block = o.block;
10961                 this.fxQueue.push(fn);
10962                 if(run){
10963                     this.nextFx();
10964                 }
10965             }else{
10966                 fn.call(this);
10967             }
10968         }
10969         return this;
10970     },
10971
10972         /* @private */
10973     fxWrap : function(pos, o, vis){
10974         var wrap;
10975         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10976             var wrapXY;
10977             if(o.fixPosition){
10978                 wrapXY = this.getXY();
10979             }
10980             var div = document.createElement("div");
10981             div.style.visibility = vis;
10982             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10983             wrap.setPositioning(pos);
10984             if(wrap.getStyle("position") == "static"){
10985                 wrap.position("relative");
10986             }
10987             this.clearPositioning('auto');
10988             wrap.clip();
10989             wrap.dom.appendChild(this.dom);
10990             if(wrapXY){
10991                 wrap.setXY(wrapXY);
10992             }
10993         }
10994         return wrap;
10995     },
10996
10997         /* @private */
10998     fxUnwrap : function(wrap, pos, o){
10999         this.clearPositioning();
11000         this.setPositioning(pos);
11001         if(!o.wrap){
11002             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11003             wrap.remove();
11004         }
11005     },
11006
11007         /* @private */
11008     getFxRestore : function(){
11009         var st = this.dom.style;
11010         return {pos: this.getPositioning(), width: st.width, height : st.height};
11011     },
11012
11013         /* @private */
11014     afterFx : function(o){
11015         if(o.afterStyle){
11016             this.applyStyles(o.afterStyle);
11017         }
11018         if(o.afterCls){
11019             this.addClass(o.afterCls);
11020         }
11021         if(o.remove === true){
11022             this.remove();
11023         }
11024         Roo.callback(o.callback, o.scope, [this]);
11025         if(!o.concurrent){
11026             this.fxQueue.shift();
11027             this.nextFx();
11028         }
11029     },
11030
11031         /* @private */
11032     getFxEl : function(){ // support for composite element fx
11033         return Roo.get(this.dom);
11034     },
11035
11036         /* @private */
11037     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11038         animType = animType || 'run';
11039         opt = opt || {};
11040         var anim = Roo.lib.Anim[animType](
11041             this.dom, args,
11042             (opt.duration || defaultDur) || .35,
11043             (opt.easing || defaultEase) || 'easeOut',
11044             function(){
11045                 Roo.callback(cb, this);
11046             },
11047             this
11048         );
11049         opt.anim = anim;
11050         return anim;
11051     }
11052 };
11053
11054 // backwords compat
11055 Roo.Fx.resize = Roo.Fx.scale;
11056
11057 //When included, Roo.Fx is automatically applied to Element so that all basic
11058 //effects are available directly via the Element API
11059 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11060  * Based on:
11061  * Ext JS Library 1.1.1
11062  * Copyright(c) 2006-2007, Ext JS, LLC.
11063  *
11064  * Originally Released Under LGPL - original licence link has changed is not relivant.
11065  *
11066  * Fork - LGPL
11067  * <script type="text/javascript">
11068  */
11069
11070
11071 /**
11072  * @class Roo.CompositeElement
11073  * Standard composite class. Creates a Roo.Element for every element in the collection.
11074  * <br><br>
11075  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11076  * actions will be performed on all the elements in this collection.</b>
11077  * <br><br>
11078  * All methods return <i>this</i> and can be chained.
11079  <pre><code>
11080  var els = Roo.select("#some-el div.some-class", true);
11081  // or select directly from an existing element
11082  var el = Roo.get('some-el');
11083  el.select('div.some-class', true);
11084
11085  els.setWidth(100); // all elements become 100 width
11086  els.hide(true); // all elements fade out and hide
11087  // or
11088  els.setWidth(100).hide(true);
11089  </code></pre>
11090  */
11091 Roo.CompositeElement = function(els){
11092     this.elements = [];
11093     this.addElements(els);
11094 };
11095 Roo.CompositeElement.prototype = {
11096     isComposite: true,
11097     addElements : function(els){
11098         if(!els) {
11099             return this;
11100         }
11101         if(typeof els == "string"){
11102             els = Roo.Element.selectorFunction(els);
11103         }
11104         var yels = this.elements;
11105         var index = yels.length-1;
11106         for(var i = 0, len = els.length; i < len; i++) {
11107                 yels[++index] = Roo.get(els[i]);
11108         }
11109         return this;
11110     },
11111
11112     /**
11113     * Clears this composite and adds the elements returned by the passed selector.
11114     * @param {String/Array} els A string CSS selector, an array of elements or an element
11115     * @return {CompositeElement} this
11116     */
11117     fill : function(els){
11118         this.elements = [];
11119         this.add(els);
11120         return this;
11121     },
11122
11123     /**
11124     * Filters this composite to only elements that match the passed selector.
11125     * @param {String} selector A string CSS selector
11126     * @param {Boolean} inverse return inverse filter (not matches)
11127     * @return {CompositeElement} this
11128     */
11129     filter : function(selector, inverse){
11130         var els = [];
11131         inverse = inverse || false;
11132         this.each(function(el){
11133             var match = inverse ? !el.is(selector) : el.is(selector);
11134             if(match){
11135                 els[els.length] = el.dom;
11136             }
11137         });
11138         this.fill(els);
11139         return this;
11140     },
11141
11142     invoke : function(fn, args){
11143         var els = this.elements;
11144         for(var i = 0, len = els.length; i < len; i++) {
11145                 Roo.Element.prototype[fn].apply(els[i], args);
11146         }
11147         return this;
11148     },
11149     /**
11150     * Adds elements to this composite.
11151     * @param {String/Array} els A string CSS selector, an array of elements or an element
11152     * @return {CompositeElement} this
11153     */
11154     add : function(els){
11155         if(typeof els == "string"){
11156             this.addElements(Roo.Element.selectorFunction(els));
11157         }else if(els.length !== undefined){
11158             this.addElements(els);
11159         }else{
11160             this.addElements([els]);
11161         }
11162         return this;
11163     },
11164     /**
11165     * Calls the passed function passing (el, this, index) for each element in this composite.
11166     * @param {Function} fn The function to call
11167     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11168     * @return {CompositeElement} this
11169     */
11170     each : function(fn, scope){
11171         var els = this.elements;
11172         for(var i = 0, len = els.length; i < len; i++){
11173             if(fn.call(scope || els[i], els[i], this, i) === false) {
11174                 break;
11175             }
11176         }
11177         return this;
11178     },
11179
11180     /**
11181      * Returns the Element object at the specified index
11182      * @param {Number} index
11183      * @return {Roo.Element}
11184      */
11185     item : function(index){
11186         return this.elements[index] || null;
11187     },
11188
11189     /**
11190      * Returns the first Element
11191      * @return {Roo.Element}
11192      */
11193     first : function(){
11194         return this.item(0);
11195     },
11196
11197     /**
11198      * Returns the last Element
11199      * @return {Roo.Element}
11200      */
11201     last : function(){
11202         return this.item(this.elements.length-1);
11203     },
11204
11205     /**
11206      * Returns the number of elements in this composite
11207      * @return Number
11208      */
11209     getCount : function(){
11210         return this.elements.length;
11211     },
11212
11213     /**
11214      * Returns true if this composite contains the passed element
11215      * @return Boolean
11216      */
11217     contains : function(el){
11218         return this.indexOf(el) !== -1;
11219     },
11220
11221     /**
11222      * Returns true if this composite contains the passed element
11223      * @return Boolean
11224      */
11225     indexOf : function(el){
11226         return this.elements.indexOf(Roo.get(el));
11227     },
11228
11229
11230     /**
11231     * Removes the specified element(s).
11232     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11233     * or an array of any of those.
11234     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11235     * @return {CompositeElement} this
11236     */
11237     removeElement : function(el, removeDom){
11238         if(el instanceof Array){
11239             for(var i = 0, len = el.length; i < len; i++){
11240                 this.removeElement(el[i]);
11241             }
11242             return this;
11243         }
11244         var index = typeof el == 'number' ? el : this.indexOf(el);
11245         if(index !== -1){
11246             if(removeDom){
11247                 var d = this.elements[index];
11248                 if(d.dom){
11249                     d.remove();
11250                 }else{
11251                     d.parentNode.removeChild(d);
11252                 }
11253             }
11254             this.elements.splice(index, 1);
11255         }
11256         return this;
11257     },
11258
11259     /**
11260     * Replaces the specified element with the passed element.
11261     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11262     * to replace.
11263     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11264     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11265     * @return {CompositeElement} this
11266     */
11267     replaceElement : function(el, replacement, domReplace){
11268         var index = typeof el == 'number' ? el : this.indexOf(el);
11269         if(index !== -1){
11270             if(domReplace){
11271                 this.elements[index].replaceWith(replacement);
11272             }else{
11273                 this.elements.splice(index, 1, Roo.get(replacement))
11274             }
11275         }
11276         return this;
11277     },
11278
11279     /**
11280      * Removes all elements.
11281      */
11282     clear : function(){
11283         this.elements = [];
11284     }
11285 };
11286 (function(){
11287     Roo.CompositeElement.createCall = function(proto, fnName){
11288         if(!proto[fnName]){
11289             proto[fnName] = function(){
11290                 return this.invoke(fnName, arguments);
11291             };
11292         }
11293     };
11294     for(var fnName in Roo.Element.prototype){
11295         if(typeof Roo.Element.prototype[fnName] == "function"){
11296             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11297         }
11298     };
11299 })();
11300 /*
11301  * Based on:
11302  * Ext JS Library 1.1.1
11303  * Copyright(c) 2006-2007, Ext JS, LLC.
11304  *
11305  * Originally Released Under LGPL - original licence link has changed is not relivant.
11306  *
11307  * Fork - LGPL
11308  * <script type="text/javascript">
11309  */
11310
11311 /**
11312  * @class Roo.CompositeElementLite
11313  * @extends Roo.CompositeElement
11314  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11315  <pre><code>
11316  var els = Roo.select("#some-el div.some-class");
11317  // or select directly from an existing element
11318  var el = Roo.get('some-el');
11319  el.select('div.some-class');
11320
11321  els.setWidth(100); // all elements become 100 width
11322  els.hide(true); // all elements fade out and hide
11323  // or
11324  els.setWidth(100).hide(true);
11325  </code></pre><br><br>
11326  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11327  * actions will be performed on all the elements in this collection.</b>
11328  */
11329 Roo.CompositeElementLite = function(els){
11330     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11331     this.el = new Roo.Element.Flyweight();
11332 };
11333 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11334     addElements : function(els){
11335         if(els){
11336             if(els instanceof Array){
11337                 this.elements = this.elements.concat(els);
11338             }else{
11339                 var yels = this.elements;
11340                 var index = yels.length-1;
11341                 for(var i = 0, len = els.length; i < len; i++) {
11342                     yels[++index] = els[i];
11343                 }
11344             }
11345         }
11346         return this;
11347     },
11348     invoke : function(fn, args){
11349         var els = this.elements;
11350         var el = this.el;
11351         for(var i = 0, len = els.length; i < len; i++) {
11352             el.dom = els[i];
11353                 Roo.Element.prototype[fn].apply(el, args);
11354         }
11355         return this;
11356     },
11357     /**
11358      * Returns a flyweight Element of the dom element object at the specified index
11359      * @param {Number} index
11360      * @return {Roo.Element}
11361      */
11362     item : function(index){
11363         if(!this.elements[index]){
11364             return null;
11365         }
11366         this.el.dom = this.elements[index];
11367         return this.el;
11368     },
11369
11370     // fixes scope with flyweight
11371     addListener : function(eventName, handler, scope, opt){
11372         var els = this.elements;
11373         for(var i = 0, len = els.length; i < len; i++) {
11374             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11375         }
11376         return this;
11377     },
11378
11379     /**
11380     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11381     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11382     * a reference to the dom node, use el.dom.</b>
11383     * @param {Function} fn The function to call
11384     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11385     * @return {CompositeElement} this
11386     */
11387     each : function(fn, scope){
11388         var els = this.elements;
11389         var el = this.el;
11390         for(var i = 0, len = els.length; i < len; i++){
11391             el.dom = els[i];
11392                 if(fn.call(scope || el, el, this, i) === false){
11393                 break;
11394             }
11395         }
11396         return this;
11397     },
11398
11399     indexOf : function(el){
11400         return this.elements.indexOf(Roo.getDom(el));
11401     },
11402
11403     replaceElement : function(el, replacement, domReplace){
11404         var index = typeof el == 'number' ? el : this.indexOf(el);
11405         if(index !== -1){
11406             replacement = Roo.getDom(replacement);
11407             if(domReplace){
11408                 var d = this.elements[index];
11409                 d.parentNode.insertBefore(replacement, d);
11410                 d.parentNode.removeChild(d);
11411             }
11412             this.elements.splice(index, 1, replacement);
11413         }
11414         return this;
11415     }
11416 });
11417 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11418
11419 /*
11420  * Based on:
11421  * Ext JS Library 1.1.1
11422  * Copyright(c) 2006-2007, Ext JS, LLC.
11423  *
11424  * Originally Released Under LGPL - original licence link has changed is not relivant.
11425  *
11426  * Fork - LGPL
11427  * <script type="text/javascript">
11428  */
11429
11430  
11431
11432 /**
11433  * @class Roo.data.Connection
11434  * @extends Roo.util.Observable
11435  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11436  * either to a configured URL, or to a URL specified at request time.<br><br>
11437  * <p>
11438  * Requests made by this class are asynchronous, and will return immediately. No data from
11439  * the server will be available to the statement immediately following the {@link #request} call.
11440  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11441  * <p>
11442  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11443  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11444  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11445  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11446  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11447  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11448  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11449  * standard DOM methods.
11450  * @constructor
11451  * @param {Object} config a configuration object.
11452  */
11453 Roo.data.Connection = function(config){
11454     Roo.apply(this, config);
11455     this.addEvents({
11456         /**
11457          * @event beforerequest
11458          * Fires before a network request is made to retrieve a data object.
11459          * @param {Connection} conn This Connection object.
11460          * @param {Object} options The options config object passed to the {@link #request} method.
11461          */
11462         "beforerequest" : true,
11463         /**
11464          * @event requestcomplete
11465          * Fires if the request was successfully completed.
11466          * @param {Connection} conn This Connection object.
11467          * @param {Object} response The XHR object containing the response data.
11468          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11469          * @param {Object} options The options config object passed to the {@link #request} method.
11470          */
11471         "requestcomplete" : true,
11472         /**
11473          * @event requestexception
11474          * Fires if an error HTTP status was returned from the server.
11475          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11476          * @param {Connection} conn This Connection object.
11477          * @param {Object} response The XHR object containing the response data.
11478          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11479          * @param {Object} options The options config object passed to the {@link #request} method.
11480          */
11481         "requestexception" : true
11482     });
11483     Roo.data.Connection.superclass.constructor.call(this);
11484 };
11485
11486 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11487     /**
11488      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11489      */
11490     /**
11491      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11492      * extra parameters to each request made by this object. (defaults to undefined)
11493      */
11494     /**
11495      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11496      *  to each request made by this object. (defaults to undefined)
11497      */
11498     /**
11499      * @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)
11500      */
11501     /**
11502      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11503      */
11504     timeout : 30000,
11505     /**
11506      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11507      * @type Boolean
11508      */
11509     autoAbort:false,
11510
11511     /**
11512      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11513      * @type Boolean
11514      */
11515     disableCaching: true,
11516
11517     /**
11518      * Sends an HTTP request to a remote server.
11519      * @param {Object} options An object which may contain the following properties:<ul>
11520      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11521      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11522      * request, a url encoded string or a function to call to get either.</li>
11523      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11524      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11525      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11526      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11527      * <li>options {Object} The parameter to the request call.</li>
11528      * <li>success {Boolean} True if the request succeeded.</li>
11529      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11530      * </ul></li>
11531      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11532      * The callback is passed the following parameters:<ul>
11533      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11534      * <li>options {Object} The parameter to the request call.</li>
11535      * </ul></li>
11536      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11537      * The callback is passed the following parameters:<ul>
11538      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11539      * <li>options {Object} The parameter to the request call.</li>
11540      * </ul></li>
11541      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11542      * for the callback function. Defaults to the browser window.</li>
11543      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11544      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11545      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11546      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11547      * params for the post data. Any params will be appended to the URL.</li>
11548      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11549      * </ul>
11550      * @return {Number} transactionId
11551      */
11552     request : function(o){
11553         if(this.fireEvent("beforerequest", this, o) !== false){
11554             var p = o.params;
11555
11556             if(typeof p == "function"){
11557                 p = p.call(o.scope||window, o);
11558             }
11559             if(typeof p == "object"){
11560                 p = Roo.urlEncode(o.params);
11561             }
11562             if(this.extraParams){
11563                 var extras = Roo.urlEncode(this.extraParams);
11564                 p = p ? (p + '&' + extras) : extras;
11565             }
11566
11567             var url = o.url || this.url;
11568             if(typeof url == 'function'){
11569                 url = url.call(o.scope||window, o);
11570             }
11571
11572             if(o.form){
11573                 var form = Roo.getDom(o.form);
11574                 url = url || form.action;
11575
11576                 var enctype = form.getAttribute("enctype");
11577                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11578                     return this.doFormUpload(o, p, url);
11579                 }
11580                 var f = Roo.lib.Ajax.serializeForm(form);
11581                 p = p ? (p + '&' + f) : f;
11582             }
11583
11584             var hs = o.headers;
11585             if(this.defaultHeaders){
11586                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11587                 if(!o.headers){
11588                     o.headers = hs;
11589                 }
11590             }
11591
11592             var cb = {
11593                 success: this.handleResponse,
11594                 failure: this.handleFailure,
11595                 scope: this,
11596                 argument: {options: o},
11597                 timeout : o.timeout || this.timeout
11598             };
11599
11600             var method = o.method||this.method||(p ? "POST" : "GET");
11601
11602             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11603                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11604             }
11605
11606             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11607                 if(o.autoAbort){
11608                     this.abort();
11609                 }
11610             }else if(this.autoAbort !== false){
11611                 this.abort();
11612             }
11613
11614             if((method == 'GET' && p) || o.xmlData){
11615                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11616                 p = '';
11617             }
11618             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11619             return this.transId;
11620         }else{
11621             Roo.callback(o.callback, o.scope, [o, null, null]);
11622             return null;
11623         }
11624     },
11625
11626     /**
11627      * Determine whether this object has a request outstanding.
11628      * @param {Number} transactionId (Optional) defaults to the last transaction
11629      * @return {Boolean} True if there is an outstanding request.
11630      */
11631     isLoading : function(transId){
11632         if(transId){
11633             return Roo.lib.Ajax.isCallInProgress(transId);
11634         }else{
11635             return this.transId ? true : false;
11636         }
11637     },
11638
11639     /**
11640      * Aborts any outstanding request.
11641      * @param {Number} transactionId (Optional) defaults to the last transaction
11642      */
11643     abort : function(transId){
11644         if(transId || this.isLoading()){
11645             Roo.lib.Ajax.abort(transId || this.transId);
11646         }
11647     },
11648
11649     // private
11650     handleResponse : function(response){
11651         this.transId = false;
11652         var options = response.argument.options;
11653         response.argument = options ? options.argument : null;
11654         this.fireEvent("requestcomplete", this, response, options);
11655         Roo.callback(options.success, options.scope, [response, options]);
11656         Roo.callback(options.callback, options.scope, [options, true, response]);
11657     },
11658
11659     // private
11660     handleFailure : function(response, e){
11661         this.transId = false;
11662         var options = response.argument.options;
11663         response.argument = options ? options.argument : null;
11664         this.fireEvent("requestexception", this, response, options, e);
11665         Roo.callback(options.failure, options.scope, [response, options]);
11666         Roo.callback(options.callback, options.scope, [options, false, response]);
11667     },
11668
11669     // private
11670     doFormUpload : function(o, ps, url){
11671         var id = Roo.id();
11672         var frame = document.createElement('iframe');
11673         frame.id = id;
11674         frame.name = id;
11675         frame.className = 'x-hidden';
11676         if(Roo.isIE){
11677             frame.src = Roo.SSL_SECURE_URL;
11678         }
11679         document.body.appendChild(frame);
11680
11681         if(Roo.isIE){
11682            document.frames[id].name = id;
11683         }
11684
11685         var form = Roo.getDom(o.form);
11686         form.target = id;
11687         form.method = 'POST';
11688         form.enctype = form.encoding = 'multipart/form-data';
11689         if(url){
11690             form.action = url;
11691         }
11692
11693         var hiddens, hd;
11694         if(ps){ // add dynamic params
11695             hiddens = [];
11696             ps = Roo.urlDecode(ps, false);
11697             for(var k in ps){
11698                 if(ps.hasOwnProperty(k)){
11699                     hd = document.createElement('input');
11700                     hd.type = 'hidden';
11701                     hd.name = k;
11702                     hd.value = ps[k];
11703                     form.appendChild(hd);
11704                     hiddens.push(hd);
11705                 }
11706             }
11707         }
11708
11709         function cb(){
11710             var r = {  // bogus response object
11711                 responseText : '',
11712                 responseXML : null
11713             };
11714
11715             r.argument = o ? o.argument : null;
11716
11717             try { //
11718                 var doc;
11719                 if(Roo.isIE){
11720                     doc = frame.contentWindow.document;
11721                 }else {
11722                     doc = (frame.contentDocument || window.frames[id].document);
11723                 }
11724                 if(doc && doc.body){
11725                     r.responseText = doc.body.innerHTML;
11726                 }
11727                 if(doc && doc.XMLDocument){
11728                     r.responseXML = doc.XMLDocument;
11729                 }else {
11730                     r.responseXML = doc;
11731                 }
11732             }
11733             catch(e) {
11734                 // ignore
11735             }
11736
11737             Roo.EventManager.removeListener(frame, 'load', cb, this);
11738
11739             this.fireEvent("requestcomplete", this, r, o);
11740             Roo.callback(o.success, o.scope, [r, o]);
11741             Roo.callback(o.callback, o.scope, [o, true, r]);
11742
11743             setTimeout(function(){document.body.removeChild(frame);}, 100);
11744         }
11745
11746         Roo.EventManager.on(frame, 'load', cb, this);
11747         form.submit();
11748
11749         if(hiddens){ // remove dynamic params
11750             for(var i = 0, len = hiddens.length; i < len; i++){
11751                 form.removeChild(hiddens[i]);
11752             }
11753         }
11754     }
11755 });
11756 /*
11757  * Based on:
11758  * Ext JS Library 1.1.1
11759  * Copyright(c) 2006-2007, Ext JS, LLC.
11760  *
11761  * Originally Released Under LGPL - original licence link has changed is not relivant.
11762  *
11763  * Fork - LGPL
11764  * <script type="text/javascript">
11765  */
11766  
11767 /**
11768  * Global Ajax request class.
11769  * 
11770  * @class Roo.Ajax
11771  * @extends Roo.data.Connection
11772  * @static
11773  * 
11774  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11775  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11776  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11777  * @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)
11778  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11779  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11780  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11781  */
11782 Roo.Ajax = new Roo.data.Connection({
11783     // fix up the docs
11784     /**
11785      * @scope Roo.Ajax
11786      * @type {Boolear} 
11787      */
11788     autoAbort : false,
11789
11790     /**
11791      * Serialize the passed form into a url encoded string
11792      * @scope Roo.Ajax
11793      * @param {String/HTMLElement} form
11794      * @return {String}
11795      */
11796     serializeForm : function(form){
11797         return Roo.lib.Ajax.serializeForm(form);
11798     }
11799 });/*
11800  * Based on:
11801  * Ext JS Library 1.1.1
11802  * Copyright(c) 2006-2007, Ext JS, LLC.
11803  *
11804  * Originally Released Under LGPL - original licence link has changed is not relivant.
11805  *
11806  * Fork - LGPL
11807  * <script type="text/javascript">
11808  */
11809
11810  
11811 /**
11812  * @class Roo.UpdateManager
11813  * @extends Roo.util.Observable
11814  * Provides AJAX-style update for Element object.<br><br>
11815  * Usage:<br>
11816  * <pre><code>
11817  * // Get it from a Roo.Element object
11818  * var el = Roo.get("foo");
11819  * var mgr = el.getUpdateManager();
11820  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11821  * ...
11822  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11823  * <br>
11824  * // or directly (returns the same UpdateManager instance)
11825  * var mgr = new Roo.UpdateManager("myElementId");
11826  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11827  * mgr.on("update", myFcnNeedsToKnow);
11828  * <br>
11829    // short handed call directly from the element object
11830    Roo.get("foo").load({
11831         url: "bar.php",
11832         scripts:true,
11833         params: "for=bar",
11834         text: "Loading Foo..."
11835    });
11836  * </code></pre>
11837  * @constructor
11838  * Create new UpdateManager directly.
11839  * @param {String/HTMLElement/Roo.Element} el The element to update
11840  * @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).
11841  */
11842 Roo.UpdateManager = function(el, forceNew){
11843     el = Roo.get(el);
11844     if(!forceNew && el.updateManager){
11845         return el.updateManager;
11846     }
11847     /**
11848      * The Element object
11849      * @type Roo.Element
11850      */
11851     this.el = el;
11852     /**
11853      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11854      * @type String
11855      */
11856     this.defaultUrl = null;
11857
11858     this.addEvents({
11859         /**
11860          * @event beforeupdate
11861          * Fired before an update is made, return false from your handler and the update is cancelled.
11862          * @param {Roo.Element} el
11863          * @param {String/Object/Function} url
11864          * @param {String/Object} params
11865          */
11866         "beforeupdate": true,
11867         /**
11868          * @event update
11869          * Fired after successful update is made.
11870          * @param {Roo.Element} el
11871          * @param {Object} oResponseObject The response Object
11872          */
11873         "update": true,
11874         /**
11875          * @event failure
11876          * Fired on update failure.
11877          * @param {Roo.Element} el
11878          * @param {Object} oResponseObject The response Object
11879          */
11880         "failure": true
11881     });
11882     var d = Roo.UpdateManager.defaults;
11883     /**
11884      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11885      * @type String
11886      */
11887     this.sslBlankUrl = d.sslBlankUrl;
11888     /**
11889      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11890      * @type Boolean
11891      */
11892     this.disableCaching = d.disableCaching;
11893     /**
11894      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11895      * @type String
11896      */
11897     this.indicatorText = d.indicatorText;
11898     /**
11899      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11900      * @type String
11901      */
11902     this.showLoadIndicator = d.showLoadIndicator;
11903     /**
11904      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11905      * @type Number
11906      */
11907     this.timeout = d.timeout;
11908
11909     /**
11910      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11911      * @type Boolean
11912      */
11913     this.loadScripts = d.loadScripts;
11914
11915     /**
11916      * Transaction object of current executing transaction
11917      */
11918     this.transaction = null;
11919
11920     /**
11921      * @private
11922      */
11923     this.autoRefreshProcId = null;
11924     /**
11925      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11926      * @type Function
11927      */
11928     this.refreshDelegate = this.refresh.createDelegate(this);
11929     /**
11930      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11931      * @type Function
11932      */
11933     this.updateDelegate = this.update.createDelegate(this);
11934     /**
11935      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11936      * @type Function
11937      */
11938     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11939     /**
11940      * @private
11941      */
11942     this.successDelegate = this.processSuccess.createDelegate(this);
11943     /**
11944      * @private
11945      */
11946     this.failureDelegate = this.processFailure.createDelegate(this);
11947
11948     if(!this.renderer){
11949      /**
11950       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11951       */
11952     this.renderer = new Roo.UpdateManager.BasicRenderer();
11953     }
11954     
11955     Roo.UpdateManager.superclass.constructor.call(this);
11956 };
11957
11958 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11959     /**
11960      * Get the Element this UpdateManager is bound to
11961      * @return {Roo.Element} The element
11962      */
11963     getEl : function(){
11964         return this.el;
11965     },
11966     /**
11967      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11968      * @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:
11969 <pre><code>
11970 um.update({<br/>
11971     url: "your-url.php",<br/>
11972     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11973     callback: yourFunction,<br/>
11974     scope: yourObject, //(optional scope)  <br/>
11975     discardUrl: false, <br/>
11976     nocache: false,<br/>
11977     text: "Loading...",<br/>
11978     timeout: 30,<br/>
11979     scripts: false<br/>
11980 });
11981 </code></pre>
11982      * The only required property is url. The optional properties nocache, text and scripts
11983      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11984      * @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}
11985      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11986      * @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.
11987      */
11988     update : function(url, params, callback, discardUrl){
11989         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11990             var method = this.method,
11991                 cfg;
11992             if(typeof url == "object"){ // must be config object
11993                 cfg = url;
11994                 url = cfg.url;
11995                 params = params || cfg.params;
11996                 callback = callback || cfg.callback;
11997                 discardUrl = discardUrl || cfg.discardUrl;
11998                 if(callback && cfg.scope){
11999                     callback = callback.createDelegate(cfg.scope);
12000                 }
12001                 if(typeof cfg.method != "undefined"){method = cfg.method;};
12002                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12003                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12004                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12005                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12006             }
12007             this.showLoading();
12008             if(!discardUrl){
12009                 this.defaultUrl = url;
12010             }
12011             if(typeof url == "function"){
12012                 url = url.call(this);
12013             }
12014
12015             method = method || (params ? "POST" : "GET");
12016             if(method == "GET"){
12017                 url = this.prepareUrl(url);
12018             }
12019
12020             var o = Roo.apply(cfg ||{}, {
12021                 url : url,
12022                 params: params,
12023                 success: this.successDelegate,
12024                 failure: this.failureDelegate,
12025                 callback: undefined,
12026                 timeout: (this.timeout*1000),
12027                 argument: {"url": url, "form": null, "callback": callback, "params": params}
12028             });
12029             Roo.log("updated manager called with timeout of " + o.timeout);
12030             this.transaction = Roo.Ajax.request(o);
12031         }
12032     },
12033
12034     /**
12035      * 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.
12036      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12037      * @param {String/HTMLElement} form The form Id or form element
12038      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12039      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12040      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12041      */
12042     formUpdate : function(form, url, reset, callback){
12043         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12044             if(typeof url == "function"){
12045                 url = url.call(this);
12046             }
12047             form = Roo.getDom(form);
12048             this.transaction = Roo.Ajax.request({
12049                 form: form,
12050                 url:url,
12051                 success: this.successDelegate,
12052                 failure: this.failureDelegate,
12053                 timeout: (this.timeout*1000),
12054                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12055             });
12056             this.showLoading.defer(1, this);
12057         }
12058     },
12059
12060     /**
12061      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12062      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12063      */
12064     refresh : function(callback){
12065         if(this.defaultUrl == null){
12066             return;
12067         }
12068         this.update(this.defaultUrl, null, callback, true);
12069     },
12070
12071     /**
12072      * Set this element to auto refresh.
12073      * @param {Number} interval How often to update (in seconds).
12074      * @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)
12075      * @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}
12076      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12077      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12078      */
12079     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12080         if(refreshNow){
12081             this.update(url || this.defaultUrl, params, callback, true);
12082         }
12083         if(this.autoRefreshProcId){
12084             clearInterval(this.autoRefreshProcId);
12085         }
12086         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12087     },
12088
12089     /**
12090      * Stop auto refresh on this element.
12091      */
12092      stopAutoRefresh : function(){
12093         if(this.autoRefreshProcId){
12094             clearInterval(this.autoRefreshProcId);
12095             delete this.autoRefreshProcId;
12096         }
12097     },
12098
12099     isAutoRefreshing : function(){
12100        return this.autoRefreshProcId ? true : false;
12101     },
12102     /**
12103      * Called to update the element to "Loading" state. Override to perform custom action.
12104      */
12105     showLoading : function(){
12106         if(this.showLoadIndicator){
12107             this.el.update(this.indicatorText);
12108         }
12109     },
12110
12111     /**
12112      * Adds unique parameter to query string if disableCaching = true
12113      * @private
12114      */
12115     prepareUrl : function(url){
12116         if(this.disableCaching){
12117             var append = "_dc=" + (new Date().getTime());
12118             if(url.indexOf("?") !== -1){
12119                 url += "&" + append;
12120             }else{
12121                 url += "?" + append;
12122             }
12123         }
12124         return url;
12125     },
12126
12127     /**
12128      * @private
12129      */
12130     processSuccess : function(response){
12131         this.transaction = null;
12132         if(response.argument.form && response.argument.reset){
12133             try{ // put in try/catch since some older FF releases had problems with this
12134                 response.argument.form.reset();
12135             }catch(e){}
12136         }
12137         if(this.loadScripts){
12138             this.renderer.render(this.el, response, this,
12139                 this.updateComplete.createDelegate(this, [response]));
12140         }else{
12141             this.renderer.render(this.el, response, this);
12142             this.updateComplete(response);
12143         }
12144     },
12145
12146     updateComplete : function(response){
12147         this.fireEvent("update", this.el, response);
12148         if(typeof response.argument.callback == "function"){
12149             response.argument.callback(this.el, true, response);
12150         }
12151     },
12152
12153     /**
12154      * @private
12155      */
12156     processFailure : function(response){
12157         this.transaction = null;
12158         this.fireEvent("failure", this.el, response);
12159         if(typeof response.argument.callback == "function"){
12160             response.argument.callback(this.el, false, response);
12161         }
12162     },
12163
12164     /**
12165      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12166      * @param {Object} renderer The object implementing the render() method
12167      */
12168     setRenderer : function(renderer){
12169         this.renderer = renderer;
12170     },
12171
12172     getRenderer : function(){
12173        return this.renderer;
12174     },
12175
12176     /**
12177      * Set the defaultUrl used for updates
12178      * @param {String/Function} defaultUrl The url or a function to call to get the url
12179      */
12180     setDefaultUrl : function(defaultUrl){
12181         this.defaultUrl = defaultUrl;
12182     },
12183
12184     /**
12185      * Aborts the executing transaction
12186      */
12187     abort : function(){
12188         if(this.transaction){
12189             Roo.Ajax.abort(this.transaction);
12190         }
12191     },
12192
12193     /**
12194      * Returns true if an update is in progress
12195      * @return {Boolean}
12196      */
12197     isUpdating : function(){
12198         if(this.transaction){
12199             return Roo.Ajax.isLoading(this.transaction);
12200         }
12201         return false;
12202     }
12203 });
12204
12205 /**
12206  * @class Roo.UpdateManager.defaults
12207  * @static (not really - but it helps the doc tool)
12208  * The defaults collection enables customizing the default properties of UpdateManager
12209  */
12210    Roo.UpdateManager.defaults = {
12211        /**
12212          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12213          * @type Number
12214          */
12215          timeout : 30,
12216
12217          /**
12218          * True to process scripts by default (Defaults to false).
12219          * @type Boolean
12220          */
12221         loadScripts : false,
12222
12223         /**
12224         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12225         * @type String
12226         */
12227         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12228         /**
12229          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12230          * @type Boolean
12231          */
12232         disableCaching : false,
12233         /**
12234          * Whether to show indicatorText when loading (Defaults to true).
12235          * @type Boolean
12236          */
12237         showLoadIndicator : true,
12238         /**
12239          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12240          * @type String
12241          */
12242         indicatorText : '<div class="loading-indicator">Loading...</div>'
12243    };
12244
12245 /**
12246  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12247  *Usage:
12248  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12249  * @param {String/HTMLElement/Roo.Element} el The element to update
12250  * @param {String} url The url
12251  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12252  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12253  * @static
12254  * @deprecated
12255  * @member Roo.UpdateManager
12256  */
12257 Roo.UpdateManager.updateElement = function(el, url, params, options){
12258     var um = Roo.get(el, true).getUpdateManager();
12259     Roo.apply(um, options);
12260     um.update(url, params, options ? options.callback : null);
12261 };
12262 // alias for backwards compat
12263 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12264 /**
12265  * @class Roo.UpdateManager.BasicRenderer
12266  * Default Content renderer. Updates the elements innerHTML with the responseText.
12267  */
12268 Roo.UpdateManager.BasicRenderer = function(){};
12269
12270 Roo.UpdateManager.BasicRenderer.prototype = {
12271     /**
12272      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12273      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12274      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12275      * @param {Roo.Element} el The element being rendered
12276      * @param {Object} response The YUI Connect response object
12277      * @param {UpdateManager} updateManager The calling update manager
12278      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12279      */
12280      render : function(el, response, updateManager, callback){
12281         el.update(response.responseText, updateManager.loadScripts, callback);
12282     }
12283 };
12284 /*
12285  * Based on:
12286  * Roo JS
12287  * (c)) Alan Knowles
12288  * Licence : LGPL
12289  */
12290
12291
12292 /**
12293  * @class Roo.DomTemplate
12294  * @extends Roo.Template
12295  * An effort at a dom based template engine..
12296  *
12297  * Similar to XTemplate, except it uses dom parsing to create the template..
12298  *
12299  * Supported features:
12300  *
12301  *  Tags:
12302
12303 <pre><code>
12304       {a_variable} - output encoded.
12305       {a_variable.format:("Y-m-d")} - call a method on the variable
12306       {a_variable:raw} - unencoded output
12307       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12308       {a_variable:this.method_on_template(...)} - call a method on the template object.
12309  
12310 </code></pre>
12311  *  The tpl tag:
12312 <pre><code>
12313         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12314         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12315         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12316         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12317   
12318 </code></pre>
12319  *      
12320  */
12321 Roo.DomTemplate = function()
12322 {
12323      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12324      if (this.html) {
12325         this.compile();
12326      }
12327 };
12328
12329
12330 Roo.extend(Roo.DomTemplate, Roo.Template, {
12331     /**
12332      * id counter for sub templates.
12333      */
12334     id : 0,
12335     /**
12336      * flag to indicate if dom parser is inside a pre,
12337      * it will strip whitespace if not.
12338      */
12339     inPre : false,
12340     
12341     /**
12342      * The various sub templates
12343      */
12344     tpls : false,
12345     
12346     
12347     
12348     /**
12349      *
12350      * basic tag replacing syntax
12351      * WORD:WORD()
12352      *
12353      * // you can fake an object call by doing this
12354      *  x.t:(test,tesT) 
12355      * 
12356      */
12357     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12358     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12359     
12360     iterChild : function (node, method) {
12361         
12362         var oldPre = this.inPre;
12363         if (node.tagName == 'PRE') {
12364             this.inPre = true;
12365         }
12366         for( var i = 0; i < node.childNodes.length; i++) {
12367             method.call(this, node.childNodes[i]);
12368         }
12369         this.inPre = oldPre;
12370     },
12371     
12372     
12373     
12374     /**
12375      * compile the template
12376      *
12377      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12378      *
12379      */
12380     compile: function()
12381     {
12382         var s = this.html;
12383         
12384         // covert the html into DOM...
12385         var doc = false;
12386         var div =false;
12387         try {
12388             doc = document.implementation.createHTMLDocument("");
12389             doc.documentElement.innerHTML =   this.html  ;
12390             div = doc.documentElement;
12391         } catch (e) {
12392             // old IE... - nasty -- it causes all sorts of issues.. with
12393             // images getting pulled from server..
12394             div = document.createElement('div');
12395             div.innerHTML = this.html;
12396         }
12397         //doc.documentElement.innerHTML = htmlBody
12398          
12399         
12400         
12401         this.tpls = [];
12402         var _t = this;
12403         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12404         
12405         var tpls = this.tpls;
12406         
12407         // create a top level template from the snippet..
12408         
12409         //Roo.log(div.innerHTML);
12410         
12411         var tpl = {
12412             uid : 'master',
12413             id : this.id++,
12414             attr : false,
12415             value : false,
12416             body : div.innerHTML,
12417             
12418             forCall : false,
12419             execCall : false,
12420             dom : div,
12421             isTop : true
12422             
12423         };
12424         tpls.unshift(tpl);
12425         
12426         
12427         // compile them...
12428         this.tpls = [];
12429         Roo.each(tpls, function(tp){
12430             this.compileTpl(tp);
12431             this.tpls[tp.id] = tp;
12432         }, this);
12433         
12434         this.master = tpls[0];
12435         return this;
12436         
12437         
12438     },
12439     
12440     compileNode : function(node, istop) {
12441         // test for
12442         //Roo.log(node);
12443         
12444         
12445         // skip anything not a tag..
12446         if (node.nodeType != 1) {
12447             if (node.nodeType == 3 && !this.inPre) {
12448                 // reduce white space..
12449                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12450                 
12451             }
12452             return;
12453         }
12454         
12455         var tpl = {
12456             uid : false,
12457             id : false,
12458             attr : false,
12459             value : false,
12460             body : '',
12461             
12462             forCall : false,
12463             execCall : false,
12464             dom : false,
12465             isTop : istop
12466             
12467             
12468         };
12469         
12470         
12471         switch(true) {
12472             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12473             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12474             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12475             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12476             // no default..
12477         }
12478         
12479         
12480         if (!tpl.attr) {
12481             // just itterate children..
12482             this.iterChild(node,this.compileNode);
12483             return;
12484         }
12485         tpl.uid = this.id++;
12486         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12487         node.removeAttribute('roo-'+ tpl.attr);
12488         if (tpl.attr != 'name') {
12489             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12490             node.parentNode.replaceChild(placeholder,  node);
12491         } else {
12492             
12493             var placeholder =  document.createElement('span');
12494             placeholder.className = 'roo-tpl-' + tpl.value;
12495             node.parentNode.replaceChild(placeholder,  node);
12496         }
12497         
12498         // parent now sees '{domtplXXXX}
12499         this.iterChild(node,this.compileNode);
12500         
12501         // we should now have node body...
12502         var div = document.createElement('div');
12503         div.appendChild(node);
12504         tpl.dom = node;
12505         // this has the unfortunate side effect of converting tagged attributes
12506         // eg. href="{...}" into %7C...%7D
12507         // this has been fixed by searching for those combo's although it's a bit hacky..
12508         
12509         
12510         tpl.body = div.innerHTML;
12511         
12512         
12513          
12514         tpl.id = tpl.uid;
12515         switch(tpl.attr) {
12516             case 'for' :
12517                 switch (tpl.value) {
12518                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12519                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12520                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12521                 }
12522                 break;
12523             
12524             case 'exec':
12525                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12526                 break;
12527             
12528             case 'if':     
12529                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12530                 break;
12531             
12532             case 'name':
12533                 tpl.id  = tpl.value; // replace non characters???
12534                 break;
12535             
12536         }
12537         
12538         
12539         this.tpls.push(tpl);
12540         
12541         
12542         
12543     },
12544     
12545     
12546     
12547     
12548     /**
12549      * Compile a segment of the template into a 'sub-template'
12550      *
12551      * 
12552      * 
12553      *
12554      */
12555     compileTpl : function(tpl)
12556     {
12557         var fm = Roo.util.Format;
12558         var useF = this.disableFormats !== true;
12559         
12560         var sep = Roo.isGecko ? "+\n" : ",\n";
12561         
12562         var undef = function(str) {
12563             Roo.debug && Roo.log("Property not found :"  + str);
12564             return '';
12565         };
12566           
12567         //Roo.log(tpl.body);
12568         
12569         
12570         
12571         var fn = function(m, lbrace, name, format, args)
12572         {
12573             //Roo.log("ARGS");
12574             //Roo.log(arguments);
12575             args = args ? args.replace(/\\'/g,"'") : args;
12576             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12577             if (typeof(format) == 'undefined') {
12578                 format =  'htmlEncode'; 
12579             }
12580             if (format == 'raw' ) {
12581                 format = false;
12582             }
12583             
12584             if(name.substr(0, 6) == 'domtpl'){
12585                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12586             }
12587             
12588             // build an array of options to determine if value is undefined..
12589             
12590             // basically get 'xxxx.yyyy' then do
12591             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12592             //    (function () { Roo.log("Property not found"); return ''; })() :
12593             //    ......
12594             
12595             var udef_ar = [];
12596             var lookfor = '';
12597             Roo.each(name.split('.'), function(st) {
12598                 lookfor += (lookfor.length ? '.': '') + st;
12599                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12600             });
12601             
12602             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12603             
12604             
12605             if(format && useF){
12606                 
12607                 args = args ? ',' + args : "";
12608                  
12609                 if(format.substr(0, 5) != "this."){
12610                     format = "fm." + format + '(';
12611                 }else{
12612                     format = 'this.call("'+ format.substr(5) + '", ';
12613                     args = ", values";
12614                 }
12615                 
12616                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12617             }
12618              
12619             if (args && args.length) {
12620                 // called with xxyx.yuu:(test,test)
12621                 // change to ()
12622                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12623             }
12624             // raw.. - :raw modifier..
12625             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12626             
12627         };
12628         var body;
12629         // branched to use + in gecko and [].join() in others
12630         if(Roo.isGecko){
12631             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12632                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12633                     "';};};";
12634         }else{
12635             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12636             body.push(tpl.body.replace(/(\r\n|\n)/g,
12637                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12638             body.push("'].join('');};};");
12639             body = body.join('');
12640         }
12641         
12642         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12643        
12644         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12645         eval(body);
12646         
12647         return this;
12648     },
12649      
12650     /**
12651      * same as applyTemplate, except it's done to one of the subTemplates
12652      * when using named templates, you can do:
12653      *
12654      * var str = pl.applySubTemplate('your-name', values);
12655      *
12656      * 
12657      * @param {Number} id of the template
12658      * @param {Object} values to apply to template
12659      * @param {Object} parent (normaly the instance of this object)
12660      */
12661     applySubTemplate : function(id, values, parent)
12662     {
12663         
12664         
12665         var t = this.tpls[id];
12666         
12667         
12668         try { 
12669             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12670                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12671                 return '';
12672             }
12673         } catch(e) {
12674             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12675             Roo.log(values);
12676           
12677             return '';
12678         }
12679         try { 
12680             
12681             if(t.execCall && t.execCall.call(this, values, parent)){
12682                 return '';
12683             }
12684         } catch(e) {
12685             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12686             Roo.log(values);
12687             return '';
12688         }
12689         
12690         try {
12691             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12692             parent = t.target ? values : parent;
12693             if(t.forCall && vs instanceof Array){
12694                 var buf = [];
12695                 for(var i = 0, len = vs.length; i < len; i++){
12696                     try {
12697                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12698                     } catch (e) {
12699                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12700                         Roo.log(e.body);
12701                         //Roo.log(t.compiled);
12702                         Roo.log(vs[i]);
12703                     }   
12704                 }
12705                 return buf.join('');
12706             }
12707         } catch (e) {
12708             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12709             Roo.log(values);
12710             return '';
12711         }
12712         try {
12713             return t.compiled.call(this, vs, parent);
12714         } catch (e) {
12715             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12716             Roo.log(e.body);
12717             //Roo.log(t.compiled);
12718             Roo.log(values);
12719             return '';
12720         }
12721     },
12722
12723    
12724
12725     applyTemplate : function(values){
12726         return this.master.compiled.call(this, values, {});
12727         //var s = this.subs;
12728     },
12729
12730     apply : function(){
12731         return this.applyTemplate.apply(this, arguments);
12732     }
12733
12734  });
12735
12736 Roo.DomTemplate.from = function(el){
12737     el = Roo.getDom(el);
12738     return new Roo.Domtemplate(el.value || el.innerHTML);
12739 };/*
12740  * Based on:
12741  * Ext JS Library 1.1.1
12742  * Copyright(c) 2006-2007, Ext JS, LLC.
12743  *
12744  * Originally Released Under LGPL - original licence link has changed is not relivant.
12745  *
12746  * Fork - LGPL
12747  * <script type="text/javascript">
12748  */
12749
12750 /**
12751  * @class Roo.util.DelayedTask
12752  * Provides a convenient method of performing setTimeout where a new
12753  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12754  * You can use this class to buffer
12755  * the keypress events for a certain number of milliseconds, and perform only if they stop
12756  * for that amount of time.
12757  * @constructor The parameters to this constructor serve as defaults and are not required.
12758  * @param {Function} fn (optional) The default function to timeout
12759  * @param {Object} scope (optional) The default scope of that timeout
12760  * @param {Array} args (optional) The default Array of arguments
12761  */
12762 Roo.util.DelayedTask = function(fn, scope, args){
12763     var id = null, d, t;
12764
12765     var call = function(){
12766         var now = new Date().getTime();
12767         if(now - t >= d){
12768             clearInterval(id);
12769             id = null;
12770             fn.apply(scope, args || []);
12771         }
12772     };
12773     /**
12774      * Cancels any pending timeout and queues a new one
12775      * @param {Number} delay The milliseconds to delay
12776      * @param {Function} newFn (optional) Overrides function passed to constructor
12777      * @param {Object} newScope (optional) Overrides scope passed to constructor
12778      * @param {Array} newArgs (optional) Overrides args passed to constructor
12779      */
12780     this.delay = function(delay, newFn, newScope, newArgs){
12781         if(id && delay != d){
12782             this.cancel();
12783         }
12784         d = delay;
12785         t = new Date().getTime();
12786         fn = newFn || fn;
12787         scope = newScope || scope;
12788         args = newArgs || args;
12789         if(!id){
12790             id = setInterval(call, d);
12791         }
12792     };
12793
12794     /**
12795      * Cancel the last queued timeout
12796      */
12797     this.cancel = function(){
12798         if(id){
12799             clearInterval(id);
12800             id = null;
12801         }
12802     };
12803 };/*
12804  * Based on:
12805  * Ext JS Library 1.1.1
12806  * Copyright(c) 2006-2007, Ext JS, LLC.
12807  *
12808  * Originally Released Under LGPL - original licence link has changed is not relivant.
12809  *
12810  * Fork - LGPL
12811  * <script type="text/javascript">
12812  */
12813  
12814  
12815 Roo.util.TaskRunner = function(interval){
12816     interval = interval || 10;
12817     var tasks = [], removeQueue = [];
12818     var id = 0;
12819     var running = false;
12820
12821     var stopThread = function(){
12822         running = false;
12823         clearInterval(id);
12824         id = 0;
12825     };
12826
12827     var startThread = function(){
12828         if(!running){
12829             running = true;
12830             id = setInterval(runTasks, interval);
12831         }
12832     };
12833
12834     var removeTask = function(task){
12835         removeQueue.push(task);
12836         if(task.onStop){
12837             task.onStop();
12838         }
12839     };
12840
12841     var runTasks = function(){
12842         if(removeQueue.length > 0){
12843             for(var i = 0, len = removeQueue.length; i < len; i++){
12844                 tasks.remove(removeQueue[i]);
12845             }
12846             removeQueue = [];
12847             if(tasks.length < 1){
12848                 stopThread();
12849                 return;
12850             }
12851         }
12852         var now = new Date().getTime();
12853         for(var i = 0, len = tasks.length; i < len; ++i){
12854             var t = tasks[i];
12855             var itime = now - t.taskRunTime;
12856             if(t.interval <= itime){
12857                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12858                 t.taskRunTime = now;
12859                 if(rt === false || t.taskRunCount === t.repeat){
12860                     removeTask(t);
12861                     return;
12862                 }
12863             }
12864             if(t.duration && t.duration <= (now - t.taskStartTime)){
12865                 removeTask(t);
12866             }
12867         }
12868     };
12869
12870     /**
12871      * Queues a new task.
12872      * @param {Object} task
12873      */
12874     this.start = function(task){
12875         tasks.push(task);
12876         task.taskStartTime = new Date().getTime();
12877         task.taskRunTime = 0;
12878         task.taskRunCount = 0;
12879         startThread();
12880         return task;
12881     };
12882
12883     this.stop = function(task){
12884         removeTask(task);
12885         return task;
12886     };
12887
12888     this.stopAll = function(){
12889         stopThread();
12890         for(var i = 0, len = tasks.length; i < len; i++){
12891             if(tasks[i].onStop){
12892                 tasks[i].onStop();
12893             }
12894         }
12895         tasks = [];
12896         removeQueue = [];
12897     };
12898 };
12899
12900 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12901  * Based on:
12902  * Ext JS Library 1.1.1
12903  * Copyright(c) 2006-2007, Ext JS, LLC.
12904  *
12905  * Originally Released Under LGPL - original licence link has changed is not relivant.
12906  *
12907  * Fork - LGPL
12908  * <script type="text/javascript">
12909  */
12910
12911  
12912 /**
12913  * @class Roo.util.MixedCollection
12914  * @extends Roo.util.Observable
12915  * A Collection class that maintains both numeric indexes and keys and exposes events.
12916  * @constructor
12917  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12918  * collection (defaults to false)
12919  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12920  * and return the key value for that item.  This is used when available to look up the key on items that
12921  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12922  * equivalent to providing an implementation for the {@link #getKey} method.
12923  */
12924 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12925     this.items = [];
12926     this.map = {};
12927     this.keys = [];
12928     this.length = 0;
12929     this.addEvents({
12930         /**
12931          * @event clear
12932          * Fires when the collection is cleared.
12933          */
12934         "clear" : true,
12935         /**
12936          * @event add
12937          * Fires when an item is added to the collection.
12938          * @param {Number} index The index at which the item was added.
12939          * @param {Object} o The item added.
12940          * @param {String} key The key associated with the added item.
12941          */
12942         "add" : true,
12943         /**
12944          * @event replace
12945          * Fires when an item is replaced in the collection.
12946          * @param {String} key he key associated with the new added.
12947          * @param {Object} old The item being replaced.
12948          * @param {Object} new The new item.
12949          */
12950         "replace" : true,
12951         /**
12952          * @event remove
12953          * Fires when an item is removed from the collection.
12954          * @param {Object} o The item being removed.
12955          * @param {String} key (optional) The key associated with the removed item.
12956          */
12957         "remove" : true,
12958         "sort" : true
12959     });
12960     this.allowFunctions = allowFunctions === true;
12961     if(keyFn){
12962         this.getKey = keyFn;
12963     }
12964     Roo.util.MixedCollection.superclass.constructor.call(this);
12965 };
12966
12967 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12968     allowFunctions : false,
12969     
12970 /**
12971  * Adds an item to the collection.
12972  * @param {String} key The key to associate with the item
12973  * @param {Object} o The item to add.
12974  * @return {Object} The item added.
12975  */
12976     add : function(key, o){
12977         if(arguments.length == 1){
12978             o = arguments[0];
12979             key = this.getKey(o);
12980         }
12981         if(typeof key == "undefined" || key === null){
12982             this.length++;
12983             this.items.push(o);
12984             this.keys.push(null);
12985         }else{
12986             var old = this.map[key];
12987             if(old){
12988                 return this.replace(key, o);
12989             }
12990             this.length++;
12991             this.items.push(o);
12992             this.map[key] = o;
12993             this.keys.push(key);
12994         }
12995         this.fireEvent("add", this.length-1, o, key);
12996         return o;
12997     },
12998        
12999 /**
13000   * MixedCollection has a generic way to fetch keys if you implement getKey.
13001 <pre><code>
13002 // normal way
13003 var mc = new Roo.util.MixedCollection();
13004 mc.add(someEl.dom.id, someEl);
13005 mc.add(otherEl.dom.id, otherEl);
13006 //and so on
13007
13008 // using getKey
13009 var mc = new Roo.util.MixedCollection();
13010 mc.getKey = function(el){
13011    return el.dom.id;
13012 };
13013 mc.add(someEl);
13014 mc.add(otherEl);
13015
13016 // or via the constructor
13017 var mc = new Roo.util.MixedCollection(false, function(el){
13018    return el.dom.id;
13019 });
13020 mc.add(someEl);
13021 mc.add(otherEl);
13022 </code></pre>
13023  * @param o {Object} The item for which to find the key.
13024  * @return {Object} The key for the passed item.
13025  */
13026     getKey : function(o){
13027          return o.id; 
13028     },
13029    
13030 /**
13031  * Replaces an item in the collection.
13032  * @param {String} key The key associated with the item to replace, or the item to replace.
13033  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13034  * @return {Object}  The new item.
13035  */
13036     replace : function(key, o){
13037         if(arguments.length == 1){
13038             o = arguments[0];
13039             key = this.getKey(o);
13040         }
13041         var old = this.item(key);
13042         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13043              return this.add(key, o);
13044         }
13045         var index = this.indexOfKey(key);
13046         this.items[index] = o;
13047         this.map[key] = o;
13048         this.fireEvent("replace", key, old, o);
13049         return o;
13050     },
13051    
13052 /**
13053  * Adds all elements of an Array or an Object to the collection.
13054  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13055  * an Array of values, each of which are added to the collection.
13056  */
13057     addAll : function(objs){
13058         if(arguments.length > 1 || objs instanceof Array){
13059             var args = arguments.length > 1 ? arguments : objs;
13060             for(var i = 0, len = args.length; i < len; i++){
13061                 this.add(args[i]);
13062             }
13063         }else{
13064             for(var key in objs){
13065                 if(this.allowFunctions || typeof objs[key] != "function"){
13066                     this.add(key, objs[key]);
13067                 }
13068             }
13069         }
13070     },
13071    
13072 /**
13073  * Executes the specified function once for every item in the collection, passing each
13074  * item as the first and only parameter. returning false from the function will stop the iteration.
13075  * @param {Function} fn The function to execute for each item.
13076  * @param {Object} scope (optional) The scope in which to execute the function.
13077  */
13078     each : function(fn, scope){
13079         var items = [].concat(this.items); // each safe for removal
13080         for(var i = 0, len = items.length; i < len; i++){
13081             if(fn.call(scope || items[i], items[i], i, len) === false){
13082                 break;
13083             }
13084         }
13085     },
13086    
13087 /**
13088  * Executes the specified function once for every key in the collection, passing each
13089  * key, and its associated item as the first two parameters.
13090  * @param {Function} fn The function to execute for each item.
13091  * @param {Object} scope (optional) The scope in which to execute the function.
13092  */
13093     eachKey : function(fn, scope){
13094         for(var i = 0, len = this.keys.length; i < len; i++){
13095             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13096         }
13097     },
13098    
13099 /**
13100  * Returns the first item in the collection which elicits a true return value from the
13101  * passed selection function.
13102  * @param {Function} fn The selection function to execute for each item.
13103  * @param {Object} scope (optional) The scope in which to execute the function.
13104  * @return {Object} The first item in the collection which returned true from the selection function.
13105  */
13106     find : function(fn, scope){
13107         for(var i = 0, len = this.items.length; i < len; i++){
13108             if(fn.call(scope || window, this.items[i], this.keys[i])){
13109                 return this.items[i];
13110             }
13111         }
13112         return null;
13113     },
13114    
13115 /**
13116  * Inserts an item at the specified index in the collection.
13117  * @param {Number} index The index to insert the item at.
13118  * @param {String} key The key to associate with the new item, or the item itself.
13119  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13120  * @return {Object} The item inserted.
13121  */
13122     insert : function(index, key, o){
13123         if(arguments.length == 2){
13124             o = arguments[1];
13125             key = this.getKey(o);
13126         }
13127         if(index >= this.length){
13128             return this.add(key, o);
13129         }
13130         this.length++;
13131         this.items.splice(index, 0, o);
13132         if(typeof key != "undefined" && key != null){
13133             this.map[key] = o;
13134         }
13135         this.keys.splice(index, 0, key);
13136         this.fireEvent("add", index, o, key);
13137         return o;
13138     },
13139    
13140 /**
13141  * Removed an item from the collection.
13142  * @param {Object} o The item to remove.
13143  * @return {Object} The item removed.
13144  */
13145     remove : function(o){
13146         return this.removeAt(this.indexOf(o));
13147     },
13148    
13149 /**
13150  * Remove an item from a specified index in the collection.
13151  * @param {Number} index The index within the collection of the item to remove.
13152  */
13153     removeAt : function(index){
13154         if(index < this.length && index >= 0){
13155             this.length--;
13156             var o = this.items[index];
13157             this.items.splice(index, 1);
13158             var key = this.keys[index];
13159             if(typeof key != "undefined"){
13160                 delete this.map[key];
13161             }
13162             this.keys.splice(index, 1);
13163             this.fireEvent("remove", o, key);
13164         }
13165     },
13166    
13167 /**
13168  * Removed an item associated with the passed key fom the collection.
13169  * @param {String} key The key of the item to remove.
13170  */
13171     removeKey : function(key){
13172         return this.removeAt(this.indexOfKey(key));
13173     },
13174    
13175 /**
13176  * Returns the number of items in the collection.
13177  * @return {Number} the number of items in the collection.
13178  */
13179     getCount : function(){
13180         return this.length; 
13181     },
13182    
13183 /**
13184  * Returns index within the collection of the passed Object.
13185  * @param {Object} o The item to find the index of.
13186  * @return {Number} index of the item.
13187  */
13188     indexOf : function(o){
13189         if(!this.items.indexOf){
13190             for(var i = 0, len = this.items.length; i < len; i++){
13191                 if(this.items[i] == o) {
13192                     return i;
13193                 }
13194             }
13195             return -1;
13196         }else{
13197             return this.items.indexOf(o);
13198         }
13199     },
13200    
13201 /**
13202  * Returns index within the collection of the passed key.
13203  * @param {String} key The key to find the index of.
13204  * @return {Number} index of the key.
13205  */
13206     indexOfKey : function(key){
13207         if(!this.keys.indexOf){
13208             for(var i = 0, len = this.keys.length; i < len; i++){
13209                 if(this.keys[i] == key) {
13210                     return i;
13211                 }
13212             }
13213             return -1;
13214         }else{
13215             return this.keys.indexOf(key);
13216         }
13217     },
13218    
13219 /**
13220  * Returns the item associated with the passed key OR index. Key has priority over index.
13221  * @param {String/Number} key The key or index of the item.
13222  * @return {Object} The item associated with the passed key.
13223  */
13224     item : function(key){
13225         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13226         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13227     },
13228     
13229 /**
13230  * Returns the item at the specified index.
13231  * @param {Number} index The index of the item.
13232  * @return {Object}
13233  */
13234     itemAt : function(index){
13235         return this.items[index];
13236     },
13237     
13238 /**
13239  * Returns the item associated with the passed key.
13240  * @param {String/Number} key The key of the item.
13241  * @return {Object} The item associated with the passed key.
13242  */
13243     key : function(key){
13244         return this.map[key];
13245     },
13246    
13247 /**
13248  * Returns true if the collection contains the passed Object as an item.
13249  * @param {Object} o  The Object to look for in the collection.
13250  * @return {Boolean} True if the collection contains the Object as an item.
13251  */
13252     contains : function(o){
13253         return this.indexOf(o) != -1;
13254     },
13255    
13256 /**
13257  * Returns true if the collection contains the passed Object as a key.
13258  * @param {String} key The key to look for in the collection.
13259  * @return {Boolean} True if the collection contains the Object as a key.
13260  */
13261     containsKey : function(key){
13262         return typeof this.map[key] != "undefined";
13263     },
13264    
13265 /**
13266  * Removes all items from the collection.
13267  */
13268     clear : function(){
13269         this.length = 0;
13270         this.items = [];
13271         this.keys = [];
13272         this.map = {};
13273         this.fireEvent("clear");
13274     },
13275    
13276 /**
13277  * Returns the first item in the collection.
13278  * @return {Object} the first item in the collection..
13279  */
13280     first : function(){
13281         return this.items[0]; 
13282     },
13283    
13284 /**
13285  * Returns the last item in the collection.
13286  * @return {Object} the last item in the collection..
13287  */
13288     last : function(){
13289         return this.items[this.length-1];   
13290     },
13291     
13292     _sort : function(property, dir, fn){
13293         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13294         fn = fn || function(a, b){
13295             return a-b;
13296         };
13297         var c = [], k = this.keys, items = this.items;
13298         for(var i = 0, len = items.length; i < len; i++){
13299             c[c.length] = {key: k[i], value: items[i], index: i};
13300         }
13301         c.sort(function(a, b){
13302             var v = fn(a[property], b[property]) * dsc;
13303             if(v == 0){
13304                 v = (a.index < b.index ? -1 : 1);
13305             }
13306             return v;
13307         });
13308         for(var i = 0, len = c.length; i < len; i++){
13309             items[i] = c[i].value;
13310             k[i] = c[i].key;
13311         }
13312         this.fireEvent("sort", this);
13313     },
13314     
13315     /**
13316      * Sorts this collection with the passed comparison function
13317      * @param {String} direction (optional) "ASC" or "DESC"
13318      * @param {Function} fn (optional) comparison function
13319      */
13320     sort : function(dir, fn){
13321         this._sort("value", dir, fn);
13322     },
13323     
13324     /**
13325      * Sorts this collection by keys
13326      * @param {String} direction (optional) "ASC" or "DESC"
13327      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13328      */
13329     keySort : function(dir, fn){
13330         this._sort("key", dir, fn || function(a, b){
13331             return String(a).toUpperCase()-String(b).toUpperCase();
13332         });
13333     },
13334     
13335     /**
13336      * Returns a range of items in this collection
13337      * @param {Number} startIndex (optional) defaults to 0
13338      * @param {Number} endIndex (optional) default to the last item
13339      * @return {Array} An array of items
13340      */
13341     getRange : function(start, end){
13342         var items = this.items;
13343         if(items.length < 1){
13344             return [];
13345         }
13346         start = start || 0;
13347         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13348         var r = [];
13349         if(start <= end){
13350             for(var i = start; i <= end; i++) {
13351                     r[r.length] = items[i];
13352             }
13353         }else{
13354             for(var i = start; i >= end; i--) {
13355                     r[r.length] = items[i];
13356             }
13357         }
13358         return r;
13359     },
13360         
13361     /**
13362      * Filter the <i>objects</i> in this collection by a specific property. 
13363      * Returns a new collection that has been filtered.
13364      * @param {String} property A property on your objects
13365      * @param {String/RegExp} value Either string that the property values 
13366      * should start with or a RegExp to test against the property
13367      * @return {MixedCollection} The new filtered collection
13368      */
13369     filter : function(property, value){
13370         if(!value.exec){ // not a regex
13371             value = String(value);
13372             if(value.length == 0){
13373                 return this.clone();
13374             }
13375             value = new RegExp("^" + Roo.escapeRe(value), "i");
13376         }
13377         return this.filterBy(function(o){
13378             return o && value.test(o[property]);
13379         });
13380         },
13381     
13382     /**
13383      * Filter by a function. * Returns a new collection that has been filtered.
13384      * The passed function will be called with each 
13385      * object in the collection. If the function returns true, the value is included 
13386      * otherwise it is filtered.
13387      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13388      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13389      * @return {MixedCollection} The new filtered collection
13390      */
13391     filterBy : function(fn, scope){
13392         var r = new Roo.util.MixedCollection();
13393         r.getKey = this.getKey;
13394         var k = this.keys, it = this.items;
13395         for(var i = 0, len = it.length; i < len; i++){
13396             if(fn.call(scope||this, it[i], k[i])){
13397                                 r.add(k[i], it[i]);
13398                         }
13399         }
13400         return r;
13401     },
13402     
13403     /**
13404      * Creates a duplicate of this collection
13405      * @return {MixedCollection}
13406      */
13407     clone : function(){
13408         var r = new Roo.util.MixedCollection();
13409         var k = this.keys, it = this.items;
13410         for(var i = 0, len = it.length; i < len; i++){
13411             r.add(k[i], it[i]);
13412         }
13413         r.getKey = this.getKey;
13414         return r;
13415     }
13416 });
13417 /**
13418  * Returns the item associated with the passed key or index.
13419  * @method
13420  * @param {String/Number} key The key or index of the item.
13421  * @return {Object} The item associated with the passed key.
13422  */
13423 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13424  * Based on:
13425  * Ext JS Library 1.1.1
13426  * Copyright(c) 2006-2007, Ext JS, LLC.
13427  *
13428  * Originally Released Under LGPL - original licence link has changed is not relivant.
13429  *
13430  * Fork - LGPL
13431  * <script type="text/javascript">
13432  */
13433 /**
13434  * @class Roo.util.JSON
13435  * Modified version of Douglas Crockford"s json.js that doesn"t
13436  * mess with the Object prototype 
13437  * http://www.json.org/js.html
13438  * @singleton
13439  */
13440 Roo.util.JSON = new (function(){
13441     var useHasOwn = {}.hasOwnProperty ? true : false;
13442     
13443     // crashes Safari in some instances
13444     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13445     
13446     var pad = function(n) {
13447         return n < 10 ? "0" + n : n;
13448     };
13449     
13450     var m = {
13451         "\b": '\\b',
13452         "\t": '\\t',
13453         "\n": '\\n',
13454         "\f": '\\f',
13455         "\r": '\\r',
13456         '"' : '\\"',
13457         "\\": '\\\\'
13458     };
13459
13460     var encodeString = function(s){
13461         if (/["\\\x00-\x1f]/.test(s)) {
13462             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13463                 var c = m[b];
13464                 if(c){
13465                     return c;
13466                 }
13467                 c = b.charCodeAt();
13468                 return "\\u00" +
13469                     Math.floor(c / 16).toString(16) +
13470                     (c % 16).toString(16);
13471             }) + '"';
13472         }
13473         return '"' + s + '"';
13474     };
13475     
13476     var encodeArray = function(o){
13477         var a = ["["], b, i, l = o.length, v;
13478             for (i = 0; i < l; i += 1) {
13479                 v = o[i];
13480                 switch (typeof v) {
13481                     case "undefined":
13482                     case "function":
13483                     case "unknown":
13484                         break;
13485                     default:
13486                         if (b) {
13487                             a.push(',');
13488                         }
13489                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13490                         b = true;
13491                 }
13492             }
13493             a.push("]");
13494             return a.join("");
13495     };
13496     
13497     var encodeDate = function(o){
13498         return '"' + o.getFullYear() + "-" +
13499                 pad(o.getMonth() + 1) + "-" +
13500                 pad(o.getDate()) + "T" +
13501                 pad(o.getHours()) + ":" +
13502                 pad(o.getMinutes()) + ":" +
13503                 pad(o.getSeconds()) + '"';
13504     };
13505     
13506     /**
13507      * Encodes an Object, Array or other value
13508      * @param {Mixed} o The variable to encode
13509      * @return {String} The JSON string
13510      */
13511     this.encode = function(o)
13512     {
13513         // should this be extended to fully wrap stringify..
13514         
13515         if(typeof o == "undefined" || o === null){
13516             return "null";
13517         }else if(o instanceof Array){
13518             return encodeArray(o);
13519         }else if(o instanceof Date){
13520             return encodeDate(o);
13521         }else if(typeof o == "string"){
13522             return encodeString(o);
13523         }else if(typeof o == "number"){
13524             return isFinite(o) ? String(o) : "null";
13525         }else if(typeof o == "boolean"){
13526             return String(o);
13527         }else {
13528             var a = ["{"], b, i, v;
13529             for (i in o) {
13530                 if(!useHasOwn || o.hasOwnProperty(i)) {
13531                     v = o[i];
13532                     switch (typeof v) {
13533                     case "undefined":
13534                     case "function":
13535                     case "unknown":
13536                         break;
13537                     default:
13538                         if(b){
13539                             a.push(',');
13540                         }
13541                         a.push(this.encode(i), ":",
13542                                 v === null ? "null" : this.encode(v));
13543                         b = true;
13544                     }
13545                 }
13546             }
13547             a.push("}");
13548             return a.join("");
13549         }
13550     };
13551     
13552     /**
13553      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13554      * @param {String} json The JSON string
13555      * @return {Object} The resulting object
13556      */
13557     this.decode = function(json){
13558         
13559         return  /** eval:var:json */ eval("(" + json + ')');
13560     };
13561 })();
13562 /** 
13563  * Shorthand for {@link Roo.util.JSON#encode}
13564  * @member Roo encode 
13565  * @method */
13566 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13567 /** 
13568  * Shorthand for {@link Roo.util.JSON#decode}
13569  * @member Roo decode 
13570  * @method */
13571 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13572 /*
13573  * Based on:
13574  * Ext JS Library 1.1.1
13575  * Copyright(c) 2006-2007, Ext JS, LLC.
13576  *
13577  * Originally Released Under LGPL - original licence link has changed is not relivant.
13578  *
13579  * Fork - LGPL
13580  * <script type="text/javascript">
13581  */
13582  
13583 /**
13584  * @class Roo.util.Format
13585  * Reusable data formatting functions
13586  * @singleton
13587  */
13588 Roo.util.Format = function(){
13589     var trimRe = /^\s+|\s+$/g;
13590     return {
13591         /**
13592          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13593          * @param {String} value The string to truncate
13594          * @param {Number} length The maximum length to allow before truncating
13595          * @return {String} The converted text
13596          */
13597         ellipsis : function(value, len){
13598             if(value && value.length > len){
13599                 return value.substr(0, len-3)+"...";
13600             }
13601             return value;
13602         },
13603
13604         /**
13605          * Checks a reference and converts it to empty string if it is undefined
13606          * @param {Mixed} value Reference to check
13607          * @return {Mixed} Empty string if converted, otherwise the original value
13608          */
13609         undef : function(value){
13610             return typeof value != "undefined" ? value : "";
13611         },
13612
13613         /**
13614          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13615          * @param {String} value The string to encode
13616          * @return {String} The encoded text
13617          */
13618         htmlEncode : function(value){
13619             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13620         },
13621
13622         /**
13623          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13624          * @param {String} value The string to decode
13625          * @return {String} The decoded text
13626          */
13627         htmlDecode : function(value){
13628             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13629         },
13630
13631         /**
13632          * Trims any whitespace from either side of a string
13633          * @param {String} value The text to trim
13634          * @return {String} The trimmed text
13635          */
13636         trim : function(value){
13637             return String(value).replace(trimRe, "");
13638         },
13639
13640         /**
13641          * Returns a substring from within an original string
13642          * @param {String} value The original text
13643          * @param {Number} start The start index of the substring
13644          * @param {Number} length The length of the substring
13645          * @return {String} The substring
13646          */
13647         substr : function(value, start, length){
13648             return String(value).substr(start, length);
13649         },
13650
13651         /**
13652          * Converts a string to all lower case letters
13653          * @param {String} value The text to convert
13654          * @return {String} The converted text
13655          */
13656         lowercase : function(value){
13657             return String(value).toLowerCase();
13658         },
13659
13660         /**
13661          * Converts a string to all upper case letters
13662          * @param {String} value The text to convert
13663          * @return {String} The converted text
13664          */
13665         uppercase : function(value){
13666             return String(value).toUpperCase();
13667         },
13668
13669         /**
13670          * Converts the first character only of a string to upper case
13671          * @param {String} value The text to convert
13672          * @return {String} The converted text
13673          */
13674         capitalize : function(value){
13675             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13676         },
13677
13678         // private
13679         call : function(value, fn){
13680             if(arguments.length > 2){
13681                 var args = Array.prototype.slice.call(arguments, 2);
13682                 args.unshift(value);
13683                  
13684                 return /** eval:var:value */  eval(fn).apply(window, args);
13685             }else{
13686                 /** eval:var:value */
13687                 return /** eval:var:value */ eval(fn).call(window, value);
13688             }
13689         },
13690
13691        
13692         /**
13693          * safer version of Math.toFixed..??/
13694          * @param {Number/String} value The numeric value to format
13695          * @param {Number/String} value Decimal places 
13696          * @return {String} The formatted currency string
13697          */
13698         toFixed : function(v, n)
13699         {
13700             // why not use to fixed - precision is buggered???
13701             if (!n) {
13702                 return Math.round(v-0);
13703             }
13704             var fact = Math.pow(10,n+1);
13705             v = (Math.round((v-0)*fact))/fact;
13706             var z = (''+fact).substring(2);
13707             if (v == Math.floor(v)) {
13708                 return Math.floor(v) + '.' + z;
13709             }
13710             
13711             // now just padd decimals..
13712             var ps = String(v).split('.');
13713             var fd = (ps[1] + z);
13714             var r = fd.substring(0,n); 
13715             var rm = fd.substring(n); 
13716             if (rm < 5) {
13717                 return ps[0] + '.' + r;
13718             }
13719             r*=1; // turn it into a number;
13720             r++;
13721             if (String(r).length != n) {
13722                 ps[0]*=1;
13723                 ps[0]++;
13724                 r = String(r).substring(1); // chop the end off.
13725             }
13726             
13727             return ps[0] + '.' + r;
13728              
13729         },
13730         
13731         /**
13732          * Format a number as US currency
13733          * @param {Number/String} value The numeric value to format
13734          * @return {String} The formatted currency string
13735          */
13736         usMoney : function(v){
13737             return '$' + Roo.util.Format.number(v);
13738         },
13739         
13740         /**
13741          * Format a number
13742          * eventually this should probably emulate php's number_format
13743          * @param {Number/String} value The numeric value to format
13744          * @param {Number} decimals number of decimal places
13745          * @return {String} The formatted currency string
13746          */
13747         number : function(v,decimals)
13748         {
13749             // multiply and round.
13750             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13751             var mul = Math.pow(10, decimals);
13752             var zero = String(mul).substring(1);
13753             v = (Math.round((v-0)*mul))/mul;
13754             
13755             // if it's '0' number.. then
13756             
13757             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13758             v = String(v);
13759             var ps = v.split('.');
13760             var whole = ps[0];
13761             
13762             
13763             var r = /(\d+)(\d{3})/;
13764             // add comma's
13765             while (r.test(whole)) {
13766                 whole = whole.replace(r, '$1' + ',' + '$2');
13767             }
13768             
13769             
13770             var sub = ps[1] ?
13771                     // has decimals..
13772                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13773                     // does not have decimals
13774                     (decimals ? ('.' + zero) : '');
13775             
13776             
13777             return whole + sub ;
13778         },
13779         
13780         /**
13781          * Parse a value into a formatted date using the specified format pattern.
13782          * @param {Mixed} value The value to format
13783          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13784          * @return {String} The formatted date string
13785          */
13786         date : function(v, format){
13787             if(!v){
13788                 return "";
13789             }
13790             if(!(v instanceof Date)){
13791                 v = new Date(Date.parse(v));
13792             }
13793             return v.dateFormat(format || Roo.util.Format.defaults.date);
13794         },
13795
13796         /**
13797          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13798          * @param {String} format Any valid date format string
13799          * @return {Function} The date formatting function
13800          */
13801         dateRenderer : function(format){
13802             return function(v){
13803                 return Roo.util.Format.date(v, format);  
13804             };
13805         },
13806
13807         // private
13808         stripTagsRE : /<\/?[^>]+>/gi,
13809         
13810         /**
13811          * Strips all HTML tags
13812          * @param {Mixed} value The text from which to strip tags
13813          * @return {String} The stripped text
13814          */
13815         stripTags : function(v){
13816             return !v ? v : String(v).replace(this.stripTagsRE, "");
13817         }
13818     };
13819 }();
13820 Roo.util.Format.defaults = {
13821     date : 'd/M/Y'
13822 };/*
13823  * Based on:
13824  * Ext JS Library 1.1.1
13825  * Copyright(c) 2006-2007, Ext JS, LLC.
13826  *
13827  * Originally Released Under LGPL - original licence link has changed is not relivant.
13828  *
13829  * Fork - LGPL
13830  * <script type="text/javascript">
13831  */
13832
13833
13834  
13835
13836 /**
13837  * @class Roo.MasterTemplate
13838  * @extends Roo.Template
13839  * Provides a template that can have child templates. The syntax is:
13840 <pre><code>
13841 var t = new Roo.MasterTemplate(
13842         '&lt;select name="{name}"&gt;',
13843                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13844         '&lt;/select&gt;'
13845 );
13846 t.add('options', {value: 'foo', text: 'bar'});
13847 // or you can add multiple child elements in one shot
13848 t.addAll('options', [
13849     {value: 'foo', text: 'bar'},
13850     {value: 'foo2', text: 'bar2'},
13851     {value: 'foo3', text: 'bar3'}
13852 ]);
13853 // then append, applying the master template values
13854 t.append('my-form', {name: 'my-select'});
13855 </code></pre>
13856 * A name attribute for the child template is not required if you have only one child
13857 * template or you want to refer to them by index.
13858  */
13859 Roo.MasterTemplate = function(){
13860     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13861     this.originalHtml = this.html;
13862     var st = {};
13863     var m, re = this.subTemplateRe;
13864     re.lastIndex = 0;
13865     var subIndex = 0;
13866     while(m = re.exec(this.html)){
13867         var name = m[1], content = m[2];
13868         st[subIndex] = {
13869             name: name,
13870             index: subIndex,
13871             buffer: [],
13872             tpl : new Roo.Template(content)
13873         };
13874         if(name){
13875             st[name] = st[subIndex];
13876         }
13877         st[subIndex].tpl.compile();
13878         st[subIndex].tpl.call = this.call.createDelegate(this);
13879         subIndex++;
13880     }
13881     this.subCount = subIndex;
13882     this.subs = st;
13883 };
13884 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13885     /**
13886     * The regular expression used to match sub templates
13887     * @type RegExp
13888     * @property
13889     */
13890     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13891
13892     /**
13893      * Applies the passed values to a child template.
13894      * @param {String/Number} name (optional) The name or index of the child template
13895      * @param {Array/Object} values The values to be applied to the template
13896      * @return {MasterTemplate} this
13897      */
13898      add : function(name, values){
13899         if(arguments.length == 1){
13900             values = arguments[0];
13901             name = 0;
13902         }
13903         var s = this.subs[name];
13904         s.buffer[s.buffer.length] = s.tpl.apply(values);
13905         return this;
13906     },
13907
13908     /**
13909      * Applies all the passed values to a child template.
13910      * @param {String/Number} name (optional) The name or index of the child template
13911      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13912      * @param {Boolean} reset (optional) True to reset the template first
13913      * @return {MasterTemplate} this
13914      */
13915     fill : function(name, values, reset){
13916         var a = arguments;
13917         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13918             values = a[0];
13919             name = 0;
13920             reset = a[1];
13921         }
13922         if(reset){
13923             this.reset();
13924         }
13925         for(var i = 0, len = values.length; i < len; i++){
13926             this.add(name, values[i]);
13927         }
13928         return this;
13929     },
13930
13931     /**
13932      * Resets the template for reuse
13933      * @return {MasterTemplate} this
13934      */
13935      reset : function(){
13936         var s = this.subs;
13937         for(var i = 0; i < this.subCount; i++){
13938             s[i].buffer = [];
13939         }
13940         return this;
13941     },
13942
13943     applyTemplate : function(values){
13944         var s = this.subs;
13945         var replaceIndex = -1;
13946         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13947             return s[++replaceIndex].buffer.join("");
13948         });
13949         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13950     },
13951
13952     apply : function(){
13953         return this.applyTemplate.apply(this, arguments);
13954     },
13955
13956     compile : function(){return this;}
13957 });
13958
13959 /**
13960  * Alias for fill().
13961  * @method
13962  */
13963 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13964  /**
13965  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13966  * var tpl = Roo.MasterTemplate.from('element-id');
13967  * @param {String/HTMLElement} el
13968  * @param {Object} config
13969  * @static
13970  */
13971 Roo.MasterTemplate.from = function(el, config){
13972     el = Roo.getDom(el);
13973     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13974 };/*
13975  * Based on:
13976  * Ext JS Library 1.1.1
13977  * Copyright(c) 2006-2007, Ext JS, LLC.
13978  *
13979  * Originally Released Under LGPL - original licence link has changed is not relivant.
13980  *
13981  * Fork - LGPL
13982  * <script type="text/javascript">
13983  */
13984
13985  
13986 /**
13987  * @class Roo.util.CSS
13988  * Utility class for manipulating CSS rules
13989  * @singleton
13990  */
13991 Roo.util.CSS = function(){
13992         var rules = null;
13993         var doc = document;
13994
13995     var camelRe = /(-[a-z])/gi;
13996     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13997
13998    return {
13999    /**
14000     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
14001     * tag and appended to the HEAD of the document.
14002     * @param {String|Object} cssText The text containing the css rules
14003     * @param {String} id An id to add to the stylesheet for later removal
14004     * @return {StyleSheet}
14005     */
14006     createStyleSheet : function(cssText, id){
14007         var ss;
14008         var head = doc.getElementsByTagName("head")[0];
14009         var nrules = doc.createElement("style");
14010         nrules.setAttribute("type", "text/css");
14011         if(id){
14012             nrules.setAttribute("id", id);
14013         }
14014         if (typeof(cssText) != 'string') {
14015             // support object maps..
14016             // not sure if this a good idea.. 
14017             // perhaps it should be merged with the general css handling
14018             // and handle js style props.
14019             var cssTextNew = [];
14020             for(var n in cssText) {
14021                 var citems = [];
14022                 for(var k in cssText[n]) {
14023                     citems.push( k + ' : ' +cssText[n][k] + ';' );
14024                 }
14025                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14026                 
14027             }
14028             cssText = cssTextNew.join("\n");
14029             
14030         }
14031        
14032        
14033        if(Roo.isIE){
14034            head.appendChild(nrules);
14035            ss = nrules.styleSheet;
14036            ss.cssText = cssText;
14037        }else{
14038            try{
14039                 nrules.appendChild(doc.createTextNode(cssText));
14040            }catch(e){
14041                nrules.cssText = cssText; 
14042            }
14043            head.appendChild(nrules);
14044            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14045        }
14046        this.cacheStyleSheet(ss);
14047        return ss;
14048    },
14049
14050    /**
14051     * Removes a style or link tag by id
14052     * @param {String} id The id of the tag
14053     */
14054    removeStyleSheet : function(id){
14055        var existing = doc.getElementById(id);
14056        if(existing){
14057            existing.parentNode.removeChild(existing);
14058        }
14059    },
14060
14061    /**
14062     * Dynamically swaps an existing stylesheet reference for a new one
14063     * @param {String} id The id of an existing link tag to remove
14064     * @param {String} url The href of the new stylesheet to include
14065     */
14066    swapStyleSheet : function(id, url){
14067        this.removeStyleSheet(id);
14068        var ss = doc.createElement("link");
14069        ss.setAttribute("rel", "stylesheet");
14070        ss.setAttribute("type", "text/css");
14071        ss.setAttribute("id", id);
14072        ss.setAttribute("href", url);
14073        doc.getElementsByTagName("head")[0].appendChild(ss);
14074    },
14075    
14076    /**
14077     * Refresh the rule cache if you have dynamically added stylesheets
14078     * @return {Object} An object (hash) of rules indexed by selector
14079     */
14080    refreshCache : function(){
14081        return this.getRules(true);
14082    },
14083
14084    // private
14085    cacheStyleSheet : function(stylesheet){
14086        if(!rules){
14087            rules = {};
14088        }
14089        try{// try catch for cross domain access issue
14090            var ssRules = stylesheet.cssRules || stylesheet.rules;
14091            for(var j = ssRules.length-1; j >= 0; --j){
14092                rules[ssRules[j].selectorText] = ssRules[j];
14093            }
14094        }catch(e){}
14095    },
14096    
14097    /**
14098     * Gets all css rules for the document
14099     * @param {Boolean} refreshCache true to refresh the internal cache
14100     * @return {Object} An object (hash) of rules indexed by selector
14101     */
14102    getRules : function(refreshCache){
14103                 if(rules == null || refreshCache){
14104                         rules = {};
14105                         var ds = doc.styleSheets;
14106                         for(var i =0, len = ds.length; i < len; i++){
14107                             try{
14108                         this.cacheStyleSheet(ds[i]);
14109                     }catch(e){} 
14110                 }
14111                 }
14112                 return rules;
14113         },
14114         
14115         /**
14116     * Gets an an individual CSS rule by selector(s)
14117     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14118     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14119     * @return {CSSRule} The CSS rule or null if one is not found
14120     */
14121    getRule : function(selector, refreshCache){
14122                 var rs = this.getRules(refreshCache);
14123                 if(!(selector instanceof Array)){
14124                     return rs[selector];
14125                 }
14126                 for(var i = 0; i < selector.length; i++){
14127                         if(rs[selector[i]]){
14128                                 return rs[selector[i]];
14129                         }
14130                 }
14131                 return null;
14132         },
14133         
14134         
14135         /**
14136     * Updates a rule property
14137     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14138     * @param {String} property The css property
14139     * @param {String} value The new value for the property
14140     * @return {Boolean} true If a rule was found and updated
14141     */
14142    updateRule : function(selector, property, value){
14143                 if(!(selector instanceof Array)){
14144                         var rule = this.getRule(selector);
14145                         if(rule){
14146                                 rule.style[property.replace(camelRe, camelFn)] = value;
14147                                 return true;
14148                         }
14149                 }else{
14150                         for(var i = 0; i < selector.length; i++){
14151                                 if(this.updateRule(selector[i], property, value)){
14152                                         return true;
14153                                 }
14154                         }
14155                 }
14156                 return false;
14157         }
14158    };   
14159 }();/*
14160  * Based on:
14161  * Ext JS Library 1.1.1
14162  * Copyright(c) 2006-2007, Ext JS, LLC.
14163  *
14164  * Originally Released Under LGPL - original licence link has changed is not relivant.
14165  *
14166  * Fork - LGPL
14167  * <script type="text/javascript">
14168  */
14169
14170  
14171
14172 /**
14173  * @class Roo.util.ClickRepeater
14174  * @extends Roo.util.Observable
14175  * 
14176  * A wrapper class which can be applied to any element. Fires a "click" event while the
14177  * mouse is pressed. The interval between firings may be specified in the config but
14178  * defaults to 10 milliseconds.
14179  * 
14180  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14181  * 
14182  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14183  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14184  * Similar to an autorepeat key delay.
14185  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14186  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14187  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14188  *           "interval" and "delay" are ignored. "immediate" is honored.
14189  * @cfg {Boolean} preventDefault True to prevent the default click event
14190  * @cfg {Boolean} stopDefault True to stop the default click event
14191  * 
14192  * @history
14193  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14194  *     2007-02-02 jvs Renamed to ClickRepeater
14195  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14196  *
14197  *  @constructor
14198  * @param {String/HTMLElement/Element} el The element to listen on
14199  * @param {Object} config
14200  **/
14201 Roo.util.ClickRepeater = function(el, config)
14202 {
14203     this.el = Roo.get(el);
14204     this.el.unselectable();
14205
14206     Roo.apply(this, config);
14207
14208     this.addEvents({
14209     /**
14210      * @event mousedown
14211      * Fires when the mouse button is depressed.
14212      * @param {Roo.util.ClickRepeater} this
14213      */
14214         "mousedown" : true,
14215     /**
14216      * @event click
14217      * Fires on a specified interval during the time the element is pressed.
14218      * @param {Roo.util.ClickRepeater} this
14219      */
14220         "click" : true,
14221     /**
14222      * @event mouseup
14223      * Fires when the mouse key is released.
14224      * @param {Roo.util.ClickRepeater} this
14225      */
14226         "mouseup" : true
14227     });
14228
14229     this.el.on("mousedown", this.handleMouseDown, this);
14230     if(this.preventDefault || this.stopDefault){
14231         this.el.on("click", function(e){
14232             if(this.preventDefault){
14233                 e.preventDefault();
14234             }
14235             if(this.stopDefault){
14236                 e.stopEvent();
14237             }
14238         }, this);
14239     }
14240
14241     // allow inline handler
14242     if(this.handler){
14243         this.on("click", this.handler,  this.scope || this);
14244     }
14245
14246     Roo.util.ClickRepeater.superclass.constructor.call(this);
14247 };
14248
14249 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14250     interval : 20,
14251     delay: 250,
14252     preventDefault : true,
14253     stopDefault : false,
14254     timer : 0,
14255
14256     // private
14257     handleMouseDown : function(){
14258         clearTimeout(this.timer);
14259         this.el.blur();
14260         if(this.pressClass){
14261             this.el.addClass(this.pressClass);
14262         }
14263         this.mousedownTime = new Date();
14264
14265         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14266         this.el.on("mouseout", this.handleMouseOut, this);
14267
14268         this.fireEvent("mousedown", this);
14269         this.fireEvent("click", this);
14270         
14271         this.timer = this.click.defer(this.delay || this.interval, this);
14272     },
14273
14274     // private
14275     click : function(){
14276         this.fireEvent("click", this);
14277         this.timer = this.click.defer(this.getInterval(), this);
14278     },
14279
14280     // private
14281     getInterval: function(){
14282         if(!this.accelerate){
14283             return this.interval;
14284         }
14285         var pressTime = this.mousedownTime.getElapsed();
14286         if(pressTime < 500){
14287             return 400;
14288         }else if(pressTime < 1700){
14289             return 320;
14290         }else if(pressTime < 2600){
14291             return 250;
14292         }else if(pressTime < 3500){
14293             return 180;
14294         }else if(pressTime < 4400){
14295             return 140;
14296         }else if(pressTime < 5300){
14297             return 80;
14298         }else if(pressTime < 6200){
14299             return 50;
14300         }else{
14301             return 10;
14302         }
14303     },
14304
14305     // private
14306     handleMouseOut : function(){
14307         clearTimeout(this.timer);
14308         if(this.pressClass){
14309             this.el.removeClass(this.pressClass);
14310         }
14311         this.el.on("mouseover", this.handleMouseReturn, this);
14312     },
14313
14314     // private
14315     handleMouseReturn : function(){
14316         this.el.un("mouseover", this.handleMouseReturn);
14317         if(this.pressClass){
14318             this.el.addClass(this.pressClass);
14319         }
14320         this.click();
14321     },
14322
14323     // private
14324     handleMouseUp : function(){
14325         clearTimeout(this.timer);
14326         this.el.un("mouseover", this.handleMouseReturn);
14327         this.el.un("mouseout", this.handleMouseOut);
14328         Roo.get(document).un("mouseup", this.handleMouseUp);
14329         this.el.removeClass(this.pressClass);
14330         this.fireEvent("mouseup", this);
14331     }
14332 });/*
14333  * Based on:
14334  * Ext JS Library 1.1.1
14335  * Copyright(c) 2006-2007, Ext JS, LLC.
14336  *
14337  * Originally Released Under LGPL - original licence link has changed is not relivant.
14338  *
14339  * Fork - LGPL
14340  * <script type="text/javascript">
14341  */
14342
14343  
14344 /**
14345  * @class Roo.KeyNav
14346  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14347  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14348  * way to implement custom navigation schemes for any UI component.</p>
14349  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14350  * pageUp, pageDown, del, home, end.  Usage:</p>
14351  <pre><code>
14352 var nav = new Roo.KeyNav("my-element", {
14353     "left" : function(e){
14354         this.moveLeft(e.ctrlKey);
14355     },
14356     "right" : function(e){
14357         this.moveRight(e.ctrlKey);
14358     },
14359     "enter" : function(e){
14360         this.save();
14361     },
14362     scope : this
14363 });
14364 </code></pre>
14365  * @constructor
14366  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14367  * @param {Object} config The config
14368  */
14369 Roo.KeyNav = function(el, config){
14370     this.el = Roo.get(el);
14371     Roo.apply(this, config);
14372     if(!this.disabled){
14373         this.disabled = true;
14374         this.enable();
14375     }
14376 };
14377
14378 Roo.KeyNav.prototype = {
14379     /**
14380      * @cfg {Boolean} disabled
14381      * True to disable this KeyNav instance (defaults to false)
14382      */
14383     disabled : false,
14384     /**
14385      * @cfg {String} defaultEventAction
14386      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14387      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14388      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14389      */
14390     defaultEventAction: "stopEvent",
14391     /**
14392      * @cfg {Boolean} forceKeyDown
14393      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14394      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14395      * handle keydown instead of keypress.
14396      */
14397     forceKeyDown : false,
14398
14399     // private
14400     prepareEvent : function(e){
14401         var k = e.getKey();
14402         var h = this.keyToHandler[k];
14403         //if(h && this[h]){
14404         //    e.stopPropagation();
14405         //}
14406         if(Roo.isSafari && h && k >= 37 && k <= 40){
14407             e.stopEvent();
14408         }
14409     },
14410
14411     // private
14412     relay : function(e){
14413         var k = e.getKey();
14414         var h = this.keyToHandler[k];
14415         if(h && this[h]){
14416             if(this.doRelay(e, this[h], h) !== true){
14417                 e[this.defaultEventAction]();
14418             }
14419         }
14420     },
14421
14422     // private
14423     doRelay : function(e, h, hname){
14424         return h.call(this.scope || this, e);
14425     },
14426
14427     // possible handlers
14428     enter : false,
14429     left : false,
14430     right : false,
14431     up : false,
14432     down : false,
14433     tab : false,
14434     esc : false,
14435     pageUp : false,
14436     pageDown : false,
14437     del : false,
14438     home : false,
14439     end : false,
14440
14441     // quick lookup hash
14442     keyToHandler : {
14443         37 : "left",
14444         39 : "right",
14445         38 : "up",
14446         40 : "down",
14447         33 : "pageUp",
14448         34 : "pageDown",
14449         46 : "del",
14450         36 : "home",
14451         35 : "end",
14452         13 : "enter",
14453         27 : "esc",
14454         9  : "tab"
14455     },
14456
14457         /**
14458          * Enable this KeyNav
14459          */
14460         enable: function(){
14461                 if(this.disabled){
14462             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14463             // the EventObject will normalize Safari automatically
14464             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14465                 this.el.on("keydown", this.relay,  this);
14466             }else{
14467                 this.el.on("keydown", this.prepareEvent,  this);
14468                 this.el.on("keypress", this.relay,  this);
14469             }
14470                     this.disabled = false;
14471                 }
14472         },
14473
14474         /**
14475          * Disable this KeyNav
14476          */
14477         disable: function(){
14478                 if(!this.disabled){
14479                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14480                 this.el.un("keydown", this.relay);
14481             }else{
14482                 this.el.un("keydown", this.prepareEvent);
14483                 this.el.un("keypress", this.relay);
14484             }
14485                     this.disabled = true;
14486                 }
14487         }
14488 };/*
14489  * Based on:
14490  * Ext JS Library 1.1.1
14491  * Copyright(c) 2006-2007, Ext JS, LLC.
14492  *
14493  * Originally Released Under LGPL - original licence link has changed is not relivant.
14494  *
14495  * Fork - LGPL
14496  * <script type="text/javascript">
14497  */
14498
14499  
14500 /**
14501  * @class Roo.KeyMap
14502  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14503  * The constructor accepts the same config object as defined by {@link #addBinding}.
14504  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14505  * combination it will call the function with this signature (if the match is a multi-key
14506  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14507  * A KeyMap can also handle a string representation of keys.<br />
14508  * Usage:
14509  <pre><code>
14510 // map one key by key code
14511 var map = new Roo.KeyMap("my-element", {
14512     key: 13, // or Roo.EventObject.ENTER
14513     fn: myHandler,
14514     scope: myObject
14515 });
14516
14517 // map multiple keys to one action by string
14518 var map = new Roo.KeyMap("my-element", {
14519     key: "a\r\n\t",
14520     fn: myHandler,
14521     scope: myObject
14522 });
14523
14524 // map multiple keys to multiple actions by strings and array of codes
14525 var map = new Roo.KeyMap("my-element", [
14526     {
14527         key: [10,13],
14528         fn: function(){ alert("Return was pressed"); }
14529     }, {
14530         key: "abc",
14531         fn: function(){ alert('a, b or c was pressed'); }
14532     }, {
14533         key: "\t",
14534         ctrl:true,
14535         shift:true,
14536         fn: function(){ alert('Control + shift + tab was pressed.'); }
14537     }
14538 ]);
14539 </code></pre>
14540  * <b>Note: A KeyMap starts enabled</b>
14541  * @constructor
14542  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14543  * @param {Object} config The config (see {@link #addBinding})
14544  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14545  */
14546 Roo.KeyMap = function(el, config, eventName){
14547     this.el  = Roo.get(el);
14548     this.eventName = eventName || "keydown";
14549     this.bindings = [];
14550     if(config){
14551         this.addBinding(config);
14552     }
14553     this.enable();
14554 };
14555
14556 Roo.KeyMap.prototype = {
14557     /**
14558      * True to stop the event from bubbling and prevent the default browser action if the
14559      * key was handled by the KeyMap (defaults to false)
14560      * @type Boolean
14561      */
14562     stopEvent : false,
14563
14564     /**
14565      * Add a new binding to this KeyMap. The following config object properties are supported:
14566      * <pre>
14567 Property    Type             Description
14568 ----------  ---------------  ----------------------------------------------------------------------
14569 key         String/Array     A single keycode or an array of keycodes to handle
14570 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14571 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14572 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14573 fn          Function         The function to call when KeyMap finds the expected key combination
14574 scope       Object           The scope of the callback function
14575 </pre>
14576      *
14577      * Usage:
14578      * <pre><code>
14579 // Create a KeyMap
14580 var map = new Roo.KeyMap(document, {
14581     key: Roo.EventObject.ENTER,
14582     fn: handleKey,
14583     scope: this
14584 });
14585
14586 //Add a new binding to the existing KeyMap later
14587 map.addBinding({
14588     key: 'abc',
14589     shift: true,
14590     fn: handleKey,
14591     scope: this
14592 });
14593 </code></pre>
14594      * @param {Object/Array} config A single KeyMap config or an array of configs
14595      */
14596         addBinding : function(config){
14597         if(config instanceof Array){
14598             for(var i = 0, len = config.length; i < len; i++){
14599                 this.addBinding(config[i]);
14600             }
14601             return;
14602         }
14603         var keyCode = config.key,
14604             shift = config.shift, 
14605             ctrl = config.ctrl, 
14606             alt = config.alt,
14607             fn = config.fn,
14608             scope = config.scope;
14609         if(typeof keyCode == "string"){
14610             var ks = [];
14611             var keyString = keyCode.toUpperCase();
14612             for(var j = 0, len = keyString.length; j < len; j++){
14613                 ks.push(keyString.charCodeAt(j));
14614             }
14615             keyCode = ks;
14616         }
14617         var keyArray = keyCode instanceof Array;
14618         var handler = function(e){
14619             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14620                 var k = e.getKey();
14621                 if(keyArray){
14622                     for(var i = 0, len = keyCode.length; i < len; i++){
14623                         if(keyCode[i] == k){
14624                           if(this.stopEvent){
14625                               e.stopEvent();
14626                           }
14627                           fn.call(scope || window, k, e);
14628                           return;
14629                         }
14630                     }
14631                 }else{
14632                     if(k == keyCode){
14633                         if(this.stopEvent){
14634                            e.stopEvent();
14635                         }
14636                         fn.call(scope || window, k, e);
14637                     }
14638                 }
14639             }
14640         };
14641         this.bindings.push(handler);  
14642         },
14643
14644     /**
14645      * Shorthand for adding a single key listener
14646      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14647      * following options:
14648      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14649      * @param {Function} fn The function to call
14650      * @param {Object} scope (optional) The scope of the function
14651      */
14652     on : function(key, fn, scope){
14653         var keyCode, shift, ctrl, alt;
14654         if(typeof key == "object" && !(key instanceof Array)){
14655             keyCode = key.key;
14656             shift = key.shift;
14657             ctrl = key.ctrl;
14658             alt = key.alt;
14659         }else{
14660             keyCode = key;
14661         }
14662         this.addBinding({
14663             key: keyCode,
14664             shift: shift,
14665             ctrl: ctrl,
14666             alt: alt,
14667             fn: fn,
14668             scope: scope
14669         })
14670     },
14671
14672     // private
14673     handleKeyDown : function(e){
14674             if(this.enabled){ //just in case
14675             var b = this.bindings;
14676             for(var i = 0, len = b.length; i < len; i++){
14677                 b[i].call(this, e);
14678             }
14679             }
14680         },
14681         
14682         /**
14683          * Returns true if this KeyMap is enabled
14684          * @return {Boolean} 
14685          */
14686         isEnabled : function(){
14687             return this.enabled;  
14688         },
14689         
14690         /**
14691          * Enables this KeyMap
14692          */
14693         enable: function(){
14694                 if(!this.enabled){
14695                     this.el.on(this.eventName, this.handleKeyDown, this);
14696                     this.enabled = true;
14697                 }
14698         },
14699
14700         /**
14701          * Disable this KeyMap
14702          */
14703         disable: function(){
14704                 if(this.enabled){
14705                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14706                     this.enabled = false;
14707                 }
14708         }
14709 };/*
14710  * Based on:
14711  * Ext JS Library 1.1.1
14712  * Copyright(c) 2006-2007, Ext JS, LLC.
14713  *
14714  * Originally Released Under LGPL - original licence link has changed is not relivant.
14715  *
14716  * Fork - LGPL
14717  * <script type="text/javascript">
14718  */
14719
14720  
14721 /**
14722  * @class Roo.util.TextMetrics
14723  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14724  * wide, in pixels, a given block of text will be.
14725  * @singleton
14726  */
14727 Roo.util.TextMetrics = function(){
14728     var shared;
14729     return {
14730         /**
14731          * Measures the size of the specified text
14732          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14733          * that can affect the size of the rendered text
14734          * @param {String} text The text to measure
14735          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14736          * in order to accurately measure the text height
14737          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14738          */
14739         measure : function(el, text, fixedWidth){
14740             if(!shared){
14741                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14742             }
14743             shared.bind(el);
14744             shared.setFixedWidth(fixedWidth || 'auto');
14745             return shared.getSize(text);
14746         },
14747
14748         /**
14749          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14750          * the overhead of multiple calls to initialize the style properties on each measurement.
14751          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14752          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14753          * in order to accurately measure the text height
14754          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14755          */
14756         createInstance : function(el, fixedWidth){
14757             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14758         }
14759     };
14760 }();
14761
14762  
14763
14764 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14765     var ml = new Roo.Element(document.createElement('div'));
14766     document.body.appendChild(ml.dom);
14767     ml.position('absolute');
14768     ml.setLeftTop(-1000, -1000);
14769     ml.hide();
14770
14771     if(fixedWidth){
14772         ml.setWidth(fixedWidth);
14773     }
14774      
14775     var instance = {
14776         /**
14777          * Returns the size of the specified text based on the internal element's style and width properties
14778          * @memberOf Roo.util.TextMetrics.Instance#
14779          * @param {String} text The text to measure
14780          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14781          */
14782         getSize : function(text){
14783             ml.update(text);
14784             var s = ml.getSize();
14785             ml.update('');
14786             return s;
14787         },
14788
14789         /**
14790          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14791          * that can affect the size of the rendered text
14792          * @memberOf Roo.util.TextMetrics.Instance#
14793          * @param {String/HTMLElement} el The element, dom node or id
14794          */
14795         bind : function(el){
14796             ml.setStyle(
14797                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14798             );
14799         },
14800
14801         /**
14802          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14803          * to set a fixed width in order to accurately measure the text height.
14804          * @memberOf Roo.util.TextMetrics.Instance#
14805          * @param {Number} width The width to set on the element
14806          */
14807         setFixedWidth : function(width){
14808             ml.setWidth(width);
14809         },
14810
14811         /**
14812          * Returns the measured width of the specified text
14813          * @memberOf Roo.util.TextMetrics.Instance#
14814          * @param {String} text The text to measure
14815          * @return {Number} width The width in pixels
14816          */
14817         getWidth : function(text){
14818             ml.dom.style.width = 'auto';
14819             return this.getSize(text).width;
14820         },
14821
14822         /**
14823          * Returns the measured height of the specified text.  For multiline text, be sure to call
14824          * {@link #setFixedWidth} if necessary.
14825          * @memberOf Roo.util.TextMetrics.Instance#
14826          * @param {String} text The text to measure
14827          * @return {Number} height The height in pixels
14828          */
14829         getHeight : function(text){
14830             return this.getSize(text).height;
14831         }
14832     };
14833
14834     instance.bind(bindTo);
14835
14836     return instance;
14837 };
14838
14839 // backwards compat
14840 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14841  * Based on:
14842  * Ext JS Library 1.1.1
14843  * Copyright(c) 2006-2007, Ext JS, LLC.
14844  *
14845  * Originally Released Under LGPL - original licence link has changed is not relivant.
14846  *
14847  * Fork - LGPL
14848  * <script type="text/javascript">
14849  */
14850
14851 /**
14852  * @class Roo.state.Provider
14853  * Abstract base class for state provider implementations. This class provides methods
14854  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14855  * Provider interface.
14856  */
14857 Roo.state.Provider = function(){
14858     /**
14859      * @event statechange
14860      * Fires when a state change occurs.
14861      * @param {Provider} this This state provider
14862      * @param {String} key The state key which was changed
14863      * @param {String} value The encoded value for the state
14864      */
14865     this.addEvents({
14866         "statechange": true
14867     });
14868     this.state = {};
14869     Roo.state.Provider.superclass.constructor.call(this);
14870 };
14871 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14872     /**
14873      * Returns the current value for a key
14874      * @param {String} name The key name
14875      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14876      * @return {Mixed} The state data
14877      */
14878     get : function(name, defaultValue){
14879         return typeof this.state[name] == "undefined" ?
14880             defaultValue : this.state[name];
14881     },
14882     
14883     /**
14884      * Clears a value from the state
14885      * @param {String} name The key name
14886      */
14887     clear : function(name){
14888         delete this.state[name];
14889         this.fireEvent("statechange", this, name, null);
14890     },
14891     
14892     /**
14893      * Sets the value for a key
14894      * @param {String} name The key name
14895      * @param {Mixed} value The value to set
14896      */
14897     set : function(name, value){
14898         this.state[name] = value;
14899         this.fireEvent("statechange", this, name, value);
14900     },
14901     
14902     /**
14903      * Decodes a string previously encoded with {@link #encodeValue}.
14904      * @param {String} value The value to decode
14905      * @return {Mixed} The decoded value
14906      */
14907     decodeValue : function(cookie){
14908         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14909         var matches = re.exec(unescape(cookie));
14910         if(!matches || !matches[1]) {
14911             return; // non state cookie
14912         }
14913         var type = matches[1];
14914         var v = matches[2];
14915         switch(type){
14916             case "n":
14917                 return parseFloat(v);
14918             case "d":
14919                 return new Date(Date.parse(v));
14920             case "b":
14921                 return (v == "1");
14922             case "a":
14923                 var all = [];
14924                 var values = v.split("^");
14925                 for(var i = 0, len = values.length; i < len; i++){
14926                     all.push(this.decodeValue(values[i]));
14927                 }
14928                 return all;
14929            case "o":
14930                 var all = {};
14931                 var values = v.split("^");
14932                 for(var i = 0, len = values.length; i < len; i++){
14933                     var kv = values[i].split("=");
14934                     all[kv[0]] = this.decodeValue(kv[1]);
14935                 }
14936                 return all;
14937            default:
14938                 return v;
14939         }
14940     },
14941     
14942     /**
14943      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14944      * @param {Mixed} value The value to encode
14945      * @return {String} The encoded value
14946      */
14947     encodeValue : function(v){
14948         var enc;
14949         if(typeof v == "number"){
14950             enc = "n:" + v;
14951         }else if(typeof v == "boolean"){
14952             enc = "b:" + (v ? "1" : "0");
14953         }else if(v instanceof Date){
14954             enc = "d:" + v.toGMTString();
14955         }else if(v instanceof Array){
14956             var flat = "";
14957             for(var i = 0, len = v.length; i < len; i++){
14958                 flat += this.encodeValue(v[i]);
14959                 if(i != len-1) {
14960                     flat += "^";
14961                 }
14962             }
14963             enc = "a:" + flat;
14964         }else if(typeof v == "object"){
14965             var flat = "";
14966             for(var key in v){
14967                 if(typeof v[key] != "function"){
14968                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14969                 }
14970             }
14971             enc = "o:" + flat.substring(0, flat.length-1);
14972         }else{
14973             enc = "s:" + v;
14974         }
14975         return escape(enc);        
14976     }
14977 });
14978
14979 /*
14980  * Based on:
14981  * Ext JS Library 1.1.1
14982  * Copyright(c) 2006-2007, Ext JS, LLC.
14983  *
14984  * Originally Released Under LGPL - original licence link has changed is not relivant.
14985  *
14986  * Fork - LGPL
14987  * <script type="text/javascript">
14988  */
14989 /**
14990  * @class Roo.state.Manager
14991  * This is the global state manager. By default all components that are "state aware" check this class
14992  * for state information if you don't pass them a custom state provider. In order for this class
14993  * to be useful, it must be initialized with a provider when your application initializes.
14994  <pre><code>
14995 // in your initialization function
14996 init : function(){
14997    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14998    ...
14999    // supposed you have a {@link Roo.BorderLayout}
15000    var layout = new Roo.BorderLayout(...);
15001    layout.restoreState();
15002    // or a {Roo.BasicDialog}
15003    var dialog = new Roo.BasicDialog(...);
15004    dialog.restoreState();
15005  </code></pre>
15006  * @singleton
15007  */
15008 Roo.state.Manager = function(){
15009     var provider = new Roo.state.Provider();
15010     
15011     return {
15012         /**
15013          * Configures the default state provider for your application
15014          * @param {Provider} stateProvider The state provider to set
15015          */
15016         setProvider : function(stateProvider){
15017             provider = stateProvider;
15018         },
15019         
15020         /**
15021          * Returns the current value for a key
15022          * @param {String} name The key name
15023          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15024          * @return {Mixed} The state data
15025          */
15026         get : function(key, defaultValue){
15027             return provider.get(key, defaultValue);
15028         },
15029         
15030         /**
15031          * Sets the value for a key
15032          * @param {String} name The key name
15033          * @param {Mixed} value The state data
15034          */
15035          set : function(key, value){
15036             provider.set(key, value);
15037         },
15038         
15039         /**
15040          * Clears a value from the state
15041          * @param {String} name The key name
15042          */
15043         clear : function(key){
15044             provider.clear(key);
15045         },
15046         
15047         /**
15048          * Gets the currently configured state provider
15049          * @return {Provider} The state provider
15050          */
15051         getProvider : function(){
15052             return provider;
15053         }
15054     };
15055 }();
15056 /*
15057  * Based on:
15058  * Ext JS Library 1.1.1
15059  * Copyright(c) 2006-2007, Ext JS, LLC.
15060  *
15061  * Originally Released Under LGPL - original licence link has changed is not relivant.
15062  *
15063  * Fork - LGPL
15064  * <script type="text/javascript">
15065  */
15066 /**
15067  * @class Roo.state.CookieProvider
15068  * @extends Roo.state.Provider
15069  * The default Provider implementation which saves state via cookies.
15070  * <br />Usage:
15071  <pre><code>
15072    var cp = new Roo.state.CookieProvider({
15073        path: "/cgi-bin/",
15074        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15075        domain: "roojs.com"
15076    })
15077    Roo.state.Manager.setProvider(cp);
15078  </code></pre>
15079  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15080  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15081  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15082  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15083  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15084  * domain the page is running on including the 'www' like 'www.roojs.com')
15085  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15086  * @constructor
15087  * Create a new CookieProvider
15088  * @param {Object} config The configuration object
15089  */
15090 Roo.state.CookieProvider = function(config){
15091     Roo.state.CookieProvider.superclass.constructor.call(this);
15092     this.path = "/";
15093     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15094     this.domain = null;
15095     this.secure = false;
15096     Roo.apply(this, config);
15097     this.state = this.readCookies();
15098 };
15099
15100 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15101     // private
15102     set : function(name, value){
15103         if(typeof value == "undefined" || value === null){
15104             this.clear(name);
15105             return;
15106         }
15107         this.setCookie(name, value);
15108         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15109     },
15110
15111     // private
15112     clear : function(name){
15113         this.clearCookie(name);
15114         Roo.state.CookieProvider.superclass.clear.call(this, name);
15115     },
15116
15117     // private
15118     readCookies : function(){
15119         var cookies = {};
15120         var c = document.cookie + ";";
15121         var re = /\s?(.*?)=(.*?);/g;
15122         var matches;
15123         while((matches = re.exec(c)) != null){
15124             var name = matches[1];
15125             var value = matches[2];
15126             if(name && name.substring(0,3) == "ys-"){
15127                 cookies[name.substr(3)] = this.decodeValue(value);
15128             }
15129         }
15130         return cookies;
15131     },
15132
15133     // private
15134     setCookie : function(name, value){
15135         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15136            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15137            ((this.path == null) ? "" : ("; path=" + this.path)) +
15138            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15139            ((this.secure == true) ? "; secure" : "");
15140     },
15141
15142     // private
15143     clearCookie : function(name){
15144         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15145            ((this.path == null) ? "" : ("; path=" + this.path)) +
15146            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15147            ((this.secure == true) ? "; secure" : "");
15148     }
15149 });/*
15150  * Based on:
15151  * Ext JS Library 1.1.1
15152  * Copyright(c) 2006-2007, Ext JS, LLC.
15153  *
15154  * Originally Released Under LGPL - original licence link has changed is not relivant.
15155  *
15156  * Fork - LGPL
15157  * <script type="text/javascript">
15158  */
15159  
15160
15161 /**
15162  * @class Roo.ComponentMgr
15163  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15164  * @singleton
15165  */
15166 Roo.ComponentMgr = function(){
15167     var all = new Roo.util.MixedCollection();
15168
15169     return {
15170         /**
15171          * Registers a component.
15172          * @param {Roo.Component} c The component
15173          */
15174         register : function(c){
15175             all.add(c);
15176         },
15177
15178         /**
15179          * Unregisters a component.
15180          * @param {Roo.Component} c The component
15181          */
15182         unregister : function(c){
15183             all.remove(c);
15184         },
15185
15186         /**
15187          * Returns a component by id
15188          * @param {String} id The component id
15189          */
15190         get : function(id){
15191             return all.get(id);
15192         },
15193
15194         /**
15195          * Registers a function that will be called when a specified component is added to ComponentMgr
15196          * @param {String} id The component id
15197          * @param {Funtction} fn The callback function
15198          * @param {Object} scope The scope of the callback
15199          */
15200         onAvailable : function(id, fn, scope){
15201             all.on("add", function(index, o){
15202                 if(o.id == id){
15203                     fn.call(scope || o, o);
15204                     all.un("add", fn, scope);
15205                 }
15206             });
15207         }
15208     };
15209 }();/*
15210  * Based on:
15211  * Ext JS Library 1.1.1
15212  * Copyright(c) 2006-2007, Ext JS, LLC.
15213  *
15214  * Originally Released Under LGPL - original licence link has changed is not relivant.
15215  *
15216  * Fork - LGPL
15217  * <script type="text/javascript">
15218  */
15219  
15220 /**
15221  * @class Roo.Component
15222  * @extends Roo.util.Observable
15223  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15224  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15225  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15226  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15227  * All visual components (widgets) that require rendering into a layout should subclass Component.
15228  * @constructor
15229  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15230  * 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
15231  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15232  */
15233 Roo.Component = function(config){
15234     config = config || {};
15235     if(config.tagName || config.dom || typeof config == "string"){ // element object
15236         config = {el: config, id: config.id || config};
15237     }
15238     this.initialConfig = config;
15239
15240     Roo.apply(this, config);
15241     this.addEvents({
15242         /**
15243          * @event disable
15244          * Fires after the component is disabled.
15245              * @param {Roo.Component} this
15246              */
15247         disable : true,
15248         /**
15249          * @event enable
15250          * Fires after the component is enabled.
15251              * @param {Roo.Component} this
15252              */
15253         enable : true,
15254         /**
15255          * @event beforeshow
15256          * Fires before the component is shown.  Return false to stop the show.
15257              * @param {Roo.Component} this
15258              */
15259         beforeshow : true,
15260         /**
15261          * @event show
15262          * Fires after the component is shown.
15263              * @param {Roo.Component} this
15264              */
15265         show : true,
15266         /**
15267          * @event beforehide
15268          * Fires before the component is hidden. Return false to stop the hide.
15269              * @param {Roo.Component} this
15270              */
15271         beforehide : true,
15272         /**
15273          * @event hide
15274          * Fires after the component is hidden.
15275              * @param {Roo.Component} this
15276              */
15277         hide : true,
15278         /**
15279          * @event beforerender
15280          * Fires before the component is rendered. Return false to stop the render.
15281              * @param {Roo.Component} this
15282              */
15283         beforerender : true,
15284         /**
15285          * @event render
15286          * Fires after the component is rendered.
15287              * @param {Roo.Component} this
15288              */
15289         render : true,
15290         /**
15291          * @event beforedestroy
15292          * Fires before the component is destroyed. Return false to stop the destroy.
15293              * @param {Roo.Component} this
15294              */
15295         beforedestroy : true,
15296         /**
15297          * @event destroy
15298          * Fires after the component is destroyed.
15299              * @param {Roo.Component} this
15300              */
15301         destroy : true
15302     });
15303     if(!this.id){
15304         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15305     }
15306     Roo.ComponentMgr.register(this);
15307     Roo.Component.superclass.constructor.call(this);
15308     this.initComponent();
15309     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15310         this.render(this.renderTo);
15311         delete this.renderTo;
15312     }
15313 };
15314
15315 /** @private */
15316 Roo.Component.AUTO_ID = 1000;
15317
15318 Roo.extend(Roo.Component, Roo.util.Observable, {
15319     /**
15320      * @scope Roo.Component.prototype
15321      * @type {Boolean}
15322      * true if this component is hidden. Read-only.
15323      */
15324     hidden : false,
15325     /**
15326      * @type {Boolean}
15327      * true if this component is disabled. Read-only.
15328      */
15329     disabled : false,
15330     /**
15331      * @type {Boolean}
15332      * true if this component has been rendered. Read-only.
15333      */
15334     rendered : false,
15335     
15336     /** @cfg {String} disableClass
15337      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15338      */
15339     disabledClass : "x-item-disabled",
15340         /** @cfg {Boolean} allowDomMove
15341          * Whether the component can move the Dom node when rendering (defaults to true).
15342          */
15343     allowDomMove : true,
15344     /** @cfg {String} hideMode (display|visibility)
15345      * How this component should hidden. Supported values are
15346      * "visibility" (css visibility), "offsets" (negative offset position) and
15347      * "display" (css display) - defaults to "display".
15348      */
15349     hideMode: 'display',
15350
15351     /** @private */
15352     ctype : "Roo.Component",
15353
15354     /**
15355      * @cfg {String} actionMode 
15356      * which property holds the element that used for  hide() / show() / disable() / enable()
15357      * default is 'el' 
15358      */
15359     actionMode : "el",
15360
15361     /** @private */
15362     getActionEl : function(){
15363         return this[this.actionMode];
15364     },
15365
15366     initComponent : Roo.emptyFn,
15367     /**
15368      * If this is a lazy rendering component, render it to its container element.
15369      * @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.
15370      */
15371     render : function(container, position){
15372         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15373             if(!container && this.el){
15374                 this.el = Roo.get(this.el);
15375                 container = this.el.dom.parentNode;
15376                 this.allowDomMove = false;
15377             }
15378             this.container = Roo.get(container);
15379             this.rendered = true;
15380             if(position !== undefined){
15381                 if(typeof position == 'number'){
15382                     position = this.container.dom.childNodes[position];
15383                 }else{
15384                     position = Roo.getDom(position);
15385                 }
15386             }
15387             this.onRender(this.container, position || null);
15388             if(this.cls){
15389                 this.el.addClass(this.cls);
15390                 delete this.cls;
15391             }
15392             if(this.style){
15393                 this.el.applyStyles(this.style);
15394                 delete this.style;
15395             }
15396             this.fireEvent("render", this);
15397             this.afterRender(this.container);
15398             if(this.hidden){
15399                 this.hide();
15400             }
15401             if(this.disabled){
15402                 this.disable();
15403             }
15404         }
15405         return this;
15406     },
15407
15408     /** @private */
15409     // default function is not really useful
15410     onRender : function(ct, position){
15411         if(this.el){
15412             this.el = Roo.get(this.el);
15413             if(this.allowDomMove !== false){
15414                 ct.dom.insertBefore(this.el.dom, position);
15415             }
15416         }
15417     },
15418
15419     /** @private */
15420     getAutoCreate : function(){
15421         var cfg = typeof this.autoCreate == "object" ?
15422                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15423         if(this.id && !cfg.id){
15424             cfg.id = this.id;
15425         }
15426         return cfg;
15427     },
15428
15429     /** @private */
15430     afterRender : Roo.emptyFn,
15431
15432     /**
15433      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15434      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15435      */
15436     destroy : function(){
15437         if(this.fireEvent("beforedestroy", this) !== false){
15438             this.purgeListeners();
15439             this.beforeDestroy();
15440             if(this.rendered){
15441                 this.el.removeAllListeners();
15442                 this.el.remove();
15443                 if(this.actionMode == "container"){
15444                     this.container.remove();
15445                 }
15446             }
15447             this.onDestroy();
15448             Roo.ComponentMgr.unregister(this);
15449             this.fireEvent("destroy", this);
15450         }
15451     },
15452
15453         /** @private */
15454     beforeDestroy : function(){
15455
15456     },
15457
15458         /** @private */
15459         onDestroy : function(){
15460
15461     },
15462
15463     /**
15464      * Returns the underlying {@link Roo.Element}.
15465      * @return {Roo.Element} The element
15466      */
15467     getEl : function(){
15468         return this.el;
15469     },
15470
15471     /**
15472      * Returns the id of this component.
15473      * @return {String}
15474      */
15475     getId : function(){
15476         return this.id;
15477     },
15478
15479     /**
15480      * Try to focus this component.
15481      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15482      * @return {Roo.Component} this
15483      */
15484     focus : function(selectText){
15485         if(this.rendered){
15486             this.el.focus();
15487             if(selectText === true){
15488                 this.el.dom.select();
15489             }
15490         }
15491         return this;
15492     },
15493
15494     /** @private */
15495     blur : function(){
15496         if(this.rendered){
15497             this.el.blur();
15498         }
15499         return this;
15500     },
15501
15502     /**
15503      * Disable this component.
15504      * @return {Roo.Component} this
15505      */
15506     disable : function(){
15507         if(this.rendered){
15508             this.onDisable();
15509         }
15510         this.disabled = true;
15511         this.fireEvent("disable", this);
15512         return this;
15513     },
15514
15515         // private
15516     onDisable : function(){
15517         this.getActionEl().addClass(this.disabledClass);
15518         this.el.dom.disabled = true;
15519     },
15520
15521     /**
15522      * Enable this component.
15523      * @return {Roo.Component} this
15524      */
15525     enable : function(){
15526         if(this.rendered){
15527             this.onEnable();
15528         }
15529         this.disabled = false;
15530         this.fireEvent("enable", this);
15531         return this;
15532     },
15533
15534         // private
15535     onEnable : function(){
15536         this.getActionEl().removeClass(this.disabledClass);
15537         this.el.dom.disabled = false;
15538     },
15539
15540     /**
15541      * Convenience function for setting disabled/enabled by boolean.
15542      * @param {Boolean} disabled
15543      */
15544     setDisabled : function(disabled){
15545         this[disabled ? "disable" : "enable"]();
15546     },
15547
15548     /**
15549      * Show this component.
15550      * @return {Roo.Component} this
15551      */
15552     show: function(){
15553         if(this.fireEvent("beforeshow", this) !== false){
15554             this.hidden = false;
15555             if(this.rendered){
15556                 this.onShow();
15557             }
15558             this.fireEvent("show", this);
15559         }
15560         return this;
15561     },
15562
15563     // private
15564     onShow : function(){
15565         var ae = this.getActionEl();
15566         if(this.hideMode == 'visibility'){
15567             ae.dom.style.visibility = "visible";
15568         }else if(this.hideMode == 'offsets'){
15569             ae.removeClass('x-hidden');
15570         }else{
15571             ae.dom.style.display = "";
15572         }
15573     },
15574
15575     /**
15576      * Hide this component.
15577      * @return {Roo.Component} this
15578      */
15579     hide: function(){
15580         if(this.fireEvent("beforehide", this) !== false){
15581             this.hidden = true;
15582             if(this.rendered){
15583                 this.onHide();
15584             }
15585             this.fireEvent("hide", this);
15586         }
15587         return this;
15588     },
15589
15590     // private
15591     onHide : function(){
15592         var ae = this.getActionEl();
15593         if(this.hideMode == 'visibility'){
15594             ae.dom.style.visibility = "hidden";
15595         }else if(this.hideMode == 'offsets'){
15596             ae.addClass('x-hidden');
15597         }else{
15598             ae.dom.style.display = "none";
15599         }
15600     },
15601
15602     /**
15603      * Convenience function to hide or show this component by boolean.
15604      * @param {Boolean} visible True to show, false to hide
15605      * @return {Roo.Component} this
15606      */
15607     setVisible: function(visible){
15608         if(visible) {
15609             this.show();
15610         }else{
15611             this.hide();
15612         }
15613         return this;
15614     },
15615
15616     /**
15617      * Returns true if this component is visible.
15618      */
15619     isVisible : function(){
15620         return this.getActionEl().isVisible();
15621     },
15622
15623     cloneConfig : function(overrides){
15624         overrides = overrides || {};
15625         var id = overrides.id || Roo.id();
15626         var cfg = Roo.applyIf(overrides, this.initialConfig);
15627         cfg.id = id; // prevent dup id
15628         return new this.constructor(cfg);
15629     }
15630 });/*
15631  * Based on:
15632  * Ext JS Library 1.1.1
15633  * Copyright(c) 2006-2007, Ext JS, LLC.
15634  *
15635  * Originally Released Under LGPL - original licence link has changed is not relivant.
15636  *
15637  * Fork - LGPL
15638  * <script type="text/javascript">
15639  */
15640
15641 /**
15642  * @class Roo.BoxComponent
15643  * @extends Roo.Component
15644  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15645  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15646  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15647  * layout containers.
15648  * @constructor
15649  * @param {Roo.Element/String/Object} config The configuration options.
15650  */
15651 Roo.BoxComponent = function(config){
15652     Roo.Component.call(this, config);
15653     this.addEvents({
15654         /**
15655          * @event resize
15656          * Fires after the component is resized.
15657              * @param {Roo.Component} this
15658              * @param {Number} adjWidth The box-adjusted width that was set
15659              * @param {Number} adjHeight The box-adjusted height that was set
15660              * @param {Number} rawWidth The width that was originally specified
15661              * @param {Number} rawHeight The height that was originally specified
15662              */
15663         resize : true,
15664         /**
15665          * @event move
15666          * Fires after the component is moved.
15667              * @param {Roo.Component} this
15668              * @param {Number} x The new x position
15669              * @param {Number} y The new y position
15670              */
15671         move : true
15672     });
15673 };
15674
15675 Roo.extend(Roo.BoxComponent, Roo.Component, {
15676     // private, set in afterRender to signify that the component has been rendered
15677     boxReady : false,
15678     // private, used to defer height settings to subclasses
15679     deferHeight: false,
15680     /** @cfg {Number} width
15681      * width (optional) size of component
15682      */
15683      /** @cfg {Number} height
15684      * height (optional) size of component
15685      */
15686      
15687     /**
15688      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15689      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15690      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15691      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15692      * @return {Roo.BoxComponent} this
15693      */
15694     setSize : function(w, h){
15695         // support for standard size objects
15696         if(typeof w == 'object'){
15697             h = w.height;
15698             w = w.width;
15699         }
15700         // not rendered
15701         if(!this.boxReady){
15702             this.width = w;
15703             this.height = h;
15704             return this;
15705         }
15706
15707         // prevent recalcs when not needed
15708         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15709             return this;
15710         }
15711         this.lastSize = {width: w, height: h};
15712
15713         var adj = this.adjustSize(w, h);
15714         var aw = adj.width, ah = adj.height;
15715         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15716             var rz = this.getResizeEl();
15717             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15718                 rz.setSize(aw, ah);
15719             }else if(!this.deferHeight && ah !== undefined){
15720                 rz.setHeight(ah);
15721             }else if(aw !== undefined){
15722                 rz.setWidth(aw);
15723             }
15724             this.onResize(aw, ah, w, h);
15725             this.fireEvent('resize', this, aw, ah, w, h);
15726         }
15727         return this;
15728     },
15729
15730     /**
15731      * Gets the current size of the component's underlying element.
15732      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15733      */
15734     getSize : function(){
15735         return this.el.getSize();
15736     },
15737
15738     /**
15739      * Gets the current XY position of the component's underlying element.
15740      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15741      * @return {Array} The XY position of the element (e.g., [100, 200])
15742      */
15743     getPosition : function(local){
15744         if(local === true){
15745             return [this.el.getLeft(true), this.el.getTop(true)];
15746         }
15747         return this.xy || this.el.getXY();
15748     },
15749
15750     /**
15751      * Gets the current box measurements of the component's underlying element.
15752      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15753      * @returns {Object} box An object in the format {x, y, width, height}
15754      */
15755     getBox : function(local){
15756         var s = this.el.getSize();
15757         if(local){
15758             s.x = this.el.getLeft(true);
15759             s.y = this.el.getTop(true);
15760         }else{
15761             var xy = this.xy || this.el.getXY();
15762             s.x = xy[0];
15763             s.y = xy[1];
15764         }
15765         return s;
15766     },
15767
15768     /**
15769      * Sets the current box measurements of the component's underlying element.
15770      * @param {Object} box An object in the format {x, y, width, height}
15771      * @returns {Roo.BoxComponent} this
15772      */
15773     updateBox : function(box){
15774         this.setSize(box.width, box.height);
15775         this.setPagePosition(box.x, box.y);
15776         return this;
15777     },
15778
15779     // protected
15780     getResizeEl : function(){
15781         return this.resizeEl || this.el;
15782     },
15783
15784     // protected
15785     getPositionEl : function(){
15786         return this.positionEl || this.el;
15787     },
15788
15789     /**
15790      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15791      * This method fires the move event.
15792      * @param {Number} left The new left
15793      * @param {Number} top The new top
15794      * @returns {Roo.BoxComponent} this
15795      */
15796     setPosition : function(x, y){
15797         this.x = x;
15798         this.y = y;
15799         if(!this.boxReady){
15800             return this;
15801         }
15802         var adj = this.adjustPosition(x, y);
15803         var ax = adj.x, ay = adj.y;
15804
15805         var el = this.getPositionEl();
15806         if(ax !== undefined || ay !== undefined){
15807             if(ax !== undefined && ay !== undefined){
15808                 el.setLeftTop(ax, ay);
15809             }else if(ax !== undefined){
15810                 el.setLeft(ax);
15811             }else if(ay !== undefined){
15812                 el.setTop(ay);
15813             }
15814             this.onPosition(ax, ay);
15815             this.fireEvent('move', this, ax, ay);
15816         }
15817         return this;
15818     },
15819
15820     /**
15821      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15822      * This method fires the move event.
15823      * @param {Number} x The new x position
15824      * @param {Number} y The new y position
15825      * @returns {Roo.BoxComponent} this
15826      */
15827     setPagePosition : function(x, y){
15828         this.pageX = x;
15829         this.pageY = y;
15830         if(!this.boxReady){
15831             return;
15832         }
15833         if(x === undefined || y === undefined){ // cannot translate undefined points
15834             return;
15835         }
15836         var p = this.el.translatePoints(x, y);
15837         this.setPosition(p.left, p.top);
15838         return this;
15839     },
15840
15841     // private
15842     onRender : function(ct, position){
15843         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15844         if(this.resizeEl){
15845             this.resizeEl = Roo.get(this.resizeEl);
15846         }
15847         if(this.positionEl){
15848             this.positionEl = Roo.get(this.positionEl);
15849         }
15850     },
15851
15852     // private
15853     afterRender : function(){
15854         Roo.BoxComponent.superclass.afterRender.call(this);
15855         this.boxReady = true;
15856         this.setSize(this.width, this.height);
15857         if(this.x || this.y){
15858             this.setPosition(this.x, this.y);
15859         }
15860         if(this.pageX || this.pageY){
15861             this.setPagePosition(this.pageX, this.pageY);
15862         }
15863     },
15864
15865     /**
15866      * Force the component's size to recalculate based on the underlying element's current height and width.
15867      * @returns {Roo.BoxComponent} this
15868      */
15869     syncSize : function(){
15870         delete this.lastSize;
15871         this.setSize(this.el.getWidth(), this.el.getHeight());
15872         return this;
15873     },
15874
15875     /**
15876      * Called after the component is resized, this method is empty by default but can be implemented by any
15877      * subclass that needs to perform custom logic after a resize occurs.
15878      * @param {Number} adjWidth The box-adjusted width that was set
15879      * @param {Number} adjHeight The box-adjusted height that was set
15880      * @param {Number} rawWidth The width that was originally specified
15881      * @param {Number} rawHeight The height that was originally specified
15882      */
15883     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15884
15885     },
15886
15887     /**
15888      * Called after the component is moved, this method is empty by default but can be implemented by any
15889      * subclass that needs to perform custom logic after a move occurs.
15890      * @param {Number} x The new x position
15891      * @param {Number} y The new y position
15892      */
15893     onPosition : function(x, y){
15894
15895     },
15896
15897     // private
15898     adjustSize : function(w, h){
15899         if(this.autoWidth){
15900             w = 'auto';
15901         }
15902         if(this.autoHeight){
15903             h = 'auto';
15904         }
15905         return {width : w, height: h};
15906     },
15907
15908     // private
15909     adjustPosition : function(x, y){
15910         return {x : x, y: y};
15911     }
15912 });/*
15913  * Original code for Roojs - LGPL
15914  * <script type="text/javascript">
15915  */
15916  
15917 /**
15918  * @class Roo.XComponent
15919  * A delayed Element creator...
15920  * Or a way to group chunks of interface together.
15921  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15922  *  used in conjunction with XComponent.build() it will create an instance of each element,
15923  *  then call addxtype() to build the User interface.
15924  * 
15925  * Mypart.xyx = new Roo.XComponent({
15926
15927     parent : 'Mypart.xyz', // empty == document.element.!!
15928     order : '001',
15929     name : 'xxxx'
15930     region : 'xxxx'
15931     disabled : function() {} 
15932      
15933     tree : function() { // return an tree of xtype declared components
15934         var MODULE = this;
15935         return 
15936         {
15937             xtype : 'NestedLayoutPanel',
15938             // technicall
15939         }
15940      ]
15941  *})
15942  *
15943  *
15944  * It can be used to build a big heiracy, with parent etc.
15945  * or you can just use this to render a single compoent to a dom element
15946  * MYPART.render(Roo.Element | String(id) | dom_element )
15947  *
15948  *
15949  * Usage patterns.
15950  *
15951  * Classic Roo
15952  *
15953  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15954  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15955  *
15956  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15957  *
15958  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15959  * - if mulitple topModules exist, the last one is defined as the top module.
15960  *
15961  * Embeded Roo
15962  * 
15963  * When the top level or multiple modules are to embedded into a existing HTML page,
15964  * the parent element can container '#id' of the element where the module will be drawn.
15965  *
15966  * Bootstrap Roo
15967  *
15968  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15969  * it relies more on a include mechanism, where sub modules are included into an outer page.
15970  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15971  * 
15972  * Bootstrap Roo Included elements
15973  *
15974  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15975  * hence confusing the component builder as it thinks there are multiple top level elements. 
15976  *
15977  * String Over-ride & Translations
15978  *
15979  * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
15980  * and also the 'overlaying of string values - needed when different versions of the same application with different text content
15981  * are needed. @see Roo.XComponent.overlayString  
15982  * 
15983  * 
15984  * 
15985  * @extends Roo.util.Observable
15986  * @constructor
15987  * @param cfg {Object} configuration of component
15988  * 
15989  */
15990 Roo.XComponent = function(cfg) {
15991     Roo.apply(this, cfg);
15992     this.addEvents({ 
15993         /**
15994              * @event built
15995              * Fires when this the componnt is built
15996              * @param {Roo.XComponent} c the component
15997              */
15998         'built' : true
15999         
16000     });
16001     this.region = this.region || 'center'; // default..
16002     Roo.XComponent.register(this);
16003     this.modules = false;
16004     this.el = false; // where the layout goes..
16005     
16006     
16007 }
16008 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16009     /**
16010      * @property el
16011      * The created element (with Roo.factory())
16012      * @type {Roo.Layout}
16013      */
16014     el  : false,
16015     
16016     /**
16017      * @property el
16018      * for BC  - use el in new code
16019      * @type {Roo.Layout}
16020      */
16021     panel : false,
16022     
16023     /**
16024      * @property layout
16025      * for BC  - use el in new code
16026      * @type {Roo.Layout}
16027      */
16028     layout : false,
16029     
16030      /**
16031      * @cfg {Function|boolean} disabled
16032      * If this module is disabled by some rule, return true from the funtion
16033      */
16034     disabled : false,
16035     
16036     /**
16037      * @cfg {String} parent 
16038      * Name of parent element which it get xtype added to..
16039      */
16040     parent: false,
16041     
16042     /**
16043      * @cfg {String} order
16044      * Used to set the order in which elements are created (usefull for multiple tabs)
16045      */
16046     
16047     order : false,
16048     /**
16049      * @cfg {String} name
16050      * String to display while loading.
16051      */
16052     name : false,
16053     /**
16054      * @cfg {String} region
16055      * Region to render component to (defaults to center)
16056      */
16057     region : 'center',
16058     
16059     /**
16060      * @cfg {Array} items
16061      * A single item array - the first element is the root of the tree..
16062      * It's done this way to stay compatible with the Xtype system...
16063      */
16064     items : false,
16065     
16066     /**
16067      * @property _tree
16068      * The method that retuns the tree of parts that make up this compoennt 
16069      * @type {function}
16070      */
16071     _tree  : false,
16072     
16073      /**
16074      * render
16075      * render element to dom or tree
16076      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16077      */
16078     
16079     render : function(el)
16080     {
16081         
16082         el = el || false;
16083         var hp = this.parent ? 1 : 0;
16084         Roo.debug &&  Roo.log(this);
16085         
16086         var tree = this._tree ? this._tree() : this.tree();
16087
16088         
16089         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16090             // if parent is a '#.....' string, then let's use that..
16091             var ename = this.parent.substr(1);
16092             this.parent = false;
16093             Roo.debug && Roo.log(ename);
16094             switch (ename) {
16095                 case 'bootstrap-body':
16096                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16097                         // this is the BorderLayout standard?
16098                        this.parent = { el : true };
16099                        break;
16100                     }
16101                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16102                         // need to insert stuff...
16103                         this.parent =  {
16104                              el : new Roo.bootstrap.layout.Border({
16105                                  el : document.body, 
16106                      
16107                                  center: {
16108                                     titlebar: false,
16109                                     autoScroll:false,
16110                                     closeOnTab: true,
16111                                     tabPosition: 'top',
16112                                       //resizeTabs: true,
16113                                     alwaysShowTabs: true,
16114                                     hideTabs: false
16115                                      //minTabWidth: 140
16116                                  }
16117                              })
16118                         
16119                          };
16120                          break;
16121                     }
16122                          
16123                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16124                         this.parent = { el :  new  Roo.bootstrap.Body() };
16125                         Roo.debug && Roo.log("setting el to doc body");
16126                          
16127                     } else {
16128                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16129                     }
16130                     break;
16131                 case 'bootstrap':
16132                     this.parent = { el : true};
16133                     // fall through
16134                 default:
16135                     el = Roo.get(ename);
16136                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16137                         this.parent = { el : true};
16138                     }
16139                     
16140                     break;
16141             }
16142                 
16143             
16144             if (!el && !this.parent) {
16145                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16146                 return;
16147             }
16148         }
16149         
16150         Roo.debug && Roo.log("EL:");
16151         Roo.debug && Roo.log(el);
16152         Roo.debug && Roo.log("this.parent.el:");
16153         Roo.debug && Roo.log(this.parent.el);
16154         
16155
16156         // altertive root elements ??? - we need a better way to indicate these.
16157         var is_alt = Roo.XComponent.is_alt ||
16158                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16159                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16160                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16161         
16162         
16163         
16164         if (!this.parent && is_alt) {
16165             //el = Roo.get(document.body);
16166             this.parent = { el : true };
16167         }
16168             
16169             
16170         
16171         if (!this.parent) {
16172             
16173             Roo.debug && Roo.log("no parent - creating one");
16174             
16175             el = el ? Roo.get(el) : false;      
16176             
16177             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16178                 
16179                 this.parent =  {
16180                     el : new Roo.bootstrap.layout.Border({
16181                         el: el || document.body,
16182                     
16183                         center: {
16184                             titlebar: false,
16185                             autoScroll:false,
16186                             closeOnTab: true,
16187                             tabPosition: 'top',
16188                              //resizeTabs: true,
16189                             alwaysShowTabs: false,
16190                             hideTabs: true,
16191                             minTabWidth: 140,
16192                             overflow: 'visible'
16193                          }
16194                      })
16195                 };
16196             } else {
16197             
16198                 // it's a top level one..
16199                 this.parent =  {
16200                     el : new Roo.BorderLayout(el || document.body, {
16201                         center: {
16202                             titlebar: false,
16203                             autoScroll:false,
16204                             closeOnTab: true,
16205                             tabPosition: 'top',
16206                              //resizeTabs: true,
16207                             alwaysShowTabs: el && hp? false :  true,
16208                             hideTabs: el || !hp ? true :  false,
16209                             minTabWidth: 140
16210                          }
16211                     })
16212                 };
16213             }
16214         }
16215         
16216         if (!this.parent.el) {
16217                 // probably an old style ctor, which has been disabled.
16218                 return;
16219
16220         }
16221                 // The 'tree' method is  '_tree now' 
16222             
16223         tree.region = tree.region || this.region;
16224         var is_body = false;
16225         if (this.parent.el === true) {
16226             // bootstrap... - body..
16227             if (el) {
16228                 tree.el = el;
16229             }
16230             this.parent.el = Roo.factory(tree);
16231             is_body = true;
16232         }
16233         
16234         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16235         this.fireEvent('built', this);
16236         
16237         this.panel = this.el;
16238         this.layout = this.panel.layout;
16239         this.parentLayout = this.parent.layout  || false;  
16240          
16241     }
16242     
16243 });
16244
16245 Roo.apply(Roo.XComponent, {
16246     /**
16247      * @property  hideProgress
16248      * true to disable the building progress bar.. usefull on single page renders.
16249      * @type Boolean
16250      */
16251     hideProgress : false,
16252     /**
16253      * @property  buildCompleted
16254      * True when the builder has completed building the interface.
16255      * @type Boolean
16256      */
16257     buildCompleted : false,
16258      
16259     /**
16260      * @property  topModule
16261      * the upper most module - uses document.element as it's constructor.
16262      * @type Object
16263      */
16264      
16265     topModule  : false,
16266       
16267     /**
16268      * @property  modules
16269      * array of modules to be created by registration system.
16270      * @type {Array} of Roo.XComponent
16271      */
16272     
16273     modules : [],
16274     /**
16275      * @property  elmodules
16276      * array of modules to be created by which use #ID 
16277      * @type {Array} of Roo.XComponent
16278      */
16279      
16280     elmodules : [],
16281
16282      /**
16283      * @property  is_alt
16284      * Is an alternative Root - normally used by bootstrap or other systems,
16285      *    where the top element in the tree can wrap 'body' 
16286      * @type {boolean}  (default false)
16287      */
16288      
16289     is_alt : false,
16290     /**
16291      * @property  build_from_html
16292      * Build elements from html - used by bootstrap HTML stuff 
16293      *    - this is cleared after build is completed
16294      * @type {boolean}    (default false)
16295      */
16296      
16297     build_from_html : false,
16298     /**
16299      * Register components to be built later.
16300      *
16301      * This solves the following issues
16302      * - Building is not done on page load, but after an authentication process has occured.
16303      * - Interface elements are registered on page load
16304      * - Parent Interface elements may not be loaded before child, so this handles that..
16305      * 
16306      *
16307      * example:
16308      * 
16309      * MyApp.register({
16310           order : '000001',
16311           module : 'Pman.Tab.projectMgr',
16312           region : 'center',
16313           parent : 'Pman.layout',
16314           disabled : false,  // or use a function..
16315         })
16316      
16317      * * @param {Object} details about module
16318      */
16319     register : function(obj) {
16320                 
16321         Roo.XComponent.event.fireEvent('register', obj);
16322         switch(typeof(obj.disabled) ) {
16323                 
16324             case 'undefined':
16325                 break;
16326             
16327             case 'function':
16328                 if ( obj.disabled() ) {
16329                         return;
16330                 }
16331                 break;
16332             
16333             default:
16334                 if (obj.disabled) {
16335                         return;
16336                 }
16337                 break;
16338         }
16339                 
16340         this.modules.push(obj);
16341          
16342     },
16343     /**
16344      * convert a string to an object..
16345      * eg. 'AAA.BBB' -> finds AAA.BBB
16346
16347      */
16348     
16349     toObject : function(str)
16350     {
16351         if (!str || typeof(str) == 'object') {
16352             return str;
16353         }
16354         if (str.substring(0,1) == '#') {
16355             return str;
16356         }
16357
16358         var ar = str.split('.');
16359         var rt, o;
16360         rt = ar.shift();
16361             /** eval:var:o */
16362         try {
16363             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16364         } catch (e) {
16365             throw "Module not found : " + str;
16366         }
16367         
16368         if (o === false) {
16369             throw "Module not found : " + str;
16370         }
16371         Roo.each(ar, function(e) {
16372             if (typeof(o[e]) == 'undefined') {
16373                 throw "Module not found : " + str;
16374             }
16375             o = o[e];
16376         });
16377         
16378         return o;
16379         
16380     },
16381     
16382     
16383     /**
16384      * move modules into their correct place in the tree..
16385      * 
16386      */
16387     preBuild : function ()
16388     {
16389         var _t = this;
16390         Roo.each(this.modules , function (obj)
16391         {
16392             Roo.XComponent.event.fireEvent('beforebuild', obj);
16393             
16394             var opar = obj.parent;
16395             try { 
16396                 obj.parent = this.toObject(opar);
16397             } catch(e) {
16398                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16399                 return;
16400             }
16401             
16402             if (!obj.parent) {
16403                 Roo.debug && Roo.log("GOT top level module");
16404                 Roo.debug && Roo.log(obj);
16405                 obj.modules = new Roo.util.MixedCollection(false, 
16406                     function(o) { return o.order + '' }
16407                 );
16408                 this.topModule = obj;
16409                 return;
16410             }
16411                         // parent is a string (usually a dom element name..)
16412             if (typeof(obj.parent) == 'string') {
16413                 this.elmodules.push(obj);
16414                 return;
16415             }
16416             if (obj.parent.constructor != Roo.XComponent) {
16417                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16418             }
16419             if (!obj.parent.modules) {
16420                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16421                     function(o) { return o.order + '' }
16422                 );
16423             }
16424             if (obj.parent.disabled) {
16425                 obj.disabled = true;
16426             }
16427             obj.parent.modules.add(obj);
16428         }, this);
16429     },
16430     
16431      /**
16432      * make a list of modules to build.
16433      * @return {Array} list of modules. 
16434      */ 
16435     
16436     buildOrder : function()
16437     {
16438         var _this = this;
16439         var cmp = function(a,b) {   
16440             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16441         };
16442         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16443             throw "No top level modules to build";
16444         }
16445         
16446         // make a flat list in order of modules to build.
16447         var mods = this.topModule ? [ this.topModule ] : [];
16448                 
16449         
16450         // elmodules (is a list of DOM based modules )
16451         Roo.each(this.elmodules, function(e) {
16452             mods.push(e);
16453             if (!this.topModule &&
16454                 typeof(e.parent) == 'string' &&
16455                 e.parent.substring(0,1) == '#' &&
16456                 Roo.get(e.parent.substr(1))
16457                ) {
16458                 
16459                 _this.topModule = e;
16460             }
16461             
16462         });
16463
16464         
16465         // add modules to their parents..
16466         var addMod = function(m) {
16467             Roo.debug && Roo.log("build Order: add: " + m.name);
16468                 
16469             mods.push(m);
16470             if (m.modules && !m.disabled) {
16471                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16472                 m.modules.keySort('ASC',  cmp );
16473                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16474     
16475                 m.modules.each(addMod);
16476             } else {
16477                 Roo.debug && Roo.log("build Order: no child modules");
16478             }
16479             // not sure if this is used any more..
16480             if (m.finalize) {
16481                 m.finalize.name = m.name + " (clean up) ";
16482                 mods.push(m.finalize);
16483             }
16484             
16485         }
16486         if (this.topModule && this.topModule.modules) { 
16487             this.topModule.modules.keySort('ASC',  cmp );
16488             this.topModule.modules.each(addMod);
16489         } 
16490         return mods;
16491     },
16492     
16493      /**
16494      * Build the registered modules.
16495      * @param {Object} parent element.
16496      * @param {Function} optional method to call after module has been added.
16497      * 
16498      */ 
16499    
16500     build : function(opts) 
16501     {
16502         
16503         if (typeof(opts) != 'undefined') {
16504             Roo.apply(this,opts);
16505         }
16506         
16507         this.preBuild();
16508         var mods = this.buildOrder();
16509       
16510         //this.allmods = mods;
16511         //Roo.debug && Roo.log(mods);
16512         //return;
16513         if (!mods.length) { // should not happen
16514             throw "NO modules!!!";
16515         }
16516         
16517         
16518         var msg = "Building Interface...";
16519         // flash it up as modal - so we store the mask!?
16520         if (!this.hideProgress && Roo.MessageBox) {
16521             Roo.MessageBox.show({ title: 'loading' });
16522             Roo.MessageBox.show({
16523                title: "Please wait...",
16524                msg: msg,
16525                width:450,
16526                progress:true,
16527                closable:false,
16528                modal: false
16529               
16530             });
16531         }
16532         var total = mods.length;
16533         
16534         var _this = this;
16535         var progressRun = function() {
16536             if (!mods.length) {
16537                 Roo.debug && Roo.log('hide?');
16538                 if (!this.hideProgress && Roo.MessageBox) {
16539                     Roo.MessageBox.hide();
16540                 }
16541                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16542                 
16543                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16544                 
16545                 // THE END...
16546                 return false;   
16547             }
16548             
16549             var m = mods.shift();
16550             
16551             
16552             Roo.debug && Roo.log(m);
16553             // not sure if this is supported any more.. - modules that are are just function
16554             if (typeof(m) == 'function') { 
16555                 m.call(this);
16556                 return progressRun.defer(10, _this);
16557             } 
16558             
16559             
16560             msg = "Building Interface " + (total  - mods.length) + 
16561                     " of " + total + 
16562                     (m.name ? (' - ' + m.name) : '');
16563                         Roo.debug && Roo.log(msg);
16564             if (!_this.hideProgress &&  Roo.MessageBox) { 
16565                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16566             }
16567             
16568          
16569             // is the module disabled?
16570             var disabled = (typeof(m.disabled) == 'function') ?
16571                 m.disabled.call(m.module.disabled) : m.disabled;    
16572             
16573             
16574             if (disabled) {
16575                 return progressRun(); // we do not update the display!
16576             }
16577             
16578             // now build 
16579             
16580                         
16581                         
16582             m.render();
16583             // it's 10 on top level, and 1 on others??? why...
16584             return progressRun.defer(10, _this);
16585              
16586         }
16587         progressRun.defer(1, _this);
16588      
16589         
16590         
16591     },
16592     /**
16593      * Overlay a set of modified strings onto a component
16594      * This is dependant on our builder exporting the strings and 'named strings' elements.
16595      * 
16596      * @param {Object} element to overlay on - eg. Pman.Dialog.Login
16597      * @param {Object} associative array of 'named' string and it's new value.
16598      * 
16599      */
16600         overlayStrings : function( component, strings )
16601     {
16602         if (typeof(component['_named_strings']) == undefined) {
16603             throw "ERROR: component does not have _named_strings";
16604         }
16605         for ( var k in strings ) {
16606             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
16607             if (md !== false) {
16608                 component['strings'][md] = strings[k];
16609             } else {
16610                 Roo.log('could not find named string: ' + k + ' in');
16611                 Roo.log(component);
16612             }
16613             
16614         }
16615         
16616     },
16617     
16618         
16619         /**
16620          * Event Object.
16621          *
16622          *
16623          */
16624         event: false, 
16625     /**
16626          * wrapper for event.on - aliased later..  
16627          * Typically use to register a event handler for register:
16628          *
16629          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16630          *
16631          */
16632     on : false
16633    
16634     
16635     
16636 });
16637
16638 Roo.XComponent.event = new Roo.util.Observable({
16639                 events : { 
16640                         /**
16641                          * @event register
16642                          * Fires when an Component is registered,
16643                          * set the disable property on the Component to stop registration.
16644                          * @param {Roo.XComponent} c the component being registerd.
16645                          * 
16646                          */
16647                         'register' : true,
16648             /**
16649                          * @event beforebuild
16650                          * Fires before each Component is built
16651                          * can be used to apply permissions.
16652                          * @param {Roo.XComponent} c the component being registerd.
16653                          * 
16654                          */
16655                         'beforebuild' : true,
16656                         /**
16657                          * @event buildcomplete
16658                          * Fires on the top level element when all elements have been built
16659                          * @param {Roo.XComponent} the top level component.
16660                          */
16661                         'buildcomplete' : true
16662                         
16663                 }
16664 });
16665
16666 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16667  //
16668  /**
16669  * marked - a markdown parser
16670  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16671  * https://github.com/chjj/marked
16672  */
16673
16674
16675 /**
16676  *
16677  * Roo.Markdown - is a very crude wrapper around marked..
16678  *
16679  * usage:
16680  * 
16681  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16682  * 
16683  * Note: move the sample code to the bottom of this
16684  * file before uncommenting it.
16685  *
16686  */
16687
16688 Roo.Markdown = {};
16689 Roo.Markdown.toHtml = function(text) {
16690     
16691     var c = new Roo.Markdown.marked.setOptions({
16692             renderer: new Roo.Markdown.marked.Renderer(),
16693             gfm: true,
16694             tables: true,
16695             breaks: false,
16696             pedantic: false,
16697             sanitize: false,
16698             smartLists: true,
16699             smartypants: false
16700           });
16701     // A FEW HACKS!!?
16702     
16703     text = text.replace(/\\\n/g,' ');
16704     return Roo.Markdown.marked(text);
16705 };
16706 //
16707 // converter
16708 //
16709 // Wraps all "globals" so that the only thing
16710 // exposed is makeHtml().
16711 //
16712 (function() {
16713     
16714     /**
16715      * Block-Level Grammar
16716      */
16717     
16718     var block = {
16719       newline: /^\n+/,
16720       code: /^( {4}[^\n]+\n*)+/,
16721       fences: noop,
16722       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16723       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16724       nptable: noop,
16725       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16726       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16727       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16728       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16729       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16730       table: noop,
16731       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16732       text: /^[^\n]+/
16733     };
16734     
16735     block.bullet = /(?:[*+-]|\d+\.)/;
16736     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16737     block.item = replace(block.item, 'gm')
16738       (/bull/g, block.bullet)
16739       ();
16740     
16741     block.list = replace(block.list)
16742       (/bull/g, block.bullet)
16743       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16744       ('def', '\\n+(?=' + block.def.source + ')')
16745       ();
16746     
16747     block.blockquote = replace(block.blockquote)
16748       ('def', block.def)
16749       ();
16750     
16751     block._tag = '(?!(?:'
16752       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16753       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16754       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16755     
16756     block.html = replace(block.html)
16757       ('comment', /<!--[\s\S]*?-->/)
16758       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16759       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16760       (/tag/g, block._tag)
16761       ();
16762     
16763     block.paragraph = replace(block.paragraph)
16764       ('hr', block.hr)
16765       ('heading', block.heading)
16766       ('lheading', block.lheading)
16767       ('blockquote', block.blockquote)
16768       ('tag', '<' + block._tag)
16769       ('def', block.def)
16770       ();
16771     
16772     /**
16773      * Normal Block Grammar
16774      */
16775     
16776     block.normal = merge({}, block);
16777     
16778     /**
16779      * GFM Block Grammar
16780      */
16781     
16782     block.gfm = merge({}, block.normal, {
16783       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16784       paragraph: /^/,
16785       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16786     });
16787     
16788     block.gfm.paragraph = replace(block.paragraph)
16789       ('(?!', '(?!'
16790         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16791         + block.list.source.replace('\\1', '\\3') + '|')
16792       ();
16793     
16794     /**
16795      * GFM + Tables Block Grammar
16796      */
16797     
16798     block.tables = merge({}, block.gfm, {
16799       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16800       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16801     });
16802     
16803     /**
16804      * Block Lexer
16805      */
16806     
16807     function Lexer(options) {
16808       this.tokens = [];
16809       this.tokens.links = {};
16810       this.options = options || marked.defaults;
16811       this.rules = block.normal;
16812     
16813       if (this.options.gfm) {
16814         if (this.options.tables) {
16815           this.rules = block.tables;
16816         } else {
16817           this.rules = block.gfm;
16818         }
16819       }
16820     }
16821     
16822     /**
16823      * Expose Block Rules
16824      */
16825     
16826     Lexer.rules = block;
16827     
16828     /**
16829      * Static Lex Method
16830      */
16831     
16832     Lexer.lex = function(src, options) {
16833       var lexer = new Lexer(options);
16834       return lexer.lex(src);
16835     };
16836     
16837     /**
16838      * Preprocessing
16839      */
16840     
16841     Lexer.prototype.lex = function(src) {
16842       src = src
16843         .replace(/\r\n|\r/g, '\n')
16844         .replace(/\t/g, '    ')
16845         .replace(/\u00a0/g, ' ')
16846         .replace(/\u2424/g, '\n');
16847     
16848       return this.token(src, true);
16849     };
16850     
16851     /**
16852      * Lexing
16853      */
16854     
16855     Lexer.prototype.token = function(src, top, bq) {
16856       var src = src.replace(/^ +$/gm, '')
16857         , next
16858         , loose
16859         , cap
16860         , bull
16861         , b
16862         , item
16863         , space
16864         , i
16865         , l;
16866     
16867       while (src) {
16868         // newline
16869         if (cap = this.rules.newline.exec(src)) {
16870           src = src.substring(cap[0].length);
16871           if (cap[0].length > 1) {
16872             this.tokens.push({
16873               type: 'space'
16874             });
16875           }
16876         }
16877     
16878         // code
16879         if (cap = this.rules.code.exec(src)) {
16880           src = src.substring(cap[0].length);
16881           cap = cap[0].replace(/^ {4}/gm, '');
16882           this.tokens.push({
16883             type: 'code',
16884             text: !this.options.pedantic
16885               ? cap.replace(/\n+$/, '')
16886               : cap
16887           });
16888           continue;
16889         }
16890     
16891         // fences (gfm)
16892         if (cap = this.rules.fences.exec(src)) {
16893           src = src.substring(cap[0].length);
16894           this.tokens.push({
16895             type: 'code',
16896             lang: cap[2],
16897             text: cap[3] || ''
16898           });
16899           continue;
16900         }
16901     
16902         // heading
16903         if (cap = this.rules.heading.exec(src)) {
16904           src = src.substring(cap[0].length);
16905           this.tokens.push({
16906             type: 'heading',
16907             depth: cap[1].length,
16908             text: cap[2]
16909           });
16910           continue;
16911         }
16912     
16913         // table no leading pipe (gfm)
16914         if (top && (cap = this.rules.nptable.exec(src))) {
16915           src = src.substring(cap[0].length);
16916     
16917           item = {
16918             type: 'table',
16919             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16920             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16921             cells: cap[3].replace(/\n$/, '').split('\n')
16922           };
16923     
16924           for (i = 0; i < item.align.length; i++) {
16925             if (/^ *-+: *$/.test(item.align[i])) {
16926               item.align[i] = 'right';
16927             } else if (/^ *:-+: *$/.test(item.align[i])) {
16928               item.align[i] = 'center';
16929             } else if (/^ *:-+ *$/.test(item.align[i])) {
16930               item.align[i] = 'left';
16931             } else {
16932               item.align[i] = null;
16933             }
16934           }
16935     
16936           for (i = 0; i < item.cells.length; i++) {
16937             item.cells[i] = item.cells[i].split(/ *\| */);
16938           }
16939     
16940           this.tokens.push(item);
16941     
16942           continue;
16943         }
16944     
16945         // lheading
16946         if (cap = this.rules.lheading.exec(src)) {
16947           src = src.substring(cap[0].length);
16948           this.tokens.push({
16949             type: 'heading',
16950             depth: cap[2] === '=' ? 1 : 2,
16951             text: cap[1]
16952           });
16953           continue;
16954         }
16955     
16956         // hr
16957         if (cap = this.rules.hr.exec(src)) {
16958           src = src.substring(cap[0].length);
16959           this.tokens.push({
16960             type: 'hr'
16961           });
16962           continue;
16963         }
16964     
16965         // blockquote
16966         if (cap = this.rules.blockquote.exec(src)) {
16967           src = src.substring(cap[0].length);
16968     
16969           this.tokens.push({
16970             type: 'blockquote_start'
16971           });
16972     
16973           cap = cap[0].replace(/^ *> ?/gm, '');
16974     
16975           // Pass `top` to keep the current
16976           // "toplevel" state. This is exactly
16977           // how markdown.pl works.
16978           this.token(cap, top, true);
16979     
16980           this.tokens.push({
16981             type: 'blockquote_end'
16982           });
16983     
16984           continue;
16985         }
16986     
16987         // list
16988         if (cap = this.rules.list.exec(src)) {
16989           src = src.substring(cap[0].length);
16990           bull = cap[2];
16991     
16992           this.tokens.push({
16993             type: 'list_start',
16994             ordered: bull.length > 1
16995           });
16996     
16997           // Get each top-level item.
16998           cap = cap[0].match(this.rules.item);
16999     
17000           next = false;
17001           l = cap.length;
17002           i = 0;
17003     
17004           for (; i < l; i++) {
17005             item = cap[i];
17006     
17007             // Remove the list item's bullet
17008             // so it is seen as the next token.
17009             space = item.length;
17010             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17011     
17012             // Outdent whatever the
17013             // list item contains. Hacky.
17014             if (~item.indexOf('\n ')) {
17015               space -= item.length;
17016               item = !this.options.pedantic
17017                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17018                 : item.replace(/^ {1,4}/gm, '');
17019             }
17020     
17021             // Determine whether the next list item belongs here.
17022             // Backpedal if it does not belong in this list.
17023             if (this.options.smartLists && i !== l - 1) {
17024               b = block.bullet.exec(cap[i + 1])[0];
17025               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17026                 src = cap.slice(i + 1).join('\n') + src;
17027                 i = l - 1;
17028               }
17029             }
17030     
17031             // Determine whether item is loose or not.
17032             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17033             // for discount behavior.
17034             loose = next || /\n\n(?!\s*$)/.test(item);
17035             if (i !== l - 1) {
17036               next = item.charAt(item.length - 1) === '\n';
17037               if (!loose) { loose = next; }
17038             }
17039     
17040             this.tokens.push({
17041               type: loose
17042                 ? 'loose_item_start'
17043                 : 'list_item_start'
17044             });
17045     
17046             // Recurse.
17047             this.token(item, false, bq);
17048     
17049             this.tokens.push({
17050               type: 'list_item_end'
17051             });
17052           }
17053     
17054           this.tokens.push({
17055             type: 'list_end'
17056           });
17057     
17058           continue;
17059         }
17060     
17061         // html
17062         if (cap = this.rules.html.exec(src)) {
17063           src = src.substring(cap[0].length);
17064           this.tokens.push({
17065             type: this.options.sanitize
17066               ? 'paragraph'
17067               : 'html',
17068             pre: !this.options.sanitizer
17069               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17070             text: cap[0]
17071           });
17072           continue;
17073         }
17074     
17075         // def
17076         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17077           src = src.substring(cap[0].length);
17078           this.tokens.links[cap[1].toLowerCase()] = {
17079             href: cap[2],
17080             title: cap[3]
17081           };
17082           continue;
17083         }
17084     
17085         // table (gfm)
17086         if (top && (cap = this.rules.table.exec(src))) {
17087           src = src.substring(cap[0].length);
17088     
17089           item = {
17090             type: 'table',
17091             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17092             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17093             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17094           };
17095     
17096           for (i = 0; i < item.align.length; i++) {
17097             if (/^ *-+: *$/.test(item.align[i])) {
17098               item.align[i] = 'right';
17099             } else if (/^ *:-+: *$/.test(item.align[i])) {
17100               item.align[i] = 'center';
17101             } else if (/^ *:-+ *$/.test(item.align[i])) {
17102               item.align[i] = 'left';
17103             } else {
17104               item.align[i] = null;
17105             }
17106           }
17107     
17108           for (i = 0; i < item.cells.length; i++) {
17109             item.cells[i] = item.cells[i]
17110               .replace(/^ *\| *| *\| *$/g, '')
17111               .split(/ *\| */);
17112           }
17113     
17114           this.tokens.push(item);
17115     
17116           continue;
17117         }
17118     
17119         // top-level paragraph
17120         if (top && (cap = this.rules.paragraph.exec(src))) {
17121           src = src.substring(cap[0].length);
17122           this.tokens.push({
17123             type: 'paragraph',
17124             text: cap[1].charAt(cap[1].length - 1) === '\n'
17125               ? cap[1].slice(0, -1)
17126               : cap[1]
17127           });
17128           continue;
17129         }
17130     
17131         // text
17132         if (cap = this.rules.text.exec(src)) {
17133           // Top-level should never reach here.
17134           src = src.substring(cap[0].length);
17135           this.tokens.push({
17136             type: 'text',
17137             text: cap[0]
17138           });
17139           continue;
17140         }
17141     
17142         if (src) {
17143           throw new
17144             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17145         }
17146       }
17147     
17148       return this.tokens;
17149     };
17150     
17151     /**
17152      * Inline-Level Grammar
17153      */
17154     
17155     var inline = {
17156       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17157       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17158       url: noop,
17159       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17160       link: /^!?\[(inside)\]\(href\)/,
17161       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17162       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17163       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17164       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17165       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17166       br: /^ {2,}\n(?!\s*$)/,
17167       del: noop,
17168       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17169     };
17170     
17171     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17172     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17173     
17174     inline.link = replace(inline.link)
17175       ('inside', inline._inside)
17176       ('href', inline._href)
17177       ();
17178     
17179     inline.reflink = replace(inline.reflink)
17180       ('inside', inline._inside)
17181       ();
17182     
17183     /**
17184      * Normal Inline Grammar
17185      */
17186     
17187     inline.normal = merge({}, inline);
17188     
17189     /**
17190      * Pedantic Inline Grammar
17191      */
17192     
17193     inline.pedantic = merge({}, inline.normal, {
17194       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17195       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17196     });
17197     
17198     /**
17199      * GFM Inline Grammar
17200      */
17201     
17202     inline.gfm = merge({}, inline.normal, {
17203       escape: replace(inline.escape)('])', '~|])')(),
17204       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17205       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17206       text: replace(inline.text)
17207         (']|', '~]|')
17208         ('|', '|https?://|')
17209         ()
17210     });
17211     
17212     /**
17213      * GFM + Line Breaks Inline Grammar
17214      */
17215     
17216     inline.breaks = merge({}, inline.gfm, {
17217       br: replace(inline.br)('{2,}', '*')(),
17218       text: replace(inline.gfm.text)('{2,}', '*')()
17219     });
17220     
17221     /**
17222      * Inline Lexer & Compiler
17223      */
17224     
17225     function InlineLexer(links, options) {
17226       this.options = options || marked.defaults;
17227       this.links = links;
17228       this.rules = inline.normal;
17229       this.renderer = this.options.renderer || new Renderer;
17230       this.renderer.options = this.options;
17231     
17232       if (!this.links) {
17233         throw new
17234           Error('Tokens array requires a `links` property.');
17235       }
17236     
17237       if (this.options.gfm) {
17238         if (this.options.breaks) {
17239           this.rules = inline.breaks;
17240         } else {
17241           this.rules = inline.gfm;
17242         }
17243       } else if (this.options.pedantic) {
17244         this.rules = inline.pedantic;
17245       }
17246     }
17247     
17248     /**
17249      * Expose Inline Rules
17250      */
17251     
17252     InlineLexer.rules = inline;
17253     
17254     /**
17255      * Static Lexing/Compiling Method
17256      */
17257     
17258     InlineLexer.output = function(src, links, options) {
17259       var inline = new InlineLexer(links, options);
17260       return inline.output(src);
17261     };
17262     
17263     /**
17264      * Lexing/Compiling
17265      */
17266     
17267     InlineLexer.prototype.output = function(src) {
17268       var out = ''
17269         , link
17270         , text
17271         , href
17272         , cap;
17273     
17274       while (src) {
17275         // escape
17276         if (cap = this.rules.escape.exec(src)) {
17277           src = src.substring(cap[0].length);
17278           out += cap[1];
17279           continue;
17280         }
17281     
17282         // autolink
17283         if (cap = this.rules.autolink.exec(src)) {
17284           src = src.substring(cap[0].length);
17285           if (cap[2] === '@') {
17286             text = cap[1].charAt(6) === ':'
17287               ? this.mangle(cap[1].substring(7))
17288               : this.mangle(cap[1]);
17289             href = this.mangle('mailto:') + text;
17290           } else {
17291             text = escape(cap[1]);
17292             href = text;
17293           }
17294           out += this.renderer.link(href, null, text);
17295           continue;
17296         }
17297     
17298         // url (gfm)
17299         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17300           src = src.substring(cap[0].length);
17301           text = escape(cap[1]);
17302           href = text;
17303           out += this.renderer.link(href, null, text);
17304           continue;
17305         }
17306     
17307         // tag
17308         if (cap = this.rules.tag.exec(src)) {
17309           if (!this.inLink && /^<a /i.test(cap[0])) {
17310             this.inLink = true;
17311           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17312             this.inLink = false;
17313           }
17314           src = src.substring(cap[0].length);
17315           out += this.options.sanitize
17316             ? this.options.sanitizer
17317               ? this.options.sanitizer(cap[0])
17318               : escape(cap[0])
17319             : cap[0];
17320           continue;
17321         }
17322     
17323         // link
17324         if (cap = this.rules.link.exec(src)) {
17325           src = src.substring(cap[0].length);
17326           this.inLink = true;
17327           out += this.outputLink(cap, {
17328             href: cap[2],
17329             title: cap[3]
17330           });
17331           this.inLink = false;
17332           continue;
17333         }
17334     
17335         // reflink, nolink
17336         if ((cap = this.rules.reflink.exec(src))
17337             || (cap = this.rules.nolink.exec(src))) {
17338           src = src.substring(cap[0].length);
17339           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17340           link = this.links[link.toLowerCase()];
17341           if (!link || !link.href) {
17342             out += cap[0].charAt(0);
17343             src = cap[0].substring(1) + src;
17344             continue;
17345           }
17346           this.inLink = true;
17347           out += this.outputLink(cap, link);
17348           this.inLink = false;
17349           continue;
17350         }
17351     
17352         // strong
17353         if (cap = this.rules.strong.exec(src)) {
17354           src = src.substring(cap[0].length);
17355           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17356           continue;
17357         }
17358     
17359         // em
17360         if (cap = this.rules.em.exec(src)) {
17361           src = src.substring(cap[0].length);
17362           out += this.renderer.em(this.output(cap[2] || cap[1]));
17363           continue;
17364         }
17365     
17366         // code
17367         if (cap = this.rules.code.exec(src)) {
17368           src = src.substring(cap[0].length);
17369           out += this.renderer.codespan(escape(cap[2], true));
17370           continue;
17371         }
17372     
17373         // br
17374         if (cap = this.rules.br.exec(src)) {
17375           src = src.substring(cap[0].length);
17376           out += this.renderer.br();
17377           continue;
17378         }
17379     
17380         // del (gfm)
17381         if (cap = this.rules.del.exec(src)) {
17382           src = src.substring(cap[0].length);
17383           out += this.renderer.del(this.output(cap[1]));
17384           continue;
17385         }
17386     
17387         // text
17388         if (cap = this.rules.text.exec(src)) {
17389           src = src.substring(cap[0].length);
17390           out += this.renderer.text(escape(this.smartypants(cap[0])));
17391           continue;
17392         }
17393     
17394         if (src) {
17395           throw new
17396             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17397         }
17398       }
17399     
17400       return out;
17401     };
17402     
17403     /**
17404      * Compile Link
17405      */
17406     
17407     InlineLexer.prototype.outputLink = function(cap, link) {
17408       var href = escape(link.href)
17409         , title = link.title ? escape(link.title) : null;
17410     
17411       return cap[0].charAt(0) !== '!'
17412         ? this.renderer.link(href, title, this.output(cap[1]))
17413         : this.renderer.image(href, title, escape(cap[1]));
17414     };
17415     
17416     /**
17417      * Smartypants Transformations
17418      */
17419     
17420     InlineLexer.prototype.smartypants = function(text) {
17421       if (!this.options.smartypants)  { return text; }
17422       return text
17423         // em-dashes
17424         .replace(/---/g, '\u2014')
17425         // en-dashes
17426         .replace(/--/g, '\u2013')
17427         // opening singles
17428         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17429         // closing singles & apostrophes
17430         .replace(/'/g, '\u2019')
17431         // opening doubles
17432         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17433         // closing doubles
17434         .replace(/"/g, '\u201d')
17435         // ellipses
17436         .replace(/\.{3}/g, '\u2026');
17437     };
17438     
17439     /**
17440      * Mangle Links
17441      */
17442     
17443     InlineLexer.prototype.mangle = function(text) {
17444       if (!this.options.mangle) { return text; }
17445       var out = ''
17446         , l = text.length
17447         , i = 0
17448         , ch;
17449     
17450       for (; i < l; i++) {
17451         ch = text.charCodeAt(i);
17452         if (Math.random() > 0.5) {
17453           ch = 'x' + ch.toString(16);
17454         }
17455         out += '&#' + ch + ';';
17456       }
17457     
17458       return out;
17459     };
17460     
17461     /**
17462      * Renderer
17463      */
17464     
17465     function Renderer(options) {
17466       this.options = options || {};
17467     }
17468     
17469     Renderer.prototype.code = function(code, lang, escaped) {
17470       if (this.options.highlight) {
17471         var out = this.options.highlight(code, lang);
17472         if (out != null && out !== code) {
17473           escaped = true;
17474           code = out;
17475         }
17476       } else {
17477             // hack!!! - it's already escapeD?
17478             escaped = true;
17479       }
17480     
17481       if (!lang) {
17482         return '<pre><code>'
17483           + (escaped ? code : escape(code, true))
17484           + '\n</code></pre>';
17485       }
17486     
17487       return '<pre><code class="'
17488         + this.options.langPrefix
17489         + escape(lang, true)
17490         + '">'
17491         + (escaped ? code : escape(code, true))
17492         + '\n</code></pre>\n';
17493     };
17494     
17495     Renderer.prototype.blockquote = function(quote) {
17496       return '<blockquote>\n' + quote + '</blockquote>\n';
17497     };
17498     
17499     Renderer.prototype.html = function(html) {
17500       return html;
17501     };
17502     
17503     Renderer.prototype.heading = function(text, level, raw) {
17504       return '<h'
17505         + level
17506         + ' id="'
17507         + this.options.headerPrefix
17508         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17509         + '">'
17510         + text
17511         + '</h'
17512         + level
17513         + '>\n';
17514     };
17515     
17516     Renderer.prototype.hr = function() {
17517       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17518     };
17519     
17520     Renderer.prototype.list = function(body, ordered) {
17521       var type = ordered ? 'ol' : 'ul';
17522       return '<' + type + '>\n' + body + '</' + type + '>\n';
17523     };
17524     
17525     Renderer.prototype.listitem = function(text) {
17526       return '<li>' + text + '</li>\n';
17527     };
17528     
17529     Renderer.prototype.paragraph = function(text) {
17530       return '<p>' + text + '</p>\n';
17531     };
17532     
17533     Renderer.prototype.table = function(header, body) {
17534       return '<table class="table table-striped">\n'
17535         + '<thead>\n'
17536         + header
17537         + '</thead>\n'
17538         + '<tbody>\n'
17539         + body
17540         + '</tbody>\n'
17541         + '</table>\n';
17542     };
17543     
17544     Renderer.prototype.tablerow = function(content) {
17545       return '<tr>\n' + content + '</tr>\n';
17546     };
17547     
17548     Renderer.prototype.tablecell = function(content, flags) {
17549       var type = flags.header ? 'th' : 'td';
17550       var tag = flags.align
17551         ? '<' + type + ' style="text-align:' + flags.align + '">'
17552         : '<' + type + '>';
17553       return tag + content + '</' + type + '>\n';
17554     };
17555     
17556     // span level renderer
17557     Renderer.prototype.strong = function(text) {
17558       return '<strong>' + text + '</strong>';
17559     };
17560     
17561     Renderer.prototype.em = function(text) {
17562       return '<em>' + text + '</em>';
17563     };
17564     
17565     Renderer.prototype.codespan = function(text) {
17566       return '<code>' + text + '</code>';
17567     };
17568     
17569     Renderer.prototype.br = function() {
17570       return this.options.xhtml ? '<br/>' : '<br>';
17571     };
17572     
17573     Renderer.prototype.del = function(text) {
17574       return '<del>' + text + '</del>';
17575     };
17576     
17577     Renderer.prototype.link = function(href, title, text) {
17578       if (this.options.sanitize) {
17579         try {
17580           var prot = decodeURIComponent(unescape(href))
17581             .replace(/[^\w:]/g, '')
17582             .toLowerCase();
17583         } catch (e) {
17584           return '';
17585         }
17586         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17587           return '';
17588         }
17589       }
17590       var out = '<a href="' + href + '"';
17591       if (title) {
17592         out += ' title="' + title + '"';
17593       }
17594       out += '>' + text + '</a>';
17595       return out;
17596     };
17597     
17598     Renderer.prototype.image = function(href, title, text) {
17599       var out = '<img src="' + href + '" alt="' + text + '"';
17600       if (title) {
17601         out += ' title="' + title + '"';
17602       }
17603       out += this.options.xhtml ? '/>' : '>';
17604       return out;
17605     };
17606     
17607     Renderer.prototype.text = function(text) {
17608       return text;
17609     };
17610     
17611     /**
17612      * Parsing & Compiling
17613      */
17614     
17615     function Parser(options) {
17616       this.tokens = [];
17617       this.token = null;
17618       this.options = options || marked.defaults;
17619       this.options.renderer = this.options.renderer || new Renderer;
17620       this.renderer = this.options.renderer;
17621       this.renderer.options = this.options;
17622     }
17623     
17624     /**
17625      * Static Parse Method
17626      */
17627     
17628     Parser.parse = function(src, options, renderer) {
17629       var parser = new Parser(options, renderer);
17630       return parser.parse(src);
17631     };
17632     
17633     /**
17634      * Parse Loop
17635      */
17636     
17637     Parser.prototype.parse = function(src) {
17638       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17639       this.tokens = src.reverse();
17640     
17641       var out = '';
17642       while (this.next()) {
17643         out += this.tok();
17644       }
17645     
17646       return out;
17647     };
17648     
17649     /**
17650      * Next Token
17651      */
17652     
17653     Parser.prototype.next = function() {
17654       return this.token = this.tokens.pop();
17655     };
17656     
17657     /**
17658      * Preview Next Token
17659      */
17660     
17661     Parser.prototype.peek = function() {
17662       return this.tokens[this.tokens.length - 1] || 0;
17663     };
17664     
17665     /**
17666      * Parse Text Tokens
17667      */
17668     
17669     Parser.prototype.parseText = function() {
17670       var body = this.token.text;
17671     
17672       while (this.peek().type === 'text') {
17673         body += '\n' + this.next().text;
17674       }
17675     
17676       return this.inline.output(body);
17677     };
17678     
17679     /**
17680      * Parse Current Token
17681      */
17682     
17683     Parser.prototype.tok = function() {
17684       switch (this.token.type) {
17685         case 'space': {
17686           return '';
17687         }
17688         case 'hr': {
17689           return this.renderer.hr();
17690         }
17691         case 'heading': {
17692           return this.renderer.heading(
17693             this.inline.output(this.token.text),
17694             this.token.depth,
17695             this.token.text);
17696         }
17697         case 'code': {
17698           return this.renderer.code(this.token.text,
17699             this.token.lang,
17700             this.token.escaped);
17701         }
17702         case 'table': {
17703           var header = ''
17704             , body = ''
17705             , i
17706             , row
17707             , cell
17708             , flags
17709             , j;
17710     
17711           // header
17712           cell = '';
17713           for (i = 0; i < this.token.header.length; i++) {
17714             flags = { header: true, align: this.token.align[i] };
17715             cell += this.renderer.tablecell(
17716               this.inline.output(this.token.header[i]),
17717               { header: true, align: this.token.align[i] }
17718             );
17719           }
17720           header += this.renderer.tablerow(cell);
17721     
17722           for (i = 0; i < this.token.cells.length; i++) {
17723             row = this.token.cells[i];
17724     
17725             cell = '';
17726             for (j = 0; j < row.length; j++) {
17727               cell += this.renderer.tablecell(
17728                 this.inline.output(row[j]),
17729                 { header: false, align: this.token.align[j] }
17730               );
17731             }
17732     
17733             body += this.renderer.tablerow(cell);
17734           }
17735           return this.renderer.table(header, body);
17736         }
17737         case 'blockquote_start': {
17738           var body = '';
17739     
17740           while (this.next().type !== 'blockquote_end') {
17741             body += this.tok();
17742           }
17743     
17744           return this.renderer.blockquote(body);
17745         }
17746         case 'list_start': {
17747           var body = ''
17748             , ordered = this.token.ordered;
17749     
17750           while (this.next().type !== 'list_end') {
17751             body += this.tok();
17752           }
17753     
17754           return this.renderer.list(body, ordered);
17755         }
17756         case 'list_item_start': {
17757           var body = '';
17758     
17759           while (this.next().type !== 'list_item_end') {
17760             body += this.token.type === 'text'
17761               ? this.parseText()
17762               : this.tok();
17763           }
17764     
17765           return this.renderer.listitem(body);
17766         }
17767         case 'loose_item_start': {
17768           var body = '';
17769     
17770           while (this.next().type !== 'list_item_end') {
17771             body += this.tok();
17772           }
17773     
17774           return this.renderer.listitem(body);
17775         }
17776         case 'html': {
17777           var html = !this.token.pre && !this.options.pedantic
17778             ? this.inline.output(this.token.text)
17779             : this.token.text;
17780           return this.renderer.html(html);
17781         }
17782         case 'paragraph': {
17783           return this.renderer.paragraph(this.inline.output(this.token.text));
17784         }
17785         case 'text': {
17786           return this.renderer.paragraph(this.parseText());
17787         }
17788       }
17789     };
17790     
17791     /**
17792      * Helpers
17793      */
17794     
17795     function escape(html, encode) {
17796       return html
17797         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17798         .replace(/</g, '&lt;')
17799         .replace(/>/g, '&gt;')
17800         .replace(/"/g, '&quot;')
17801         .replace(/'/g, '&#39;');
17802     }
17803     
17804     function unescape(html) {
17805         // explicitly match decimal, hex, and named HTML entities 
17806       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17807         n = n.toLowerCase();
17808         if (n === 'colon') { return ':'; }
17809         if (n.charAt(0) === '#') {
17810           return n.charAt(1) === 'x'
17811             ? String.fromCharCode(parseInt(n.substring(2), 16))
17812             : String.fromCharCode(+n.substring(1));
17813         }
17814         return '';
17815       });
17816     }
17817     
17818     function replace(regex, opt) {
17819       regex = regex.source;
17820       opt = opt || '';
17821       return function self(name, val) {
17822         if (!name) { return new RegExp(regex, opt); }
17823         val = val.source || val;
17824         val = val.replace(/(^|[^\[])\^/g, '$1');
17825         regex = regex.replace(name, val);
17826         return self;
17827       };
17828     }
17829     
17830     function noop() {}
17831     noop.exec = noop;
17832     
17833     function merge(obj) {
17834       var i = 1
17835         , target
17836         , key;
17837     
17838       for (; i < arguments.length; i++) {
17839         target = arguments[i];
17840         for (key in target) {
17841           if (Object.prototype.hasOwnProperty.call(target, key)) {
17842             obj[key] = target[key];
17843           }
17844         }
17845       }
17846     
17847       return obj;
17848     }
17849     
17850     
17851     /**
17852      * Marked
17853      */
17854     
17855     function marked(src, opt, callback) {
17856       if (callback || typeof opt === 'function') {
17857         if (!callback) {
17858           callback = opt;
17859           opt = null;
17860         }
17861     
17862         opt = merge({}, marked.defaults, opt || {});
17863     
17864         var highlight = opt.highlight
17865           , tokens
17866           , pending
17867           , i = 0;
17868     
17869         try {
17870           tokens = Lexer.lex(src, opt)
17871         } catch (e) {
17872           return callback(e);
17873         }
17874     
17875         pending = tokens.length;
17876     
17877         var done = function(err) {
17878           if (err) {
17879             opt.highlight = highlight;
17880             return callback(err);
17881           }
17882     
17883           var out;
17884     
17885           try {
17886             out = Parser.parse(tokens, opt);
17887           } catch (e) {
17888             err = e;
17889           }
17890     
17891           opt.highlight = highlight;
17892     
17893           return err
17894             ? callback(err)
17895             : callback(null, out);
17896         };
17897     
17898         if (!highlight || highlight.length < 3) {
17899           return done();
17900         }
17901     
17902         delete opt.highlight;
17903     
17904         if (!pending) { return done(); }
17905     
17906         for (; i < tokens.length; i++) {
17907           (function(token) {
17908             if (token.type !== 'code') {
17909               return --pending || done();
17910             }
17911             return highlight(token.text, token.lang, function(err, code) {
17912               if (err) { return done(err); }
17913               if (code == null || code === token.text) {
17914                 return --pending || done();
17915               }
17916               token.text = code;
17917               token.escaped = true;
17918               --pending || done();
17919             });
17920           })(tokens[i]);
17921         }
17922     
17923         return;
17924       }
17925       try {
17926         if (opt) { opt = merge({}, marked.defaults, opt); }
17927         return Parser.parse(Lexer.lex(src, opt), opt);
17928       } catch (e) {
17929         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17930         if ((opt || marked.defaults).silent) {
17931           return '<p>An error occured:</p><pre>'
17932             + escape(e.message + '', true)
17933             + '</pre>';
17934         }
17935         throw e;
17936       }
17937     }
17938     
17939     /**
17940      * Options
17941      */
17942     
17943     marked.options =
17944     marked.setOptions = function(opt) {
17945       merge(marked.defaults, opt);
17946       return marked;
17947     };
17948     
17949     marked.defaults = {
17950       gfm: true,
17951       tables: true,
17952       breaks: false,
17953       pedantic: false,
17954       sanitize: false,
17955       sanitizer: null,
17956       mangle: true,
17957       smartLists: false,
17958       silent: false,
17959       highlight: null,
17960       langPrefix: 'lang-',
17961       smartypants: false,
17962       headerPrefix: '',
17963       renderer: new Renderer,
17964       xhtml: false
17965     };
17966     
17967     /**
17968      * Expose
17969      */
17970     
17971     marked.Parser = Parser;
17972     marked.parser = Parser.parse;
17973     
17974     marked.Renderer = Renderer;
17975     
17976     marked.Lexer = Lexer;
17977     marked.lexer = Lexer.lex;
17978     
17979     marked.InlineLexer = InlineLexer;
17980     marked.inlineLexer = InlineLexer.output;
17981     
17982     marked.parse = marked;
17983     
17984     Roo.Markdown.marked = marked;
17985
17986 })();/*
17987  * Based on:
17988  * Ext JS Library 1.1.1
17989  * Copyright(c) 2006-2007, Ext JS, LLC.
17990  *
17991  * Originally Released Under LGPL - original licence link has changed is not relivant.
17992  *
17993  * Fork - LGPL
17994  * <script type="text/javascript">
17995  */
17996
17997
17998
17999 /*
18000  * These classes are derivatives of the similarly named classes in the YUI Library.
18001  * The original license:
18002  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18003  * Code licensed under the BSD License:
18004  * http://developer.yahoo.net/yui/license.txt
18005  */
18006
18007 (function() {
18008
18009 var Event=Roo.EventManager;
18010 var Dom=Roo.lib.Dom;
18011
18012 /**
18013  * @class Roo.dd.DragDrop
18014  * @extends Roo.util.Observable
18015  * Defines the interface and base operation of items that that can be
18016  * dragged or can be drop targets.  It was designed to be extended, overriding
18017  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18018  * Up to three html elements can be associated with a DragDrop instance:
18019  * <ul>
18020  * <li>linked element: the element that is passed into the constructor.
18021  * This is the element which defines the boundaries for interaction with
18022  * other DragDrop objects.</li>
18023  * <li>handle element(s): The drag operation only occurs if the element that
18024  * was clicked matches a handle element.  By default this is the linked
18025  * element, but there are times that you will want only a portion of the
18026  * linked element to initiate the drag operation, and the setHandleElId()
18027  * method provides a way to define this.</li>
18028  * <li>drag element: this represents the element that would be moved along
18029  * with the cursor during a drag operation.  By default, this is the linked
18030  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18031  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18032  * </li>
18033  * </ul>
18034  * This class should not be instantiated until the onload event to ensure that
18035  * the associated elements are available.
18036  * The following would define a DragDrop obj that would interact with any
18037  * other DragDrop obj in the "group1" group:
18038  * <pre>
18039  *  dd = new Roo.dd.DragDrop("div1", "group1");
18040  * </pre>
18041  * Since none of the event handlers have been implemented, nothing would
18042  * actually happen if you were to run the code above.  Normally you would
18043  * override this class or one of the default implementations, but you can
18044  * also override the methods you want on an instance of the class...
18045  * <pre>
18046  *  dd.onDragDrop = function(e, id) {
18047  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18048  *  }
18049  * </pre>
18050  * @constructor
18051  * @param {String} id of the element that is linked to this instance
18052  * @param {String} sGroup the group of related DragDrop objects
18053  * @param {object} config an object containing configurable attributes
18054  *                Valid properties for DragDrop:
18055  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18056  */
18057 Roo.dd.DragDrop = function(id, sGroup, config) {
18058     if (id) {
18059         this.init(id, sGroup, config);
18060     }
18061     
18062 };
18063
18064 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18065
18066     /**
18067      * The id of the element associated with this object.  This is what we
18068      * refer to as the "linked element" because the size and position of
18069      * this element is used to determine when the drag and drop objects have
18070      * interacted.
18071      * @property id
18072      * @type String
18073      */
18074     id: null,
18075
18076     /**
18077      * Configuration attributes passed into the constructor
18078      * @property config
18079      * @type object
18080      */
18081     config: null,
18082
18083     /**
18084      * The id of the element that will be dragged.  By default this is same
18085      * as the linked element , but could be changed to another element. Ex:
18086      * Roo.dd.DDProxy
18087      * @property dragElId
18088      * @type String
18089      * @private
18090      */
18091     dragElId: null,
18092
18093     /**
18094      * the id of the element that initiates the drag operation.  By default
18095      * this is the linked element, but could be changed to be a child of this
18096      * element.  This lets us do things like only starting the drag when the
18097      * header element within the linked html element is clicked.
18098      * @property handleElId
18099      * @type String
18100      * @private
18101      */
18102     handleElId: null,
18103
18104     /**
18105      * An associative array of HTML tags that will be ignored if clicked.
18106      * @property invalidHandleTypes
18107      * @type {string: string}
18108      */
18109     invalidHandleTypes: null,
18110
18111     /**
18112      * An associative array of ids for elements that will be ignored if clicked
18113      * @property invalidHandleIds
18114      * @type {string: string}
18115      */
18116     invalidHandleIds: null,
18117
18118     /**
18119      * An indexted array of css class names for elements that will be ignored
18120      * if clicked.
18121      * @property invalidHandleClasses
18122      * @type string[]
18123      */
18124     invalidHandleClasses: null,
18125
18126     /**
18127      * The linked element's absolute X position at the time the drag was
18128      * started
18129      * @property startPageX
18130      * @type int
18131      * @private
18132      */
18133     startPageX: 0,
18134
18135     /**
18136      * The linked element's absolute X position at the time the drag was
18137      * started
18138      * @property startPageY
18139      * @type int
18140      * @private
18141      */
18142     startPageY: 0,
18143
18144     /**
18145      * The group defines a logical collection of DragDrop objects that are
18146      * related.  Instances only get events when interacting with other
18147      * DragDrop object in the same group.  This lets us define multiple
18148      * groups using a single DragDrop subclass if we want.
18149      * @property groups
18150      * @type {string: string}
18151      */
18152     groups: null,
18153
18154     /**
18155      * Individual drag/drop instances can be locked.  This will prevent
18156      * onmousedown start drag.
18157      * @property locked
18158      * @type boolean
18159      * @private
18160      */
18161     locked: false,
18162
18163     /**
18164      * Lock this instance
18165      * @method lock
18166      */
18167     lock: function() { this.locked = true; },
18168
18169     /**
18170      * Unlock this instace
18171      * @method unlock
18172      */
18173     unlock: function() { this.locked = false; },
18174
18175     /**
18176      * By default, all insances can be a drop target.  This can be disabled by
18177      * setting isTarget to false.
18178      * @method isTarget
18179      * @type boolean
18180      */
18181     isTarget: true,
18182
18183     /**
18184      * The padding configured for this drag and drop object for calculating
18185      * the drop zone intersection with this object.
18186      * @method padding
18187      * @type int[]
18188      */
18189     padding: null,
18190
18191     /**
18192      * Cached reference to the linked element
18193      * @property _domRef
18194      * @private
18195      */
18196     _domRef: null,
18197
18198     /**
18199      * Internal typeof flag
18200      * @property __ygDragDrop
18201      * @private
18202      */
18203     __ygDragDrop: true,
18204
18205     /**
18206      * Set to true when horizontal contraints are applied
18207      * @property constrainX
18208      * @type boolean
18209      * @private
18210      */
18211     constrainX: false,
18212
18213     /**
18214      * Set to true when vertical contraints are applied
18215      * @property constrainY
18216      * @type boolean
18217      * @private
18218      */
18219     constrainY: false,
18220
18221     /**
18222      * The left constraint
18223      * @property minX
18224      * @type int
18225      * @private
18226      */
18227     minX: 0,
18228
18229     /**
18230      * The right constraint
18231      * @property maxX
18232      * @type int
18233      * @private
18234      */
18235     maxX: 0,
18236
18237     /**
18238      * The up constraint
18239      * @property minY
18240      * @type int
18241      * @type int
18242      * @private
18243      */
18244     minY: 0,
18245
18246     /**
18247      * The down constraint
18248      * @property maxY
18249      * @type int
18250      * @private
18251      */
18252     maxY: 0,
18253
18254     /**
18255      * Maintain offsets when we resetconstraints.  Set to true when you want
18256      * the position of the element relative to its parent to stay the same
18257      * when the page changes
18258      *
18259      * @property maintainOffset
18260      * @type boolean
18261      */
18262     maintainOffset: false,
18263
18264     /**
18265      * Array of pixel locations the element will snap to if we specified a
18266      * horizontal graduation/interval.  This array is generated automatically
18267      * when you define a tick interval.
18268      * @property xTicks
18269      * @type int[]
18270      */
18271     xTicks: null,
18272
18273     /**
18274      * Array of pixel locations the element will snap to if we specified a
18275      * vertical graduation/interval.  This array is generated automatically
18276      * when you define a tick interval.
18277      * @property yTicks
18278      * @type int[]
18279      */
18280     yTicks: null,
18281
18282     /**
18283      * By default the drag and drop instance will only respond to the primary
18284      * button click (left button for a right-handed mouse).  Set to true to
18285      * allow drag and drop to start with any mouse click that is propogated
18286      * by the browser
18287      * @property primaryButtonOnly
18288      * @type boolean
18289      */
18290     primaryButtonOnly: true,
18291
18292     /**
18293      * The availabe property is false until the linked dom element is accessible.
18294      * @property available
18295      * @type boolean
18296      */
18297     available: false,
18298
18299     /**
18300      * By default, drags can only be initiated if the mousedown occurs in the
18301      * region the linked element is.  This is done in part to work around a
18302      * bug in some browsers that mis-report the mousedown if the previous
18303      * mouseup happened outside of the window.  This property is set to true
18304      * if outer handles are defined.
18305      *
18306      * @property hasOuterHandles
18307      * @type boolean
18308      * @default false
18309      */
18310     hasOuterHandles: false,
18311
18312     /**
18313      * Code that executes immediately before the startDrag event
18314      * @method b4StartDrag
18315      * @private
18316      */
18317     b4StartDrag: function(x, y) { },
18318
18319     /**
18320      * Abstract method called after a drag/drop object is clicked
18321      * and the drag or mousedown time thresholds have beeen met.
18322      * @method startDrag
18323      * @param {int} X click location
18324      * @param {int} Y click location
18325      */
18326     startDrag: function(x, y) { /* override this */ },
18327
18328     /**
18329      * Code that executes immediately before the onDrag event
18330      * @method b4Drag
18331      * @private
18332      */
18333     b4Drag: function(e) { },
18334
18335     /**
18336      * Abstract method called during the onMouseMove event while dragging an
18337      * object.
18338      * @method onDrag
18339      * @param {Event} e the mousemove event
18340      */
18341     onDrag: function(e) { /* override this */ },
18342
18343     /**
18344      * Abstract method called when this element fist begins hovering over
18345      * another DragDrop obj
18346      * @method onDragEnter
18347      * @param {Event} e the mousemove event
18348      * @param {String|DragDrop[]} id In POINT mode, the element
18349      * id this is hovering over.  In INTERSECT mode, an array of one or more
18350      * dragdrop items being hovered over.
18351      */
18352     onDragEnter: function(e, id) { /* override this */ },
18353
18354     /**
18355      * Code that executes immediately before the onDragOver event
18356      * @method b4DragOver
18357      * @private
18358      */
18359     b4DragOver: function(e) { },
18360
18361     /**
18362      * Abstract method called when this element is hovering over another
18363      * DragDrop obj
18364      * @method onDragOver
18365      * @param {Event} e the mousemove event
18366      * @param {String|DragDrop[]} id In POINT mode, the element
18367      * id this is hovering over.  In INTERSECT mode, an array of dd items
18368      * being hovered over.
18369      */
18370     onDragOver: function(e, id) { /* override this */ },
18371
18372     /**
18373      * Code that executes immediately before the onDragOut event
18374      * @method b4DragOut
18375      * @private
18376      */
18377     b4DragOut: function(e) { },
18378
18379     /**
18380      * Abstract method called when we are no longer hovering over an element
18381      * @method onDragOut
18382      * @param {Event} e the mousemove event
18383      * @param {String|DragDrop[]} id In POINT mode, the element
18384      * id this was hovering over.  In INTERSECT mode, an array of dd items
18385      * that the mouse is no longer over.
18386      */
18387     onDragOut: function(e, id) { /* override this */ },
18388
18389     /**
18390      * Code that executes immediately before the onDragDrop event
18391      * @method b4DragDrop
18392      * @private
18393      */
18394     b4DragDrop: function(e) { },
18395
18396     /**
18397      * Abstract method called when this item is dropped on another DragDrop
18398      * obj
18399      * @method onDragDrop
18400      * @param {Event} e the mouseup event
18401      * @param {String|DragDrop[]} id In POINT mode, the element
18402      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18403      * was dropped on.
18404      */
18405     onDragDrop: function(e, id) { /* override this */ },
18406
18407     /**
18408      * Abstract method called when this item is dropped on an area with no
18409      * drop target
18410      * @method onInvalidDrop
18411      * @param {Event} e the mouseup event
18412      */
18413     onInvalidDrop: function(e) { /* override this */ },
18414
18415     /**
18416      * Code that executes immediately before the endDrag event
18417      * @method b4EndDrag
18418      * @private
18419      */
18420     b4EndDrag: function(e) { },
18421
18422     /**
18423      * Fired when we are done dragging the object
18424      * @method endDrag
18425      * @param {Event} e the mouseup event
18426      */
18427     endDrag: function(e) { /* override this */ },
18428
18429     /**
18430      * Code executed immediately before the onMouseDown event
18431      * @method b4MouseDown
18432      * @param {Event} e the mousedown event
18433      * @private
18434      */
18435     b4MouseDown: function(e) {  },
18436
18437     /**
18438      * Event handler that fires when a drag/drop obj gets a mousedown
18439      * @method onMouseDown
18440      * @param {Event} e the mousedown event
18441      */
18442     onMouseDown: function(e) { /* override this */ },
18443
18444     /**
18445      * Event handler that fires when a drag/drop obj gets a mouseup
18446      * @method onMouseUp
18447      * @param {Event} e the mouseup event
18448      */
18449     onMouseUp: function(e) { /* override this */ },
18450
18451     /**
18452      * Override the onAvailable method to do what is needed after the initial
18453      * position was determined.
18454      * @method onAvailable
18455      */
18456     onAvailable: function () {
18457     },
18458
18459     /*
18460      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18461      * @type Object
18462      */
18463     defaultPadding : {left:0, right:0, top:0, bottom:0},
18464
18465     /*
18466      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18467  *
18468  * Usage:
18469  <pre><code>
18470  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18471                 { dragElId: "existingProxyDiv" });
18472  dd.startDrag = function(){
18473      this.constrainTo("parent-id");
18474  };
18475  </code></pre>
18476  * Or you can initalize it using the {@link Roo.Element} object:
18477  <pre><code>
18478  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18479      startDrag : function(){
18480          this.constrainTo("parent-id");
18481      }
18482  });
18483  </code></pre>
18484      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18485      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18486      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18487      * an object containing the sides to pad. For example: {right:10, bottom:10}
18488      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18489      */
18490     constrainTo : function(constrainTo, pad, inContent){
18491         if(typeof pad == "number"){
18492             pad = {left: pad, right:pad, top:pad, bottom:pad};
18493         }
18494         pad = pad || this.defaultPadding;
18495         var b = Roo.get(this.getEl()).getBox();
18496         var ce = Roo.get(constrainTo);
18497         var s = ce.getScroll();
18498         var c, cd = ce.dom;
18499         if(cd == document.body){
18500             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18501         }else{
18502             xy = ce.getXY();
18503             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18504         }
18505
18506
18507         var topSpace = b.y - c.y;
18508         var leftSpace = b.x - c.x;
18509
18510         this.resetConstraints();
18511         this.setXConstraint(leftSpace - (pad.left||0), // left
18512                 c.width - leftSpace - b.width - (pad.right||0) //right
18513         );
18514         this.setYConstraint(topSpace - (pad.top||0), //top
18515                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18516         );
18517     },
18518
18519     /**
18520      * Returns a reference to the linked element
18521      * @method getEl
18522      * @return {HTMLElement} the html element
18523      */
18524     getEl: function() {
18525         if (!this._domRef) {
18526             this._domRef = Roo.getDom(this.id);
18527         }
18528
18529         return this._domRef;
18530     },
18531
18532     /**
18533      * Returns a reference to the actual element to drag.  By default this is
18534      * the same as the html element, but it can be assigned to another
18535      * element. An example of this can be found in Roo.dd.DDProxy
18536      * @method getDragEl
18537      * @return {HTMLElement} the html element
18538      */
18539     getDragEl: function() {
18540         return Roo.getDom(this.dragElId);
18541     },
18542
18543     /**
18544      * Sets up the DragDrop object.  Must be called in the constructor of any
18545      * Roo.dd.DragDrop subclass
18546      * @method init
18547      * @param id the id of the linked element
18548      * @param {String} sGroup the group of related items
18549      * @param {object} config configuration attributes
18550      */
18551     init: function(id, sGroup, config) {
18552         this.initTarget(id, sGroup, config);
18553         if (!Roo.isTouch) {
18554             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18555         }
18556         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18557         // Event.on(this.id, "selectstart", Event.preventDefault);
18558     },
18559
18560     /**
18561      * Initializes Targeting functionality only... the object does not
18562      * get a mousedown handler.
18563      * @method initTarget
18564      * @param id the id of the linked element
18565      * @param {String} sGroup the group of related items
18566      * @param {object} config configuration attributes
18567      */
18568     initTarget: function(id, sGroup, config) {
18569
18570         // configuration attributes
18571         this.config = config || {};
18572
18573         // create a local reference to the drag and drop manager
18574         this.DDM = Roo.dd.DDM;
18575         // initialize the groups array
18576         this.groups = {};
18577
18578         // assume that we have an element reference instead of an id if the
18579         // parameter is not a string
18580         if (typeof id !== "string") {
18581             id = Roo.id(id);
18582         }
18583
18584         // set the id
18585         this.id = id;
18586
18587         // add to an interaction group
18588         this.addToGroup((sGroup) ? sGroup : "default");
18589
18590         // We don't want to register this as the handle with the manager
18591         // so we just set the id rather than calling the setter.
18592         this.handleElId = id;
18593
18594         // the linked element is the element that gets dragged by default
18595         this.setDragElId(id);
18596
18597         // by default, clicked anchors will not start drag operations.
18598         this.invalidHandleTypes = { A: "A" };
18599         this.invalidHandleIds = {};
18600         this.invalidHandleClasses = [];
18601
18602         this.applyConfig();
18603
18604         this.handleOnAvailable();
18605     },
18606
18607     /**
18608      * Applies the configuration parameters that were passed into the constructor.
18609      * This is supposed to happen at each level through the inheritance chain.  So
18610      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18611      * DragDrop in order to get all of the parameters that are available in
18612      * each object.
18613      * @method applyConfig
18614      */
18615     applyConfig: function() {
18616
18617         // configurable properties:
18618         //    padding, isTarget, maintainOffset, primaryButtonOnly
18619         this.padding           = this.config.padding || [0, 0, 0, 0];
18620         this.isTarget          = (this.config.isTarget !== false);
18621         this.maintainOffset    = (this.config.maintainOffset);
18622         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18623
18624     },
18625
18626     /**
18627      * Executed when the linked element is available
18628      * @method handleOnAvailable
18629      * @private
18630      */
18631     handleOnAvailable: function() {
18632         this.available = true;
18633         this.resetConstraints();
18634         this.onAvailable();
18635     },
18636
18637      /**
18638      * Configures the padding for the target zone in px.  Effectively expands
18639      * (or reduces) the virtual object size for targeting calculations.
18640      * Supports css-style shorthand; if only one parameter is passed, all sides
18641      * will have that padding, and if only two are passed, the top and bottom
18642      * will have the first param, the left and right the second.
18643      * @method setPadding
18644      * @param {int} iTop    Top pad
18645      * @param {int} iRight  Right pad
18646      * @param {int} iBot    Bot pad
18647      * @param {int} iLeft   Left pad
18648      */
18649     setPadding: function(iTop, iRight, iBot, iLeft) {
18650         // this.padding = [iLeft, iRight, iTop, iBot];
18651         if (!iRight && 0 !== iRight) {
18652             this.padding = [iTop, iTop, iTop, iTop];
18653         } else if (!iBot && 0 !== iBot) {
18654             this.padding = [iTop, iRight, iTop, iRight];
18655         } else {
18656             this.padding = [iTop, iRight, iBot, iLeft];
18657         }
18658     },
18659
18660     /**
18661      * Stores the initial placement of the linked element.
18662      * @method setInitialPosition
18663      * @param {int} diffX   the X offset, default 0
18664      * @param {int} diffY   the Y offset, default 0
18665      */
18666     setInitPosition: function(diffX, diffY) {
18667         var el = this.getEl();
18668
18669         if (!this.DDM.verifyEl(el)) {
18670             return;
18671         }
18672
18673         var dx = diffX || 0;
18674         var dy = diffY || 0;
18675
18676         var p = Dom.getXY( el );
18677
18678         this.initPageX = p[0] - dx;
18679         this.initPageY = p[1] - dy;
18680
18681         this.lastPageX = p[0];
18682         this.lastPageY = p[1];
18683
18684
18685         this.setStartPosition(p);
18686     },
18687
18688     /**
18689      * Sets the start position of the element.  This is set when the obj
18690      * is initialized, the reset when a drag is started.
18691      * @method setStartPosition
18692      * @param pos current position (from previous lookup)
18693      * @private
18694      */
18695     setStartPosition: function(pos) {
18696         var p = pos || Dom.getXY( this.getEl() );
18697         this.deltaSetXY = null;
18698
18699         this.startPageX = p[0];
18700         this.startPageY = p[1];
18701     },
18702
18703     /**
18704      * Add this instance to a group of related drag/drop objects.  All
18705      * instances belong to at least one group, and can belong to as many
18706      * groups as needed.
18707      * @method addToGroup
18708      * @param sGroup {string} the name of the group
18709      */
18710     addToGroup: function(sGroup) {
18711         this.groups[sGroup] = true;
18712         this.DDM.regDragDrop(this, sGroup);
18713     },
18714
18715     /**
18716      * Remove's this instance from the supplied interaction group
18717      * @method removeFromGroup
18718      * @param {string}  sGroup  The group to drop
18719      */
18720     removeFromGroup: function(sGroup) {
18721         if (this.groups[sGroup]) {
18722             delete this.groups[sGroup];
18723         }
18724
18725         this.DDM.removeDDFromGroup(this, sGroup);
18726     },
18727
18728     /**
18729      * Allows you to specify that an element other than the linked element
18730      * will be moved with the cursor during a drag
18731      * @method setDragElId
18732      * @param id {string} the id of the element that will be used to initiate the drag
18733      */
18734     setDragElId: function(id) {
18735         this.dragElId = id;
18736     },
18737
18738     /**
18739      * Allows you to specify a child of the linked element that should be
18740      * used to initiate the drag operation.  An example of this would be if
18741      * you have a content div with text and links.  Clicking anywhere in the
18742      * content area would normally start the drag operation.  Use this method
18743      * to specify that an element inside of the content div is the element
18744      * that starts the drag operation.
18745      * @method setHandleElId
18746      * @param id {string} the id of the element that will be used to
18747      * initiate the drag.
18748      */
18749     setHandleElId: function(id) {
18750         if (typeof id !== "string") {
18751             id = Roo.id(id);
18752         }
18753         this.handleElId = id;
18754         this.DDM.regHandle(this.id, id);
18755     },
18756
18757     /**
18758      * Allows you to set an element outside of the linked element as a drag
18759      * handle
18760      * @method setOuterHandleElId
18761      * @param id the id of the element that will be used to initiate the drag
18762      */
18763     setOuterHandleElId: function(id) {
18764         if (typeof id !== "string") {
18765             id = Roo.id(id);
18766         }
18767         Event.on(id, "mousedown",
18768                 this.handleMouseDown, this);
18769         this.setHandleElId(id);
18770
18771         this.hasOuterHandles = true;
18772     },
18773
18774     /**
18775      * Remove all drag and drop hooks for this element
18776      * @method unreg
18777      */
18778     unreg: function() {
18779         Event.un(this.id, "mousedown",
18780                 this.handleMouseDown);
18781         Event.un(this.id, "touchstart",
18782                 this.handleMouseDown);
18783         this._domRef = null;
18784         this.DDM._remove(this);
18785     },
18786
18787     destroy : function(){
18788         this.unreg();
18789     },
18790
18791     /**
18792      * Returns true if this instance is locked, or the drag drop mgr is locked
18793      * (meaning that all drag/drop is disabled on the page.)
18794      * @method isLocked
18795      * @return {boolean} true if this obj or all drag/drop is locked, else
18796      * false
18797      */
18798     isLocked: function() {
18799         return (this.DDM.isLocked() || this.locked);
18800     },
18801
18802     /**
18803      * Fired when this object is clicked
18804      * @method handleMouseDown
18805      * @param {Event} e
18806      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18807      * @private
18808      */
18809     handleMouseDown: function(e, oDD){
18810      
18811         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18812             //Roo.log('not touch/ button !=0');
18813             return;
18814         }
18815         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18816             return; // double touch..
18817         }
18818         
18819
18820         if (this.isLocked()) {
18821             //Roo.log('locked');
18822             return;
18823         }
18824
18825         this.DDM.refreshCache(this.groups);
18826 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18827         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18828         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18829             //Roo.log('no outer handes or not over target');
18830                 // do nothing.
18831         } else {
18832 //            Roo.log('check validator');
18833             if (this.clickValidator(e)) {
18834 //                Roo.log('validate success');
18835                 // set the initial element position
18836                 this.setStartPosition();
18837
18838
18839                 this.b4MouseDown(e);
18840                 this.onMouseDown(e);
18841
18842                 this.DDM.handleMouseDown(e, this);
18843
18844                 this.DDM.stopEvent(e);
18845             } else {
18846
18847
18848             }
18849         }
18850     },
18851
18852     clickValidator: function(e) {
18853         var target = e.getTarget();
18854         return ( this.isValidHandleChild(target) &&
18855                     (this.id == this.handleElId ||
18856                         this.DDM.handleWasClicked(target, this.id)) );
18857     },
18858
18859     /**
18860      * Allows you to specify a tag name that should not start a drag operation
18861      * when clicked.  This is designed to facilitate embedding links within a
18862      * drag handle that do something other than start the drag.
18863      * @method addInvalidHandleType
18864      * @param {string} tagName the type of element to exclude
18865      */
18866     addInvalidHandleType: function(tagName) {
18867         var type = tagName.toUpperCase();
18868         this.invalidHandleTypes[type] = type;
18869     },
18870
18871     /**
18872      * Lets you to specify an element id for a child of a drag handle
18873      * that should not initiate a drag
18874      * @method addInvalidHandleId
18875      * @param {string} id the element id of the element you wish to ignore
18876      */
18877     addInvalidHandleId: function(id) {
18878         if (typeof id !== "string") {
18879             id = Roo.id(id);
18880         }
18881         this.invalidHandleIds[id] = id;
18882     },
18883
18884     /**
18885      * Lets you specify a css class of elements that will not initiate a drag
18886      * @method addInvalidHandleClass
18887      * @param {string} cssClass the class of the elements you wish to ignore
18888      */
18889     addInvalidHandleClass: function(cssClass) {
18890         this.invalidHandleClasses.push(cssClass);
18891     },
18892
18893     /**
18894      * Unsets an excluded tag name set by addInvalidHandleType
18895      * @method removeInvalidHandleType
18896      * @param {string} tagName the type of element to unexclude
18897      */
18898     removeInvalidHandleType: function(tagName) {
18899         var type = tagName.toUpperCase();
18900         // this.invalidHandleTypes[type] = null;
18901         delete this.invalidHandleTypes[type];
18902     },
18903
18904     /**
18905      * Unsets an invalid handle id
18906      * @method removeInvalidHandleId
18907      * @param {string} id the id of the element to re-enable
18908      */
18909     removeInvalidHandleId: function(id) {
18910         if (typeof id !== "string") {
18911             id = Roo.id(id);
18912         }
18913         delete this.invalidHandleIds[id];
18914     },
18915
18916     /**
18917      * Unsets an invalid css class
18918      * @method removeInvalidHandleClass
18919      * @param {string} cssClass the class of the element(s) you wish to
18920      * re-enable
18921      */
18922     removeInvalidHandleClass: function(cssClass) {
18923         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18924             if (this.invalidHandleClasses[i] == cssClass) {
18925                 delete this.invalidHandleClasses[i];
18926             }
18927         }
18928     },
18929
18930     /**
18931      * Checks the tag exclusion list to see if this click should be ignored
18932      * @method isValidHandleChild
18933      * @param {HTMLElement} node the HTMLElement to evaluate
18934      * @return {boolean} true if this is a valid tag type, false if not
18935      */
18936     isValidHandleChild: function(node) {
18937
18938         var valid = true;
18939         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18940         var nodeName;
18941         try {
18942             nodeName = node.nodeName.toUpperCase();
18943         } catch(e) {
18944             nodeName = node.nodeName;
18945         }
18946         valid = valid && !this.invalidHandleTypes[nodeName];
18947         valid = valid && !this.invalidHandleIds[node.id];
18948
18949         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18950             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18951         }
18952
18953
18954         return valid;
18955
18956     },
18957
18958     /**
18959      * Create the array of horizontal tick marks if an interval was specified
18960      * in setXConstraint().
18961      * @method setXTicks
18962      * @private
18963      */
18964     setXTicks: function(iStartX, iTickSize) {
18965         this.xTicks = [];
18966         this.xTickSize = iTickSize;
18967
18968         var tickMap = {};
18969
18970         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18971             if (!tickMap[i]) {
18972                 this.xTicks[this.xTicks.length] = i;
18973                 tickMap[i] = true;
18974             }
18975         }
18976
18977         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18978             if (!tickMap[i]) {
18979                 this.xTicks[this.xTicks.length] = i;
18980                 tickMap[i] = true;
18981             }
18982         }
18983
18984         this.xTicks.sort(this.DDM.numericSort) ;
18985     },
18986
18987     /**
18988      * Create the array of vertical tick marks if an interval was specified in
18989      * setYConstraint().
18990      * @method setYTicks
18991      * @private
18992      */
18993     setYTicks: function(iStartY, iTickSize) {
18994         this.yTicks = [];
18995         this.yTickSize = iTickSize;
18996
18997         var tickMap = {};
18998
18999         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19000             if (!tickMap[i]) {
19001                 this.yTicks[this.yTicks.length] = i;
19002                 tickMap[i] = true;
19003             }
19004         }
19005
19006         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19007             if (!tickMap[i]) {
19008                 this.yTicks[this.yTicks.length] = i;
19009                 tickMap[i] = true;
19010             }
19011         }
19012
19013         this.yTicks.sort(this.DDM.numericSort) ;
19014     },
19015
19016     /**
19017      * By default, the element can be dragged any place on the screen.  Use
19018      * this method to limit the horizontal travel of the element.  Pass in
19019      * 0,0 for the parameters if you want to lock the drag to the y axis.
19020      * @method setXConstraint
19021      * @param {int} iLeft the number of pixels the element can move to the left
19022      * @param {int} iRight the number of pixels the element can move to the
19023      * right
19024      * @param {int} iTickSize optional parameter for specifying that the
19025      * element
19026      * should move iTickSize pixels at a time.
19027      */
19028     setXConstraint: function(iLeft, iRight, iTickSize) {
19029         this.leftConstraint = iLeft;
19030         this.rightConstraint = iRight;
19031
19032         this.minX = this.initPageX - iLeft;
19033         this.maxX = this.initPageX + iRight;
19034         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19035
19036         this.constrainX = true;
19037     },
19038
19039     /**
19040      * Clears any constraints applied to this instance.  Also clears ticks
19041      * since they can't exist independent of a constraint at this time.
19042      * @method clearConstraints
19043      */
19044     clearConstraints: function() {
19045         this.constrainX = false;
19046         this.constrainY = false;
19047         this.clearTicks();
19048     },
19049
19050     /**
19051      * Clears any tick interval defined for this instance
19052      * @method clearTicks
19053      */
19054     clearTicks: function() {
19055         this.xTicks = null;
19056         this.yTicks = null;
19057         this.xTickSize = 0;
19058         this.yTickSize = 0;
19059     },
19060
19061     /**
19062      * By default, the element can be dragged any place on the screen.  Set
19063      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19064      * parameters if you want to lock the drag to the x axis.
19065      * @method setYConstraint
19066      * @param {int} iUp the number of pixels the element can move up
19067      * @param {int} iDown the number of pixels the element can move down
19068      * @param {int} iTickSize optional parameter for specifying that the
19069      * element should move iTickSize pixels at a time.
19070      */
19071     setYConstraint: function(iUp, iDown, iTickSize) {
19072         this.topConstraint = iUp;
19073         this.bottomConstraint = iDown;
19074
19075         this.minY = this.initPageY - iUp;
19076         this.maxY = this.initPageY + iDown;
19077         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19078
19079         this.constrainY = true;
19080
19081     },
19082
19083     /**
19084      * resetConstraints must be called if you manually reposition a dd element.
19085      * @method resetConstraints
19086      * @param {boolean} maintainOffset
19087      */
19088     resetConstraints: function() {
19089
19090
19091         // Maintain offsets if necessary
19092         if (this.initPageX || this.initPageX === 0) {
19093             // figure out how much this thing has moved
19094             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19095             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19096
19097             this.setInitPosition(dx, dy);
19098
19099         // This is the first time we have detected the element's position
19100         } else {
19101             this.setInitPosition();
19102         }
19103
19104         if (this.constrainX) {
19105             this.setXConstraint( this.leftConstraint,
19106                                  this.rightConstraint,
19107                                  this.xTickSize        );
19108         }
19109
19110         if (this.constrainY) {
19111             this.setYConstraint( this.topConstraint,
19112                                  this.bottomConstraint,
19113                                  this.yTickSize         );
19114         }
19115     },
19116
19117     /**
19118      * Normally the drag element is moved pixel by pixel, but we can specify
19119      * that it move a number of pixels at a time.  This method resolves the
19120      * location when we have it set up like this.
19121      * @method getTick
19122      * @param {int} val where we want to place the object
19123      * @param {int[]} tickArray sorted array of valid points
19124      * @return {int} the closest tick
19125      * @private
19126      */
19127     getTick: function(val, tickArray) {
19128
19129         if (!tickArray) {
19130             // If tick interval is not defined, it is effectively 1 pixel,
19131             // so we return the value passed to us.
19132             return val;
19133         } else if (tickArray[0] >= val) {
19134             // The value is lower than the first tick, so we return the first
19135             // tick.
19136             return tickArray[0];
19137         } else {
19138             for (var i=0, len=tickArray.length; i<len; ++i) {
19139                 var next = i + 1;
19140                 if (tickArray[next] && tickArray[next] >= val) {
19141                     var diff1 = val - tickArray[i];
19142                     var diff2 = tickArray[next] - val;
19143                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19144                 }
19145             }
19146
19147             // The value is larger than the last tick, so we return the last
19148             // tick.
19149             return tickArray[tickArray.length - 1];
19150         }
19151     },
19152
19153     /**
19154      * toString method
19155      * @method toString
19156      * @return {string} string representation of the dd obj
19157      */
19158     toString: function() {
19159         return ("DragDrop " + this.id);
19160     }
19161
19162 });
19163
19164 })();
19165 /*
19166  * Based on:
19167  * Ext JS Library 1.1.1
19168  * Copyright(c) 2006-2007, Ext JS, LLC.
19169  *
19170  * Originally Released Under LGPL - original licence link has changed is not relivant.
19171  *
19172  * Fork - LGPL
19173  * <script type="text/javascript">
19174  */
19175
19176
19177 /**
19178  * The drag and drop utility provides a framework for building drag and drop
19179  * applications.  In addition to enabling drag and drop for specific elements,
19180  * the drag and drop elements are tracked by the manager class, and the
19181  * interactions between the various elements are tracked during the drag and
19182  * the implementing code is notified about these important moments.
19183  */
19184
19185 // Only load the library once.  Rewriting the manager class would orphan
19186 // existing drag and drop instances.
19187 if (!Roo.dd.DragDropMgr) {
19188
19189 /**
19190  * @class Roo.dd.DragDropMgr
19191  * DragDropMgr is a singleton that tracks the element interaction for
19192  * all DragDrop items in the window.  Generally, you will not call
19193  * this class directly, but it does have helper methods that could
19194  * be useful in your DragDrop implementations.
19195  * @singleton
19196  */
19197 Roo.dd.DragDropMgr = function() {
19198
19199     var Event = Roo.EventManager;
19200
19201     return {
19202
19203         /**
19204          * Two dimensional Array of registered DragDrop objects.  The first
19205          * dimension is the DragDrop item group, the second the DragDrop
19206          * object.
19207          * @property ids
19208          * @type {string: string}
19209          * @private
19210          * @static
19211          */
19212         ids: {},
19213
19214         /**
19215          * Array of element ids defined as drag handles.  Used to determine
19216          * if the element that generated the mousedown event is actually the
19217          * handle and not the html element itself.
19218          * @property handleIds
19219          * @type {string: string}
19220          * @private
19221          * @static
19222          */
19223         handleIds: {},
19224
19225         /**
19226          * the DragDrop object that is currently being dragged
19227          * @property dragCurrent
19228          * @type DragDrop
19229          * @private
19230          * @static
19231          **/
19232         dragCurrent: null,
19233
19234         /**
19235          * the DragDrop object(s) that are being hovered over
19236          * @property dragOvers
19237          * @type Array
19238          * @private
19239          * @static
19240          */
19241         dragOvers: {},
19242
19243         /**
19244          * the X distance between the cursor and the object being dragged
19245          * @property deltaX
19246          * @type int
19247          * @private
19248          * @static
19249          */
19250         deltaX: 0,
19251
19252         /**
19253          * the Y distance between the cursor and the object being dragged
19254          * @property deltaY
19255          * @type int
19256          * @private
19257          * @static
19258          */
19259         deltaY: 0,
19260
19261         /**
19262          * Flag to determine if we should prevent the default behavior of the
19263          * events we define. By default this is true, but this can be set to
19264          * false if you need the default behavior (not recommended)
19265          * @property preventDefault
19266          * @type boolean
19267          * @static
19268          */
19269         preventDefault: true,
19270
19271         /**
19272          * Flag to determine if we should stop the propagation of the events
19273          * we generate. This is true by default but you may want to set it to
19274          * false if the html element contains other features that require the
19275          * mouse click.
19276          * @property stopPropagation
19277          * @type boolean
19278          * @static
19279          */
19280         stopPropagation: true,
19281
19282         /**
19283          * Internal flag that is set to true when drag and drop has been
19284          * intialized
19285          * @property initialized
19286          * @private
19287          * @static
19288          */
19289         initalized: false,
19290
19291         /**
19292          * All drag and drop can be disabled.
19293          * @property locked
19294          * @private
19295          * @static
19296          */
19297         locked: false,
19298
19299         /**
19300          * Called the first time an element is registered.
19301          * @method init
19302          * @private
19303          * @static
19304          */
19305         init: function() {
19306             this.initialized = true;
19307         },
19308
19309         /**
19310          * In point mode, drag and drop interaction is defined by the
19311          * location of the cursor during the drag/drop
19312          * @property POINT
19313          * @type int
19314          * @static
19315          */
19316         POINT: 0,
19317
19318         /**
19319          * In intersect mode, drag and drop interactio nis defined by the
19320          * overlap of two or more drag and drop objects.
19321          * @property INTERSECT
19322          * @type int
19323          * @static
19324          */
19325         INTERSECT: 1,
19326
19327         /**
19328          * The current drag and drop mode.  Default: POINT
19329          * @property mode
19330          * @type int
19331          * @static
19332          */
19333         mode: 0,
19334
19335         /**
19336          * Runs method on all drag and drop objects
19337          * @method _execOnAll
19338          * @private
19339          * @static
19340          */
19341         _execOnAll: function(sMethod, args) {
19342             for (var i in this.ids) {
19343                 for (var j in this.ids[i]) {
19344                     var oDD = this.ids[i][j];
19345                     if (! this.isTypeOfDD(oDD)) {
19346                         continue;
19347                     }
19348                     oDD[sMethod].apply(oDD, args);
19349                 }
19350             }
19351         },
19352
19353         /**
19354          * Drag and drop initialization.  Sets up the global event handlers
19355          * @method _onLoad
19356          * @private
19357          * @static
19358          */
19359         _onLoad: function() {
19360
19361             this.init();
19362
19363             if (!Roo.isTouch) {
19364                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19365                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19366             }
19367             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19368             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19369             
19370             Event.on(window,   "unload",    this._onUnload, this, true);
19371             Event.on(window,   "resize",    this._onResize, this, true);
19372             // Event.on(window,   "mouseout",    this._test);
19373
19374         },
19375
19376         /**
19377          * Reset constraints on all drag and drop objs
19378          * @method _onResize
19379          * @private
19380          * @static
19381          */
19382         _onResize: function(e) {
19383             this._execOnAll("resetConstraints", []);
19384         },
19385
19386         /**
19387          * Lock all drag and drop functionality
19388          * @method lock
19389          * @static
19390          */
19391         lock: function() { this.locked = true; },
19392
19393         /**
19394          * Unlock all drag and drop functionality
19395          * @method unlock
19396          * @static
19397          */
19398         unlock: function() { this.locked = false; },
19399
19400         /**
19401          * Is drag and drop locked?
19402          * @method isLocked
19403          * @return {boolean} True if drag and drop is locked, false otherwise.
19404          * @static
19405          */
19406         isLocked: function() { return this.locked; },
19407
19408         /**
19409          * Location cache that is set for all drag drop objects when a drag is
19410          * initiated, cleared when the drag is finished.
19411          * @property locationCache
19412          * @private
19413          * @static
19414          */
19415         locationCache: {},
19416
19417         /**
19418          * Set useCache to false if you want to force object the lookup of each
19419          * drag and drop linked element constantly during a drag.
19420          * @property useCache
19421          * @type boolean
19422          * @static
19423          */
19424         useCache: true,
19425
19426         /**
19427          * The number of pixels that the mouse needs to move after the
19428          * mousedown before the drag is initiated.  Default=3;
19429          * @property clickPixelThresh
19430          * @type int
19431          * @static
19432          */
19433         clickPixelThresh: 3,
19434
19435         /**
19436          * The number of milliseconds after the mousedown event to initiate the
19437          * drag if we don't get a mouseup event. Default=1000
19438          * @property clickTimeThresh
19439          * @type int
19440          * @static
19441          */
19442         clickTimeThresh: 350,
19443
19444         /**
19445          * Flag that indicates that either the drag pixel threshold or the
19446          * mousdown time threshold has been met
19447          * @property dragThreshMet
19448          * @type boolean
19449          * @private
19450          * @static
19451          */
19452         dragThreshMet: false,
19453
19454         /**
19455          * Timeout used for the click time threshold
19456          * @property clickTimeout
19457          * @type Object
19458          * @private
19459          * @static
19460          */
19461         clickTimeout: null,
19462
19463         /**
19464          * The X position of the mousedown event stored for later use when a
19465          * drag threshold is met.
19466          * @property startX
19467          * @type int
19468          * @private
19469          * @static
19470          */
19471         startX: 0,
19472
19473         /**
19474          * The Y position of the mousedown event stored for later use when a
19475          * drag threshold is met.
19476          * @property startY
19477          * @type int
19478          * @private
19479          * @static
19480          */
19481         startY: 0,
19482
19483         /**
19484          * Each DragDrop instance must be registered with the DragDropMgr.
19485          * This is executed in DragDrop.init()
19486          * @method regDragDrop
19487          * @param {DragDrop} oDD the DragDrop object to register
19488          * @param {String} sGroup the name of the group this element belongs to
19489          * @static
19490          */
19491         regDragDrop: function(oDD, sGroup) {
19492             if (!this.initialized) { this.init(); }
19493
19494             if (!this.ids[sGroup]) {
19495                 this.ids[sGroup] = {};
19496             }
19497             this.ids[sGroup][oDD.id] = oDD;
19498         },
19499
19500         /**
19501          * Removes the supplied dd instance from the supplied group. Executed
19502          * by DragDrop.removeFromGroup, so don't call this function directly.
19503          * @method removeDDFromGroup
19504          * @private
19505          * @static
19506          */
19507         removeDDFromGroup: function(oDD, sGroup) {
19508             if (!this.ids[sGroup]) {
19509                 this.ids[sGroup] = {};
19510             }
19511
19512             var obj = this.ids[sGroup];
19513             if (obj && obj[oDD.id]) {
19514                 delete obj[oDD.id];
19515             }
19516         },
19517
19518         /**
19519          * Unregisters a drag and drop item.  This is executed in
19520          * DragDrop.unreg, use that method instead of calling this directly.
19521          * @method _remove
19522          * @private
19523          * @static
19524          */
19525         _remove: function(oDD) {
19526             for (var g in oDD.groups) {
19527                 if (g && this.ids[g][oDD.id]) {
19528                     delete this.ids[g][oDD.id];
19529                 }
19530             }
19531             delete this.handleIds[oDD.id];
19532         },
19533
19534         /**
19535          * Each DragDrop handle element must be registered.  This is done
19536          * automatically when executing DragDrop.setHandleElId()
19537          * @method regHandle
19538          * @param {String} sDDId the DragDrop id this element is a handle for
19539          * @param {String} sHandleId the id of the element that is the drag
19540          * handle
19541          * @static
19542          */
19543         regHandle: function(sDDId, sHandleId) {
19544             if (!this.handleIds[sDDId]) {
19545                 this.handleIds[sDDId] = {};
19546             }
19547             this.handleIds[sDDId][sHandleId] = sHandleId;
19548         },
19549
19550         /**
19551          * Utility function to determine if a given element has been
19552          * registered as a drag drop item.
19553          * @method isDragDrop
19554          * @param {String} id the element id to check
19555          * @return {boolean} true if this element is a DragDrop item,
19556          * false otherwise
19557          * @static
19558          */
19559         isDragDrop: function(id) {
19560             return ( this.getDDById(id) ) ? true : false;
19561         },
19562
19563         /**
19564          * Returns the drag and drop instances that are in all groups the
19565          * passed in instance belongs to.
19566          * @method getRelated
19567          * @param {DragDrop} p_oDD the obj to get related data for
19568          * @param {boolean} bTargetsOnly if true, only return targetable objs
19569          * @return {DragDrop[]} the related instances
19570          * @static
19571          */
19572         getRelated: function(p_oDD, bTargetsOnly) {
19573             var oDDs = [];
19574             for (var i in p_oDD.groups) {
19575                 for (j in this.ids[i]) {
19576                     var dd = this.ids[i][j];
19577                     if (! this.isTypeOfDD(dd)) {
19578                         continue;
19579                     }
19580                     if (!bTargetsOnly || dd.isTarget) {
19581                         oDDs[oDDs.length] = dd;
19582                     }
19583                 }
19584             }
19585
19586             return oDDs;
19587         },
19588
19589         /**
19590          * Returns true if the specified dd target is a legal target for
19591          * the specifice drag obj
19592          * @method isLegalTarget
19593          * @param {DragDrop} the drag obj
19594          * @param {DragDrop} the target
19595          * @return {boolean} true if the target is a legal target for the
19596          * dd obj
19597          * @static
19598          */
19599         isLegalTarget: function (oDD, oTargetDD) {
19600             var targets = this.getRelated(oDD, true);
19601             for (var i=0, len=targets.length;i<len;++i) {
19602                 if (targets[i].id == oTargetDD.id) {
19603                     return true;
19604                 }
19605             }
19606
19607             return false;
19608         },
19609
19610         /**
19611          * My goal is to be able to transparently determine if an object is
19612          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19613          * returns "object", oDD.constructor.toString() always returns
19614          * "DragDrop" and not the name of the subclass.  So for now it just
19615          * evaluates a well-known variable in DragDrop.
19616          * @method isTypeOfDD
19617          * @param {Object} the object to evaluate
19618          * @return {boolean} true if typeof oDD = DragDrop
19619          * @static
19620          */
19621         isTypeOfDD: function (oDD) {
19622             return (oDD && oDD.__ygDragDrop);
19623         },
19624
19625         /**
19626          * Utility function to determine if a given element has been
19627          * registered as a drag drop handle for the given Drag Drop object.
19628          * @method isHandle
19629          * @param {String} id the element id to check
19630          * @return {boolean} true if this element is a DragDrop handle, false
19631          * otherwise
19632          * @static
19633          */
19634         isHandle: function(sDDId, sHandleId) {
19635             return ( this.handleIds[sDDId] &&
19636                             this.handleIds[sDDId][sHandleId] );
19637         },
19638
19639         /**
19640          * Returns the DragDrop instance for a given id
19641          * @method getDDById
19642          * @param {String} id the id of the DragDrop object
19643          * @return {DragDrop} the drag drop object, null if it is not found
19644          * @static
19645          */
19646         getDDById: function(id) {
19647             for (var i in this.ids) {
19648                 if (this.ids[i][id]) {
19649                     return this.ids[i][id];
19650                 }
19651             }
19652             return null;
19653         },
19654
19655         /**
19656          * Fired after a registered DragDrop object gets the mousedown event.
19657          * Sets up the events required to track the object being dragged
19658          * @method handleMouseDown
19659          * @param {Event} e the event
19660          * @param oDD the DragDrop object being dragged
19661          * @private
19662          * @static
19663          */
19664         handleMouseDown: function(e, oDD) {
19665             if(Roo.QuickTips){
19666                 Roo.QuickTips.disable();
19667             }
19668             this.currentTarget = e.getTarget();
19669
19670             this.dragCurrent = oDD;
19671
19672             var el = oDD.getEl();
19673
19674             // track start position
19675             this.startX = e.getPageX();
19676             this.startY = e.getPageY();
19677
19678             this.deltaX = this.startX - el.offsetLeft;
19679             this.deltaY = this.startY - el.offsetTop;
19680
19681             this.dragThreshMet = false;
19682
19683             this.clickTimeout = setTimeout(
19684                     function() {
19685                         var DDM = Roo.dd.DDM;
19686                         DDM.startDrag(DDM.startX, DDM.startY);
19687                     },
19688                     this.clickTimeThresh );
19689         },
19690
19691         /**
19692          * Fired when either the drag pixel threshol or the mousedown hold
19693          * time threshold has been met.
19694          * @method startDrag
19695          * @param x {int} the X position of the original mousedown
19696          * @param y {int} the Y position of the original mousedown
19697          * @static
19698          */
19699         startDrag: function(x, y) {
19700             clearTimeout(this.clickTimeout);
19701             if (this.dragCurrent) {
19702                 this.dragCurrent.b4StartDrag(x, y);
19703                 this.dragCurrent.startDrag(x, y);
19704             }
19705             this.dragThreshMet = true;
19706         },
19707
19708         /**
19709          * Internal function to handle the mouseup event.  Will be invoked
19710          * from the context of the document.
19711          * @method handleMouseUp
19712          * @param {Event} e the event
19713          * @private
19714          * @static
19715          */
19716         handleMouseUp: function(e) {
19717
19718             if(Roo.QuickTips){
19719                 Roo.QuickTips.enable();
19720             }
19721             if (! this.dragCurrent) {
19722                 return;
19723             }
19724
19725             clearTimeout(this.clickTimeout);
19726
19727             if (this.dragThreshMet) {
19728                 this.fireEvents(e, true);
19729             } else {
19730             }
19731
19732             this.stopDrag(e);
19733
19734             this.stopEvent(e);
19735         },
19736
19737         /**
19738          * Utility to stop event propagation and event default, if these
19739          * features are turned on.
19740          * @method stopEvent
19741          * @param {Event} e the event as returned by this.getEvent()
19742          * @static
19743          */
19744         stopEvent: function(e){
19745             if(this.stopPropagation) {
19746                 e.stopPropagation();
19747             }
19748
19749             if (this.preventDefault) {
19750                 e.preventDefault();
19751             }
19752         },
19753
19754         /**
19755          * Internal function to clean up event handlers after the drag
19756          * operation is complete
19757          * @method stopDrag
19758          * @param {Event} e the event
19759          * @private
19760          * @static
19761          */
19762         stopDrag: function(e) {
19763             // Fire the drag end event for the item that was dragged
19764             if (this.dragCurrent) {
19765                 if (this.dragThreshMet) {
19766                     this.dragCurrent.b4EndDrag(e);
19767                     this.dragCurrent.endDrag(e);
19768                 }
19769
19770                 this.dragCurrent.onMouseUp(e);
19771             }
19772
19773             this.dragCurrent = null;
19774             this.dragOvers = {};
19775         },
19776
19777         /**
19778          * Internal function to handle the mousemove event.  Will be invoked
19779          * from the context of the html element.
19780          *
19781          * @TODO figure out what we can do about mouse events lost when the
19782          * user drags objects beyond the window boundary.  Currently we can
19783          * detect this in internet explorer by verifying that the mouse is
19784          * down during the mousemove event.  Firefox doesn't give us the
19785          * button state on the mousemove event.
19786          * @method handleMouseMove
19787          * @param {Event} e the event
19788          * @private
19789          * @static
19790          */
19791         handleMouseMove: function(e) {
19792             if (! this.dragCurrent) {
19793                 return true;
19794             }
19795
19796             // var button = e.which || e.button;
19797
19798             // check for IE mouseup outside of page boundary
19799             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19800                 this.stopEvent(e);
19801                 return this.handleMouseUp(e);
19802             }
19803
19804             if (!this.dragThreshMet) {
19805                 var diffX = Math.abs(this.startX - e.getPageX());
19806                 var diffY = Math.abs(this.startY - e.getPageY());
19807                 if (diffX > this.clickPixelThresh ||
19808                             diffY > this.clickPixelThresh) {
19809                     this.startDrag(this.startX, this.startY);
19810                 }
19811             }
19812
19813             if (this.dragThreshMet) {
19814                 this.dragCurrent.b4Drag(e);
19815                 this.dragCurrent.onDrag(e);
19816                 if(!this.dragCurrent.moveOnly){
19817                     this.fireEvents(e, false);
19818                 }
19819             }
19820
19821             this.stopEvent(e);
19822
19823             return true;
19824         },
19825
19826         /**
19827          * Iterates over all of the DragDrop elements to find ones we are
19828          * hovering over or dropping on
19829          * @method fireEvents
19830          * @param {Event} e the event
19831          * @param {boolean} isDrop is this a drop op or a mouseover op?
19832          * @private
19833          * @static
19834          */
19835         fireEvents: function(e, isDrop) {
19836             var dc = this.dragCurrent;
19837
19838             // If the user did the mouse up outside of the window, we could
19839             // get here even though we have ended the drag.
19840             if (!dc || dc.isLocked()) {
19841                 return;
19842             }
19843
19844             var pt = e.getPoint();
19845
19846             // cache the previous dragOver array
19847             var oldOvers = [];
19848
19849             var outEvts   = [];
19850             var overEvts  = [];
19851             var dropEvts  = [];
19852             var enterEvts = [];
19853
19854             // Check to see if the object(s) we were hovering over is no longer
19855             // being hovered over so we can fire the onDragOut event
19856             for (var i in this.dragOvers) {
19857
19858                 var ddo = this.dragOvers[i];
19859
19860                 if (! this.isTypeOfDD(ddo)) {
19861                     continue;
19862                 }
19863
19864                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19865                     outEvts.push( ddo );
19866                 }
19867
19868                 oldOvers[i] = true;
19869                 delete this.dragOvers[i];
19870             }
19871
19872             for (var sGroup in dc.groups) {
19873
19874                 if ("string" != typeof sGroup) {
19875                     continue;
19876                 }
19877
19878                 for (i in this.ids[sGroup]) {
19879                     var oDD = this.ids[sGroup][i];
19880                     if (! this.isTypeOfDD(oDD)) {
19881                         continue;
19882                     }
19883
19884                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19885                         if (this.isOverTarget(pt, oDD, this.mode)) {
19886                             // look for drop interactions
19887                             if (isDrop) {
19888                                 dropEvts.push( oDD );
19889                             // look for drag enter and drag over interactions
19890                             } else {
19891
19892                                 // initial drag over: dragEnter fires
19893                                 if (!oldOvers[oDD.id]) {
19894                                     enterEvts.push( oDD );
19895                                 // subsequent drag overs: dragOver fires
19896                                 } else {
19897                                     overEvts.push( oDD );
19898                                 }
19899
19900                                 this.dragOvers[oDD.id] = oDD;
19901                             }
19902                         }
19903                     }
19904                 }
19905             }
19906
19907             if (this.mode) {
19908                 if (outEvts.length) {
19909                     dc.b4DragOut(e, outEvts);
19910                     dc.onDragOut(e, outEvts);
19911                 }
19912
19913                 if (enterEvts.length) {
19914                     dc.onDragEnter(e, enterEvts);
19915                 }
19916
19917                 if (overEvts.length) {
19918                     dc.b4DragOver(e, overEvts);
19919                     dc.onDragOver(e, overEvts);
19920                 }
19921
19922                 if (dropEvts.length) {
19923                     dc.b4DragDrop(e, dropEvts);
19924                     dc.onDragDrop(e, dropEvts);
19925                 }
19926
19927             } else {
19928                 // fire dragout events
19929                 var len = 0;
19930                 for (i=0, len=outEvts.length; i<len; ++i) {
19931                     dc.b4DragOut(e, outEvts[i].id);
19932                     dc.onDragOut(e, outEvts[i].id);
19933                 }
19934
19935                 // fire enter events
19936                 for (i=0,len=enterEvts.length; i<len; ++i) {
19937                     // dc.b4DragEnter(e, oDD.id);
19938                     dc.onDragEnter(e, enterEvts[i].id);
19939                 }
19940
19941                 // fire over events
19942                 for (i=0,len=overEvts.length; i<len; ++i) {
19943                     dc.b4DragOver(e, overEvts[i].id);
19944                     dc.onDragOver(e, overEvts[i].id);
19945                 }
19946
19947                 // fire drop events
19948                 for (i=0, len=dropEvts.length; i<len; ++i) {
19949                     dc.b4DragDrop(e, dropEvts[i].id);
19950                     dc.onDragDrop(e, dropEvts[i].id);
19951                 }
19952
19953             }
19954
19955             // notify about a drop that did not find a target
19956             if (isDrop && !dropEvts.length) {
19957                 dc.onInvalidDrop(e);
19958             }
19959
19960         },
19961
19962         /**
19963          * Helper function for getting the best match from the list of drag
19964          * and drop objects returned by the drag and drop events when we are
19965          * in INTERSECT mode.  It returns either the first object that the
19966          * cursor is over, or the object that has the greatest overlap with
19967          * the dragged element.
19968          * @method getBestMatch
19969          * @param  {DragDrop[]} dds The array of drag and drop objects
19970          * targeted
19971          * @return {DragDrop}       The best single match
19972          * @static
19973          */
19974         getBestMatch: function(dds) {
19975             var winner = null;
19976             // Return null if the input is not what we expect
19977             //if (!dds || !dds.length || dds.length == 0) {
19978                // winner = null;
19979             // If there is only one item, it wins
19980             //} else if (dds.length == 1) {
19981
19982             var len = dds.length;
19983
19984             if (len == 1) {
19985                 winner = dds[0];
19986             } else {
19987                 // Loop through the targeted items
19988                 for (var i=0; i<len; ++i) {
19989                     var dd = dds[i];
19990                     // If the cursor is over the object, it wins.  If the
19991                     // cursor is over multiple matches, the first one we come
19992                     // to wins.
19993                     if (dd.cursorIsOver) {
19994                         winner = dd;
19995                         break;
19996                     // Otherwise the object with the most overlap wins
19997                     } else {
19998                         if (!winner ||
19999                             winner.overlap.getArea() < dd.overlap.getArea()) {
20000                             winner = dd;
20001                         }
20002                     }
20003                 }
20004             }
20005
20006             return winner;
20007         },
20008
20009         /**
20010          * Refreshes the cache of the top-left and bottom-right points of the
20011          * drag and drop objects in the specified group(s).  This is in the
20012          * format that is stored in the drag and drop instance, so typical
20013          * usage is:
20014          * <code>
20015          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20016          * </code>
20017          * Alternatively:
20018          * <code>
20019          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20020          * </code>
20021          * @TODO this really should be an indexed array.  Alternatively this
20022          * method could accept both.
20023          * @method refreshCache
20024          * @param {Object} groups an associative array of groups to refresh
20025          * @static
20026          */
20027         refreshCache: function(groups) {
20028             for (var sGroup in groups) {
20029                 if ("string" != typeof sGroup) {
20030                     continue;
20031                 }
20032                 for (var i in this.ids[sGroup]) {
20033                     var oDD = this.ids[sGroup][i];
20034
20035                     if (this.isTypeOfDD(oDD)) {
20036                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20037                         var loc = this.getLocation(oDD);
20038                         if (loc) {
20039                             this.locationCache[oDD.id] = loc;
20040                         } else {
20041                             delete this.locationCache[oDD.id];
20042                             // this will unregister the drag and drop object if
20043                             // the element is not in a usable state
20044                             // oDD.unreg();
20045                         }
20046                     }
20047                 }
20048             }
20049         },
20050
20051         /**
20052          * This checks to make sure an element exists and is in the DOM.  The
20053          * main purpose is to handle cases where innerHTML is used to remove
20054          * drag and drop objects from the DOM.  IE provides an 'unspecified
20055          * error' when trying to access the offsetParent of such an element
20056          * @method verifyEl
20057          * @param {HTMLElement} el the element to check
20058          * @return {boolean} true if the element looks usable
20059          * @static
20060          */
20061         verifyEl: function(el) {
20062             if (el) {
20063                 var parent;
20064                 if(Roo.isIE){
20065                     try{
20066                         parent = el.offsetParent;
20067                     }catch(e){}
20068                 }else{
20069                     parent = el.offsetParent;
20070                 }
20071                 if (parent) {
20072                     return true;
20073                 }
20074             }
20075
20076             return false;
20077         },
20078
20079         /**
20080          * Returns a Region object containing the drag and drop element's position
20081          * and size, including the padding configured for it
20082          * @method getLocation
20083          * @param {DragDrop} oDD the drag and drop object to get the
20084          *                       location for
20085          * @return {Roo.lib.Region} a Region object representing the total area
20086          *                             the element occupies, including any padding
20087          *                             the instance is configured for.
20088          * @static
20089          */
20090         getLocation: function(oDD) {
20091             if (! this.isTypeOfDD(oDD)) {
20092                 return null;
20093             }
20094
20095             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20096
20097             try {
20098                 pos= Roo.lib.Dom.getXY(el);
20099             } catch (e) { }
20100
20101             if (!pos) {
20102                 return null;
20103             }
20104
20105             x1 = pos[0];
20106             x2 = x1 + el.offsetWidth;
20107             y1 = pos[1];
20108             y2 = y1 + el.offsetHeight;
20109
20110             t = y1 - oDD.padding[0];
20111             r = x2 + oDD.padding[1];
20112             b = y2 + oDD.padding[2];
20113             l = x1 - oDD.padding[3];
20114
20115             return new Roo.lib.Region( t, r, b, l );
20116         },
20117
20118         /**
20119          * Checks the cursor location to see if it over the target
20120          * @method isOverTarget
20121          * @param {Roo.lib.Point} pt The point to evaluate
20122          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20123          * @return {boolean} true if the mouse is over the target
20124          * @private
20125          * @static
20126          */
20127         isOverTarget: function(pt, oTarget, intersect) {
20128             // use cache if available
20129             var loc = this.locationCache[oTarget.id];
20130             if (!loc || !this.useCache) {
20131                 loc = this.getLocation(oTarget);
20132                 this.locationCache[oTarget.id] = loc;
20133
20134             }
20135
20136             if (!loc) {
20137                 return false;
20138             }
20139
20140             oTarget.cursorIsOver = loc.contains( pt );
20141
20142             // DragDrop is using this as a sanity check for the initial mousedown
20143             // in this case we are done.  In POINT mode, if the drag obj has no
20144             // contraints, we are also done. Otherwise we need to evaluate the
20145             // location of the target as related to the actual location of the
20146             // dragged element.
20147             var dc = this.dragCurrent;
20148             if (!dc || !dc.getTargetCoord ||
20149                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20150                 return oTarget.cursorIsOver;
20151             }
20152
20153             oTarget.overlap = null;
20154
20155             // Get the current location of the drag element, this is the
20156             // location of the mouse event less the delta that represents
20157             // where the original mousedown happened on the element.  We
20158             // need to consider constraints and ticks as well.
20159             var pos = dc.getTargetCoord(pt.x, pt.y);
20160
20161             var el = dc.getDragEl();
20162             var curRegion = new Roo.lib.Region( pos.y,
20163                                                    pos.x + el.offsetWidth,
20164                                                    pos.y + el.offsetHeight,
20165                                                    pos.x );
20166
20167             var overlap = curRegion.intersect(loc);
20168
20169             if (overlap) {
20170                 oTarget.overlap = overlap;
20171                 return (intersect) ? true : oTarget.cursorIsOver;
20172             } else {
20173                 return false;
20174             }
20175         },
20176
20177         /**
20178          * unload event handler
20179          * @method _onUnload
20180          * @private
20181          * @static
20182          */
20183         _onUnload: function(e, me) {
20184             Roo.dd.DragDropMgr.unregAll();
20185         },
20186
20187         /**
20188          * Cleans up the drag and drop events and objects.
20189          * @method unregAll
20190          * @private
20191          * @static
20192          */
20193         unregAll: function() {
20194
20195             if (this.dragCurrent) {
20196                 this.stopDrag();
20197                 this.dragCurrent = null;
20198             }
20199
20200             this._execOnAll("unreg", []);
20201
20202             for (i in this.elementCache) {
20203                 delete this.elementCache[i];
20204             }
20205
20206             this.elementCache = {};
20207             this.ids = {};
20208         },
20209
20210         /**
20211          * A cache of DOM elements
20212          * @property elementCache
20213          * @private
20214          * @static
20215          */
20216         elementCache: {},
20217
20218         /**
20219          * Get the wrapper for the DOM element specified
20220          * @method getElWrapper
20221          * @param {String} id the id of the element to get
20222          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20223          * @private
20224          * @deprecated This wrapper isn't that useful
20225          * @static
20226          */
20227         getElWrapper: function(id) {
20228             var oWrapper = this.elementCache[id];
20229             if (!oWrapper || !oWrapper.el) {
20230                 oWrapper = this.elementCache[id] =
20231                     new this.ElementWrapper(Roo.getDom(id));
20232             }
20233             return oWrapper;
20234         },
20235
20236         /**
20237          * Returns the actual DOM element
20238          * @method getElement
20239          * @param {String} id the id of the elment to get
20240          * @return {Object} The element
20241          * @deprecated use Roo.getDom instead
20242          * @static
20243          */
20244         getElement: function(id) {
20245             return Roo.getDom(id);
20246         },
20247
20248         /**
20249          * Returns the style property for the DOM element (i.e.,
20250          * document.getElById(id).style)
20251          * @method getCss
20252          * @param {String} id the id of the elment to get
20253          * @return {Object} The style property of the element
20254          * @deprecated use Roo.getDom instead
20255          * @static
20256          */
20257         getCss: function(id) {
20258             var el = Roo.getDom(id);
20259             return (el) ? el.style : null;
20260         },
20261
20262         /**
20263          * Inner class for cached elements
20264          * @class DragDropMgr.ElementWrapper
20265          * @for DragDropMgr
20266          * @private
20267          * @deprecated
20268          */
20269         ElementWrapper: function(el) {
20270                 /**
20271                  * The element
20272                  * @property el
20273                  */
20274                 this.el = el || null;
20275                 /**
20276                  * The element id
20277                  * @property id
20278                  */
20279                 this.id = this.el && el.id;
20280                 /**
20281                  * A reference to the style property
20282                  * @property css
20283                  */
20284                 this.css = this.el && el.style;
20285             },
20286
20287         /**
20288          * Returns the X position of an html element
20289          * @method getPosX
20290          * @param el the element for which to get the position
20291          * @return {int} the X coordinate
20292          * @for DragDropMgr
20293          * @deprecated use Roo.lib.Dom.getX instead
20294          * @static
20295          */
20296         getPosX: function(el) {
20297             return Roo.lib.Dom.getX(el);
20298         },
20299
20300         /**
20301          * Returns the Y position of an html element
20302          * @method getPosY
20303          * @param el the element for which to get the position
20304          * @return {int} the Y coordinate
20305          * @deprecated use Roo.lib.Dom.getY instead
20306          * @static
20307          */
20308         getPosY: function(el) {
20309             return Roo.lib.Dom.getY(el);
20310         },
20311
20312         /**
20313          * Swap two nodes.  In IE, we use the native method, for others we
20314          * emulate the IE behavior
20315          * @method swapNode
20316          * @param n1 the first node to swap
20317          * @param n2 the other node to swap
20318          * @static
20319          */
20320         swapNode: function(n1, n2) {
20321             if (n1.swapNode) {
20322                 n1.swapNode(n2);
20323             } else {
20324                 var p = n2.parentNode;
20325                 var s = n2.nextSibling;
20326
20327                 if (s == n1) {
20328                     p.insertBefore(n1, n2);
20329                 } else if (n2 == n1.nextSibling) {
20330                     p.insertBefore(n2, n1);
20331                 } else {
20332                     n1.parentNode.replaceChild(n2, n1);
20333                     p.insertBefore(n1, s);
20334                 }
20335             }
20336         },
20337
20338         /**
20339          * Returns the current scroll position
20340          * @method getScroll
20341          * @private
20342          * @static
20343          */
20344         getScroll: function () {
20345             var t, l, dde=document.documentElement, db=document.body;
20346             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20347                 t = dde.scrollTop;
20348                 l = dde.scrollLeft;
20349             } else if (db) {
20350                 t = db.scrollTop;
20351                 l = db.scrollLeft;
20352             } else {
20353
20354             }
20355             return { top: t, left: l };
20356         },
20357
20358         /**
20359          * Returns the specified element style property
20360          * @method getStyle
20361          * @param {HTMLElement} el          the element
20362          * @param {string}      styleProp   the style property
20363          * @return {string} The value of the style property
20364          * @deprecated use Roo.lib.Dom.getStyle
20365          * @static
20366          */
20367         getStyle: function(el, styleProp) {
20368             return Roo.fly(el).getStyle(styleProp);
20369         },
20370
20371         /**
20372          * Gets the scrollTop
20373          * @method getScrollTop
20374          * @return {int} the document's scrollTop
20375          * @static
20376          */
20377         getScrollTop: function () { return this.getScroll().top; },
20378
20379         /**
20380          * Gets the scrollLeft
20381          * @method getScrollLeft
20382          * @return {int} the document's scrollTop
20383          * @static
20384          */
20385         getScrollLeft: function () { return this.getScroll().left; },
20386
20387         /**
20388          * Sets the x/y position of an element to the location of the
20389          * target element.
20390          * @method moveToEl
20391          * @param {HTMLElement} moveEl      The element to move
20392          * @param {HTMLElement} targetEl    The position reference element
20393          * @static
20394          */
20395         moveToEl: function (moveEl, targetEl) {
20396             var aCoord = Roo.lib.Dom.getXY(targetEl);
20397             Roo.lib.Dom.setXY(moveEl, aCoord);
20398         },
20399
20400         /**
20401          * Numeric array sort function
20402          * @method numericSort
20403          * @static
20404          */
20405         numericSort: function(a, b) { return (a - b); },
20406
20407         /**
20408          * Internal counter
20409          * @property _timeoutCount
20410          * @private
20411          * @static
20412          */
20413         _timeoutCount: 0,
20414
20415         /**
20416          * Trying to make the load order less important.  Without this we get
20417          * an error if this file is loaded before the Event Utility.
20418          * @method _addListeners
20419          * @private
20420          * @static
20421          */
20422         _addListeners: function() {
20423             var DDM = Roo.dd.DDM;
20424             if ( Roo.lib.Event && document ) {
20425                 DDM._onLoad();
20426             } else {
20427                 if (DDM._timeoutCount > 2000) {
20428                 } else {
20429                     setTimeout(DDM._addListeners, 10);
20430                     if (document && document.body) {
20431                         DDM._timeoutCount += 1;
20432                     }
20433                 }
20434             }
20435         },
20436
20437         /**
20438          * Recursively searches the immediate parent and all child nodes for
20439          * the handle element in order to determine wheter or not it was
20440          * clicked.
20441          * @method handleWasClicked
20442          * @param node the html element to inspect
20443          * @static
20444          */
20445         handleWasClicked: function(node, id) {
20446             if (this.isHandle(id, node.id)) {
20447                 return true;
20448             } else {
20449                 // check to see if this is a text node child of the one we want
20450                 var p = node.parentNode;
20451
20452                 while (p) {
20453                     if (this.isHandle(id, p.id)) {
20454                         return true;
20455                     } else {
20456                         p = p.parentNode;
20457                     }
20458                 }
20459             }
20460
20461             return false;
20462         }
20463
20464     };
20465
20466 }();
20467
20468 // shorter alias, save a few bytes
20469 Roo.dd.DDM = Roo.dd.DragDropMgr;
20470 Roo.dd.DDM._addListeners();
20471
20472 }/*
20473  * Based on:
20474  * Ext JS Library 1.1.1
20475  * Copyright(c) 2006-2007, Ext JS, LLC.
20476  *
20477  * Originally Released Under LGPL - original licence link has changed is not relivant.
20478  *
20479  * Fork - LGPL
20480  * <script type="text/javascript">
20481  */
20482
20483 /**
20484  * @class Roo.dd.DD
20485  * A DragDrop implementation where the linked element follows the
20486  * mouse cursor during a drag.
20487  * @extends Roo.dd.DragDrop
20488  * @constructor
20489  * @param {String} id the id of the linked element
20490  * @param {String} sGroup the group of related DragDrop items
20491  * @param {object} config an object containing configurable attributes
20492  *                Valid properties for DD:
20493  *                    scroll
20494  */
20495 Roo.dd.DD = function(id, sGroup, config) {
20496     if (id) {
20497         this.init(id, sGroup, config);
20498     }
20499 };
20500
20501 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20502
20503     /**
20504      * When set to true, the utility automatically tries to scroll the browser
20505      * window wehn a drag and drop element is dragged near the viewport boundary.
20506      * Defaults to true.
20507      * @property scroll
20508      * @type boolean
20509      */
20510     scroll: true,
20511
20512     /**
20513      * Sets the pointer offset to the distance between the linked element's top
20514      * left corner and the location the element was clicked
20515      * @method autoOffset
20516      * @param {int} iPageX the X coordinate of the click
20517      * @param {int} iPageY the Y coordinate of the click
20518      */
20519     autoOffset: function(iPageX, iPageY) {
20520         var x = iPageX - this.startPageX;
20521         var y = iPageY - this.startPageY;
20522         this.setDelta(x, y);
20523     },
20524
20525     /**
20526      * Sets the pointer offset.  You can call this directly to force the
20527      * offset to be in a particular location (e.g., pass in 0,0 to set it
20528      * to the center of the object)
20529      * @method setDelta
20530      * @param {int} iDeltaX the distance from the left
20531      * @param {int} iDeltaY the distance from the top
20532      */
20533     setDelta: function(iDeltaX, iDeltaY) {
20534         this.deltaX = iDeltaX;
20535         this.deltaY = iDeltaY;
20536     },
20537
20538     /**
20539      * Sets the drag element to the location of the mousedown or click event,
20540      * maintaining the cursor location relative to the location on the element
20541      * that was clicked.  Override this if you want to place the element in a
20542      * location other than where the cursor is.
20543      * @method setDragElPos
20544      * @param {int} iPageX the X coordinate of the mousedown or drag event
20545      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20546      */
20547     setDragElPos: function(iPageX, iPageY) {
20548         // the first time we do this, we are going to check to make sure
20549         // the element has css positioning
20550
20551         var el = this.getDragEl();
20552         this.alignElWithMouse(el, iPageX, iPageY);
20553     },
20554
20555     /**
20556      * Sets the element to the location of the mousedown or click event,
20557      * maintaining the cursor location relative to the location on the element
20558      * that was clicked.  Override this if you want to place the element in a
20559      * location other than where the cursor is.
20560      * @method alignElWithMouse
20561      * @param {HTMLElement} el the element to move
20562      * @param {int} iPageX the X coordinate of the mousedown or drag event
20563      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20564      */
20565     alignElWithMouse: function(el, iPageX, iPageY) {
20566         var oCoord = this.getTargetCoord(iPageX, iPageY);
20567         var fly = el.dom ? el : Roo.fly(el);
20568         if (!this.deltaSetXY) {
20569             var aCoord = [oCoord.x, oCoord.y];
20570             fly.setXY(aCoord);
20571             var newLeft = fly.getLeft(true);
20572             var newTop  = fly.getTop(true);
20573             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20574         } else {
20575             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20576         }
20577
20578         this.cachePosition(oCoord.x, oCoord.y);
20579         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20580         return oCoord;
20581     },
20582
20583     /**
20584      * Saves the most recent position so that we can reset the constraints and
20585      * tick marks on-demand.  We need to know this so that we can calculate the
20586      * number of pixels the element is offset from its original position.
20587      * @method cachePosition
20588      * @param iPageX the current x position (optional, this just makes it so we
20589      * don't have to look it up again)
20590      * @param iPageY the current y position (optional, this just makes it so we
20591      * don't have to look it up again)
20592      */
20593     cachePosition: function(iPageX, iPageY) {
20594         if (iPageX) {
20595             this.lastPageX = iPageX;
20596             this.lastPageY = iPageY;
20597         } else {
20598             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20599             this.lastPageX = aCoord[0];
20600             this.lastPageY = aCoord[1];
20601         }
20602     },
20603
20604     /**
20605      * Auto-scroll the window if the dragged object has been moved beyond the
20606      * visible window boundary.
20607      * @method autoScroll
20608      * @param {int} x the drag element's x position
20609      * @param {int} y the drag element's y position
20610      * @param {int} h the height of the drag element
20611      * @param {int} w the width of the drag element
20612      * @private
20613      */
20614     autoScroll: function(x, y, h, w) {
20615
20616         if (this.scroll) {
20617             // The client height
20618             var clientH = Roo.lib.Dom.getViewWidth();
20619
20620             // The client width
20621             var clientW = Roo.lib.Dom.getViewHeight();
20622
20623             // The amt scrolled down
20624             var st = this.DDM.getScrollTop();
20625
20626             // The amt scrolled right
20627             var sl = this.DDM.getScrollLeft();
20628
20629             // Location of the bottom of the element
20630             var bot = h + y;
20631
20632             // Location of the right of the element
20633             var right = w + x;
20634
20635             // The distance from the cursor to the bottom of the visible area,
20636             // adjusted so that we don't scroll if the cursor is beyond the
20637             // element drag constraints
20638             var toBot = (clientH + st - y - this.deltaY);
20639
20640             // The distance from the cursor to the right of the visible area
20641             var toRight = (clientW + sl - x - this.deltaX);
20642
20643
20644             // How close to the edge the cursor must be before we scroll
20645             // var thresh = (document.all) ? 100 : 40;
20646             var thresh = 40;
20647
20648             // How many pixels to scroll per autoscroll op.  This helps to reduce
20649             // clunky scrolling. IE is more sensitive about this ... it needs this
20650             // value to be higher.
20651             var scrAmt = (document.all) ? 80 : 30;
20652
20653             // Scroll down if we are near the bottom of the visible page and the
20654             // obj extends below the crease
20655             if ( bot > clientH && toBot < thresh ) {
20656                 window.scrollTo(sl, st + scrAmt);
20657             }
20658
20659             // Scroll up if the window is scrolled down and the top of the object
20660             // goes above the top border
20661             if ( y < st && st > 0 && y - st < thresh ) {
20662                 window.scrollTo(sl, st - scrAmt);
20663             }
20664
20665             // Scroll right if the obj is beyond the right border and the cursor is
20666             // near the border.
20667             if ( right > clientW && toRight < thresh ) {
20668                 window.scrollTo(sl + scrAmt, st);
20669             }
20670
20671             // Scroll left if the window has been scrolled to the right and the obj
20672             // extends past the left border
20673             if ( x < sl && sl > 0 && x - sl < thresh ) {
20674                 window.scrollTo(sl - scrAmt, st);
20675             }
20676         }
20677     },
20678
20679     /**
20680      * Finds the location the element should be placed if we want to move
20681      * it to where the mouse location less the click offset would place us.
20682      * @method getTargetCoord
20683      * @param {int} iPageX the X coordinate of the click
20684      * @param {int} iPageY the Y coordinate of the click
20685      * @return an object that contains the coordinates (Object.x and Object.y)
20686      * @private
20687      */
20688     getTargetCoord: function(iPageX, iPageY) {
20689
20690
20691         var x = iPageX - this.deltaX;
20692         var y = iPageY - this.deltaY;
20693
20694         if (this.constrainX) {
20695             if (x < this.minX) { x = this.minX; }
20696             if (x > this.maxX) { x = this.maxX; }
20697         }
20698
20699         if (this.constrainY) {
20700             if (y < this.minY) { y = this.minY; }
20701             if (y > this.maxY) { y = this.maxY; }
20702         }
20703
20704         x = this.getTick(x, this.xTicks);
20705         y = this.getTick(y, this.yTicks);
20706
20707
20708         return {x:x, y:y};
20709     },
20710
20711     /*
20712      * Sets up config options specific to this class. Overrides
20713      * Roo.dd.DragDrop, but all versions of this method through the
20714      * inheritance chain are called
20715      */
20716     applyConfig: function() {
20717         Roo.dd.DD.superclass.applyConfig.call(this);
20718         this.scroll = (this.config.scroll !== false);
20719     },
20720
20721     /*
20722      * Event that fires prior to the onMouseDown event.  Overrides
20723      * Roo.dd.DragDrop.
20724      */
20725     b4MouseDown: function(e) {
20726         // this.resetConstraints();
20727         this.autoOffset(e.getPageX(),
20728                             e.getPageY());
20729     },
20730
20731     /*
20732      * Event that fires prior to the onDrag event.  Overrides
20733      * Roo.dd.DragDrop.
20734      */
20735     b4Drag: function(e) {
20736         this.setDragElPos(e.getPageX(),
20737                             e.getPageY());
20738     },
20739
20740     toString: function() {
20741         return ("DD " + this.id);
20742     }
20743
20744     //////////////////////////////////////////////////////////////////////////
20745     // Debugging ygDragDrop events that can be overridden
20746     //////////////////////////////////////////////////////////////////////////
20747     /*
20748     startDrag: function(x, y) {
20749     },
20750
20751     onDrag: function(e) {
20752     },
20753
20754     onDragEnter: function(e, id) {
20755     },
20756
20757     onDragOver: function(e, id) {
20758     },
20759
20760     onDragOut: function(e, id) {
20761     },
20762
20763     onDragDrop: function(e, id) {
20764     },
20765
20766     endDrag: function(e) {
20767     }
20768
20769     */
20770
20771 });/*
20772  * Based on:
20773  * Ext JS Library 1.1.1
20774  * Copyright(c) 2006-2007, Ext JS, LLC.
20775  *
20776  * Originally Released Under LGPL - original licence link has changed is not relivant.
20777  *
20778  * Fork - LGPL
20779  * <script type="text/javascript">
20780  */
20781
20782 /**
20783  * @class Roo.dd.DDProxy
20784  * A DragDrop implementation that inserts an empty, bordered div into
20785  * the document that follows the cursor during drag operations.  At the time of
20786  * the click, the frame div is resized to the dimensions of the linked html
20787  * element, and moved to the exact location of the linked element.
20788  *
20789  * References to the "frame" element refer to the single proxy element that
20790  * was created to be dragged in place of all DDProxy elements on the
20791  * page.
20792  *
20793  * @extends Roo.dd.DD
20794  * @constructor
20795  * @param {String} id the id of the linked html element
20796  * @param {String} sGroup the group of related DragDrop objects
20797  * @param {object} config an object containing configurable attributes
20798  *                Valid properties for DDProxy in addition to those in DragDrop:
20799  *                   resizeFrame, centerFrame, dragElId
20800  */
20801 Roo.dd.DDProxy = function(id, sGroup, config) {
20802     if (id) {
20803         this.init(id, sGroup, config);
20804         this.initFrame();
20805     }
20806 };
20807
20808 /**
20809  * The default drag frame div id
20810  * @property Roo.dd.DDProxy.dragElId
20811  * @type String
20812  * @static
20813  */
20814 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20815
20816 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20817
20818     /**
20819      * By default we resize the drag frame to be the same size as the element
20820      * we want to drag (this is to get the frame effect).  We can turn it off
20821      * if we want a different behavior.
20822      * @property resizeFrame
20823      * @type boolean
20824      */
20825     resizeFrame: true,
20826
20827     /**
20828      * By default the frame is positioned exactly where the drag element is, so
20829      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20830      * you do not have constraints on the obj is to have the drag frame centered
20831      * around the cursor.  Set centerFrame to true for this effect.
20832      * @property centerFrame
20833      * @type boolean
20834      */
20835     centerFrame: false,
20836
20837     /**
20838      * Creates the proxy element if it does not yet exist
20839      * @method createFrame
20840      */
20841     createFrame: function() {
20842         var self = this;
20843         var body = document.body;
20844
20845         if (!body || !body.firstChild) {
20846             setTimeout( function() { self.createFrame(); }, 50 );
20847             return;
20848         }
20849
20850         var div = this.getDragEl();
20851
20852         if (!div) {
20853             div    = document.createElement("div");
20854             div.id = this.dragElId;
20855             var s  = div.style;
20856
20857             s.position   = "absolute";
20858             s.visibility = "hidden";
20859             s.cursor     = "move";
20860             s.border     = "2px solid #aaa";
20861             s.zIndex     = 999;
20862
20863             // appendChild can blow up IE if invoked prior to the window load event
20864             // while rendering a table.  It is possible there are other scenarios
20865             // that would cause this to happen as well.
20866             body.insertBefore(div, body.firstChild);
20867         }
20868     },
20869
20870     /**
20871      * Initialization for the drag frame element.  Must be called in the
20872      * constructor of all subclasses
20873      * @method initFrame
20874      */
20875     initFrame: function() {
20876         this.createFrame();
20877     },
20878
20879     applyConfig: function() {
20880         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20881
20882         this.resizeFrame = (this.config.resizeFrame !== false);
20883         this.centerFrame = (this.config.centerFrame);
20884         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20885     },
20886
20887     /**
20888      * Resizes the drag frame to the dimensions of the clicked object, positions
20889      * it over the object, and finally displays it
20890      * @method showFrame
20891      * @param {int} iPageX X click position
20892      * @param {int} iPageY Y click position
20893      * @private
20894      */
20895     showFrame: function(iPageX, iPageY) {
20896         var el = this.getEl();
20897         var dragEl = this.getDragEl();
20898         var s = dragEl.style;
20899
20900         this._resizeProxy();
20901
20902         if (this.centerFrame) {
20903             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20904                            Math.round(parseInt(s.height, 10)/2) );
20905         }
20906
20907         this.setDragElPos(iPageX, iPageY);
20908
20909         Roo.fly(dragEl).show();
20910     },
20911
20912     /**
20913      * The proxy is automatically resized to the dimensions of the linked
20914      * element when a drag is initiated, unless resizeFrame is set to false
20915      * @method _resizeProxy
20916      * @private
20917      */
20918     _resizeProxy: function() {
20919         if (this.resizeFrame) {
20920             var el = this.getEl();
20921             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20922         }
20923     },
20924
20925     // overrides Roo.dd.DragDrop
20926     b4MouseDown: function(e) {
20927         var x = e.getPageX();
20928         var y = e.getPageY();
20929         this.autoOffset(x, y);
20930         this.setDragElPos(x, y);
20931     },
20932
20933     // overrides Roo.dd.DragDrop
20934     b4StartDrag: function(x, y) {
20935         // show the drag frame
20936         this.showFrame(x, y);
20937     },
20938
20939     // overrides Roo.dd.DragDrop
20940     b4EndDrag: function(e) {
20941         Roo.fly(this.getDragEl()).hide();
20942     },
20943
20944     // overrides Roo.dd.DragDrop
20945     // By default we try to move the element to the last location of the frame.
20946     // This is so that the default behavior mirrors that of Roo.dd.DD.
20947     endDrag: function(e) {
20948
20949         var lel = this.getEl();
20950         var del = this.getDragEl();
20951
20952         // Show the drag frame briefly so we can get its position
20953         del.style.visibility = "";
20954
20955         this.beforeMove();
20956         // Hide the linked element before the move to get around a Safari
20957         // rendering bug.
20958         lel.style.visibility = "hidden";
20959         Roo.dd.DDM.moveToEl(lel, del);
20960         del.style.visibility = "hidden";
20961         lel.style.visibility = "";
20962
20963         this.afterDrag();
20964     },
20965
20966     beforeMove : function(){
20967
20968     },
20969
20970     afterDrag : function(){
20971
20972     },
20973
20974     toString: function() {
20975         return ("DDProxy " + this.id);
20976     }
20977
20978 });
20979 /*
20980  * Based on:
20981  * Ext JS Library 1.1.1
20982  * Copyright(c) 2006-2007, Ext JS, LLC.
20983  *
20984  * Originally Released Under LGPL - original licence link has changed is not relivant.
20985  *
20986  * Fork - LGPL
20987  * <script type="text/javascript">
20988  */
20989
20990  /**
20991  * @class Roo.dd.DDTarget
20992  * A DragDrop implementation that does not move, but can be a drop
20993  * target.  You would get the same result by simply omitting implementation
20994  * for the event callbacks, but this way we reduce the processing cost of the
20995  * event listener and the callbacks.
20996  * @extends Roo.dd.DragDrop
20997  * @constructor
20998  * @param {String} id the id of the element that is a drop target
20999  * @param {String} sGroup the group of related DragDrop objects
21000  * @param {object} config an object containing configurable attributes
21001  *                 Valid properties for DDTarget in addition to those in
21002  *                 DragDrop:
21003  *                    none
21004  */
21005 Roo.dd.DDTarget = function(id, sGroup, config) {
21006     if (id) {
21007         this.initTarget(id, sGroup, config);
21008     }
21009     if (config.listeners || config.events) { 
21010        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
21011             listeners : config.listeners || {}, 
21012             events : config.events || {} 
21013         });    
21014     }
21015 };
21016
21017 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21018 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21019     toString: function() {
21020         return ("DDTarget " + this.id);
21021     }
21022 });
21023 /*
21024  * Based on:
21025  * Ext JS Library 1.1.1
21026  * Copyright(c) 2006-2007, Ext JS, LLC.
21027  *
21028  * Originally Released Under LGPL - original licence link has changed is not relivant.
21029  *
21030  * Fork - LGPL
21031  * <script type="text/javascript">
21032  */
21033  
21034
21035 /**
21036  * @class Roo.dd.ScrollManager
21037  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21038  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21039  * @singleton
21040  */
21041 Roo.dd.ScrollManager = function(){
21042     var ddm = Roo.dd.DragDropMgr;
21043     var els = {};
21044     var dragEl = null;
21045     var proc = {};
21046     
21047     
21048     
21049     var onStop = function(e){
21050         dragEl = null;
21051         clearProc();
21052     };
21053     
21054     var triggerRefresh = function(){
21055         if(ddm.dragCurrent){
21056              ddm.refreshCache(ddm.dragCurrent.groups);
21057         }
21058     };
21059     
21060     var doScroll = function(){
21061         if(ddm.dragCurrent){
21062             var dds = Roo.dd.ScrollManager;
21063             if(!dds.animate){
21064                 if(proc.el.scroll(proc.dir, dds.increment)){
21065                     triggerRefresh();
21066                 }
21067             }else{
21068                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21069             }
21070         }
21071     };
21072     
21073     var clearProc = function(){
21074         if(proc.id){
21075             clearInterval(proc.id);
21076         }
21077         proc.id = 0;
21078         proc.el = null;
21079         proc.dir = "";
21080     };
21081     
21082     var startProc = function(el, dir){
21083          Roo.log('scroll startproc');
21084         clearProc();
21085         proc.el = el;
21086         proc.dir = dir;
21087         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21088     };
21089     
21090     var onFire = function(e, isDrop){
21091        
21092         if(isDrop || !ddm.dragCurrent){ return; }
21093         var dds = Roo.dd.ScrollManager;
21094         if(!dragEl || dragEl != ddm.dragCurrent){
21095             dragEl = ddm.dragCurrent;
21096             // refresh regions on drag start
21097             dds.refreshCache();
21098         }
21099         
21100         var xy = Roo.lib.Event.getXY(e);
21101         var pt = new Roo.lib.Point(xy[0], xy[1]);
21102         for(var id in els){
21103             var el = els[id], r = el._region;
21104             if(r && r.contains(pt) && el.isScrollable()){
21105                 if(r.bottom - pt.y <= dds.thresh){
21106                     if(proc.el != el){
21107                         startProc(el, "down");
21108                     }
21109                     return;
21110                 }else if(r.right - pt.x <= dds.thresh){
21111                     if(proc.el != el){
21112                         startProc(el, "left");
21113                     }
21114                     return;
21115                 }else if(pt.y - r.top <= dds.thresh){
21116                     if(proc.el != el){
21117                         startProc(el, "up");
21118                     }
21119                     return;
21120                 }else if(pt.x - r.left <= dds.thresh){
21121                     if(proc.el != el){
21122                         startProc(el, "right");
21123                     }
21124                     return;
21125                 }
21126             }
21127         }
21128         clearProc();
21129     };
21130     
21131     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21132     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21133     
21134     return {
21135         /**
21136          * Registers new overflow element(s) to auto scroll
21137          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21138          */
21139         register : function(el){
21140             if(el instanceof Array){
21141                 for(var i = 0, len = el.length; i < len; i++) {
21142                         this.register(el[i]);
21143                 }
21144             }else{
21145                 el = Roo.get(el);
21146                 els[el.id] = el;
21147             }
21148             Roo.dd.ScrollManager.els = els;
21149         },
21150         
21151         /**
21152          * Unregisters overflow element(s) so they are no longer scrolled
21153          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21154          */
21155         unregister : function(el){
21156             if(el instanceof Array){
21157                 for(var i = 0, len = el.length; i < len; i++) {
21158                         this.unregister(el[i]);
21159                 }
21160             }else{
21161                 el = Roo.get(el);
21162                 delete els[el.id];
21163             }
21164         },
21165         
21166         /**
21167          * The number of pixels from the edge of a container the pointer needs to be to 
21168          * trigger scrolling (defaults to 25)
21169          * @type Number
21170          */
21171         thresh : 25,
21172         
21173         /**
21174          * The number of pixels to scroll in each scroll increment (defaults to 50)
21175          * @type Number
21176          */
21177         increment : 100,
21178         
21179         /**
21180          * The frequency of scrolls in milliseconds (defaults to 500)
21181          * @type Number
21182          */
21183         frequency : 500,
21184         
21185         /**
21186          * True to animate the scroll (defaults to true)
21187          * @type Boolean
21188          */
21189         animate: true,
21190         
21191         /**
21192          * The animation duration in seconds - 
21193          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21194          * @type Number
21195          */
21196         animDuration: .4,
21197         
21198         /**
21199          * Manually trigger a cache refresh.
21200          */
21201         refreshCache : function(){
21202             for(var id in els){
21203                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21204                     els[id]._region = els[id].getRegion();
21205                 }
21206             }
21207         }
21208     };
21209 }();/*
21210  * Based on:
21211  * Ext JS Library 1.1.1
21212  * Copyright(c) 2006-2007, Ext JS, LLC.
21213  *
21214  * Originally Released Under LGPL - original licence link has changed is not relivant.
21215  *
21216  * Fork - LGPL
21217  * <script type="text/javascript">
21218  */
21219  
21220
21221 /**
21222  * @class Roo.dd.Registry
21223  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21224  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21225  * @singleton
21226  */
21227 Roo.dd.Registry = function(){
21228     var elements = {}; 
21229     var handles = {}; 
21230     var autoIdSeed = 0;
21231
21232     var getId = function(el, autogen){
21233         if(typeof el == "string"){
21234             return el;
21235         }
21236         var id = el.id;
21237         if(!id && autogen !== false){
21238             id = "roodd-" + (++autoIdSeed);
21239             el.id = id;
21240         }
21241         return id;
21242     };
21243     
21244     return {
21245     /**
21246      * Register a drag drop element
21247      * @param {String|HTMLElement} element The id or DOM node to register
21248      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21249      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21250      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21251      * populated in the data object (if applicable):
21252      * <pre>
21253 Value      Description<br />
21254 ---------  ------------------------------------------<br />
21255 handles    Array of DOM nodes that trigger dragging<br />
21256            for the element being registered<br />
21257 isHandle   True if the element passed in triggers<br />
21258            dragging itself, else false
21259 </pre>
21260      */
21261         register : function(el, data){
21262             data = data || {};
21263             if(typeof el == "string"){
21264                 el = document.getElementById(el);
21265             }
21266             data.ddel = el;
21267             elements[getId(el)] = data;
21268             if(data.isHandle !== false){
21269                 handles[data.ddel.id] = data;
21270             }
21271             if(data.handles){
21272                 var hs = data.handles;
21273                 for(var i = 0, len = hs.length; i < len; i++){
21274                         handles[getId(hs[i])] = data;
21275                 }
21276             }
21277         },
21278
21279     /**
21280      * Unregister a drag drop element
21281      * @param {String|HTMLElement}  element The id or DOM node to unregister
21282      */
21283         unregister : function(el){
21284             var id = getId(el, false);
21285             var data = elements[id];
21286             if(data){
21287                 delete elements[id];
21288                 if(data.handles){
21289                     var hs = data.handles;
21290                     for(var i = 0, len = hs.length; i < len; i++){
21291                         delete handles[getId(hs[i], false)];
21292                     }
21293                 }
21294             }
21295         },
21296
21297     /**
21298      * Returns the handle registered for a DOM Node by id
21299      * @param {String|HTMLElement} id The DOM node or id to look up
21300      * @return {Object} handle The custom handle data
21301      */
21302         getHandle : function(id){
21303             if(typeof id != "string"){ // must be element?
21304                 id = id.id;
21305             }
21306             return handles[id];
21307         },
21308
21309     /**
21310      * Returns the handle that is registered for the DOM node that is the target of the event
21311      * @param {Event} e The event
21312      * @return {Object} handle The custom handle data
21313      */
21314         getHandleFromEvent : function(e){
21315             var t = Roo.lib.Event.getTarget(e);
21316             return t ? handles[t.id] : null;
21317         },
21318
21319     /**
21320      * Returns a custom data object that is registered for a DOM node by id
21321      * @param {String|HTMLElement} id The DOM node or id to look up
21322      * @return {Object} data The custom data
21323      */
21324         getTarget : function(id){
21325             if(typeof id != "string"){ // must be element?
21326                 id = id.id;
21327             }
21328             return elements[id];
21329         },
21330
21331     /**
21332      * Returns a custom data object that is registered for the DOM node that is the target of the event
21333      * @param {Event} e The event
21334      * @return {Object} data The custom data
21335      */
21336         getTargetFromEvent : function(e){
21337             var t = Roo.lib.Event.getTarget(e);
21338             return t ? elements[t.id] || handles[t.id] : null;
21339         }
21340     };
21341 }();/*
21342  * Based on:
21343  * Ext JS Library 1.1.1
21344  * Copyright(c) 2006-2007, Ext JS, LLC.
21345  *
21346  * Originally Released Under LGPL - original licence link has changed is not relivant.
21347  *
21348  * Fork - LGPL
21349  * <script type="text/javascript">
21350  */
21351  
21352
21353 /**
21354  * @class Roo.dd.StatusProxy
21355  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21356  * default drag proxy used by all Roo.dd components.
21357  * @constructor
21358  * @param {Object} config
21359  */
21360 Roo.dd.StatusProxy = function(config){
21361     Roo.apply(this, config);
21362     this.id = this.id || Roo.id();
21363     this.el = new Roo.Layer({
21364         dh: {
21365             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21366                 {tag: "div", cls: "x-dd-drop-icon"},
21367                 {tag: "div", cls: "x-dd-drag-ghost"}
21368             ]
21369         }, 
21370         shadow: !config || config.shadow !== false
21371     });
21372     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21373     this.dropStatus = this.dropNotAllowed;
21374 };
21375
21376 Roo.dd.StatusProxy.prototype = {
21377     /**
21378      * @cfg {String} dropAllowed
21379      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21380      */
21381     dropAllowed : "x-dd-drop-ok",
21382     /**
21383      * @cfg {String} dropNotAllowed
21384      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21385      */
21386     dropNotAllowed : "x-dd-drop-nodrop",
21387
21388     /**
21389      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21390      * over the current target element.
21391      * @param {String} cssClass The css class for the new drop status indicator image
21392      */
21393     setStatus : function(cssClass){
21394         cssClass = cssClass || this.dropNotAllowed;
21395         if(this.dropStatus != cssClass){
21396             this.el.replaceClass(this.dropStatus, cssClass);
21397             this.dropStatus = cssClass;
21398         }
21399     },
21400
21401     /**
21402      * Resets the status indicator to the default dropNotAllowed value
21403      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21404      */
21405     reset : function(clearGhost){
21406         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21407         this.dropStatus = this.dropNotAllowed;
21408         if(clearGhost){
21409             this.ghost.update("");
21410         }
21411     },
21412
21413     /**
21414      * Updates the contents of the ghost element
21415      * @param {String} html The html that will replace the current innerHTML of the ghost element
21416      */
21417     update : function(html){
21418         if(typeof html == "string"){
21419             this.ghost.update(html);
21420         }else{
21421             this.ghost.update("");
21422             html.style.margin = "0";
21423             this.ghost.dom.appendChild(html);
21424         }
21425         // ensure float = none set?? cant remember why though.
21426         var el = this.ghost.dom.firstChild;
21427                 if(el){
21428                         Roo.fly(el).setStyle('float', 'none');
21429                 }
21430     },
21431     
21432     /**
21433      * Returns the underlying proxy {@link Roo.Layer}
21434      * @return {Roo.Layer} el
21435     */
21436     getEl : function(){
21437         return this.el;
21438     },
21439
21440     /**
21441      * Returns the ghost element
21442      * @return {Roo.Element} el
21443      */
21444     getGhost : function(){
21445         return this.ghost;
21446     },
21447
21448     /**
21449      * Hides the proxy
21450      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21451      */
21452     hide : function(clear){
21453         this.el.hide();
21454         if(clear){
21455             this.reset(true);
21456         }
21457     },
21458
21459     /**
21460      * Stops the repair animation if it's currently running
21461      */
21462     stop : function(){
21463         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21464             this.anim.stop();
21465         }
21466     },
21467
21468     /**
21469      * Displays this proxy
21470      */
21471     show : function(){
21472         this.el.show();
21473     },
21474
21475     /**
21476      * Force the Layer to sync its shadow and shim positions to the element
21477      */
21478     sync : function(){
21479         this.el.sync();
21480     },
21481
21482     /**
21483      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21484      * invalid drop operation by the item being dragged.
21485      * @param {Array} xy The XY position of the element ([x, y])
21486      * @param {Function} callback The function to call after the repair is complete
21487      * @param {Object} scope The scope in which to execute the callback
21488      */
21489     repair : function(xy, callback, scope){
21490         this.callback = callback;
21491         this.scope = scope;
21492         if(xy && this.animRepair !== false){
21493             this.el.addClass("x-dd-drag-repair");
21494             this.el.hideUnders(true);
21495             this.anim = this.el.shift({
21496                 duration: this.repairDuration || .5,
21497                 easing: 'easeOut',
21498                 xy: xy,
21499                 stopFx: true,
21500                 callback: this.afterRepair,
21501                 scope: this
21502             });
21503         }else{
21504             this.afterRepair();
21505         }
21506     },
21507
21508     // private
21509     afterRepair : function(){
21510         this.hide(true);
21511         if(typeof this.callback == "function"){
21512             this.callback.call(this.scope || this);
21513         }
21514         this.callback = null;
21515         this.scope = null;
21516     }
21517 };/*
21518  * Based on:
21519  * Ext JS Library 1.1.1
21520  * Copyright(c) 2006-2007, Ext JS, LLC.
21521  *
21522  * Originally Released Under LGPL - original licence link has changed is not relivant.
21523  *
21524  * Fork - LGPL
21525  * <script type="text/javascript">
21526  */
21527
21528 /**
21529  * @class Roo.dd.DragSource
21530  * @extends Roo.dd.DDProxy
21531  * A simple class that provides the basic implementation needed to make any element draggable.
21532  * @constructor
21533  * @param {String/HTMLElement/Element} el The container element
21534  * @param {Object} config
21535  */
21536 Roo.dd.DragSource = function(el, config){
21537     this.el = Roo.get(el);
21538     this.dragData = {};
21539     
21540     Roo.apply(this, config);
21541     
21542     if(!this.proxy){
21543         this.proxy = new Roo.dd.StatusProxy();
21544     }
21545
21546     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21547           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21548     
21549     this.dragging = false;
21550 };
21551
21552 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21553     /**
21554      * @cfg {String} dropAllowed
21555      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21556      */
21557     dropAllowed : "x-dd-drop-ok",
21558     /**
21559      * @cfg {String} dropNotAllowed
21560      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21561      */
21562     dropNotAllowed : "x-dd-drop-nodrop",
21563
21564     /**
21565      * Returns the data object associated with this drag source
21566      * @return {Object} data An object containing arbitrary data
21567      */
21568     getDragData : function(e){
21569         return this.dragData;
21570     },
21571
21572     // private
21573     onDragEnter : function(e, id){
21574         var target = Roo.dd.DragDropMgr.getDDById(id);
21575         this.cachedTarget = target;
21576         if(this.beforeDragEnter(target, e, id) !== false){
21577             if(target.isNotifyTarget){
21578                 var status = target.notifyEnter(this, e, this.dragData);
21579                 this.proxy.setStatus(status);
21580             }else{
21581                 this.proxy.setStatus(this.dropAllowed);
21582             }
21583             
21584             if(this.afterDragEnter){
21585                 /**
21586                  * An empty function by default, but provided so that you can perform a custom action
21587                  * when the dragged item enters the drop target by providing an implementation.
21588                  * @param {Roo.dd.DragDrop} target The drop target
21589                  * @param {Event} e The event object
21590                  * @param {String} id The id of the dragged element
21591                  * @method afterDragEnter
21592                  */
21593                 this.afterDragEnter(target, e, id);
21594             }
21595         }
21596     },
21597
21598     /**
21599      * An empty function by default, but provided so that you can perform a custom action
21600      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21601      * @param {Roo.dd.DragDrop} target The drop target
21602      * @param {Event} e The event object
21603      * @param {String} id The id of the dragged element
21604      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21605      */
21606     beforeDragEnter : function(target, e, id){
21607         return true;
21608     },
21609
21610     // private
21611     alignElWithMouse: function() {
21612         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21613         this.proxy.sync();
21614     },
21615
21616     // private
21617     onDragOver : function(e, id){
21618         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21619         if(this.beforeDragOver(target, e, id) !== false){
21620             if(target.isNotifyTarget){
21621                 var status = target.notifyOver(this, e, this.dragData);
21622                 this.proxy.setStatus(status);
21623             }
21624
21625             if(this.afterDragOver){
21626                 /**
21627                  * An empty function by default, but provided so that you can perform a custom action
21628                  * while the dragged item is over the drop target by providing an implementation.
21629                  * @param {Roo.dd.DragDrop} target The drop target
21630                  * @param {Event} e The event object
21631                  * @param {String} id The id of the dragged element
21632                  * @method afterDragOver
21633                  */
21634                 this.afterDragOver(target, e, id);
21635             }
21636         }
21637     },
21638
21639     /**
21640      * An empty function by default, but provided so that you can perform a custom action
21641      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21642      * @param {Roo.dd.DragDrop} target The drop target
21643      * @param {Event} e The event object
21644      * @param {String} id The id of the dragged element
21645      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21646      */
21647     beforeDragOver : function(target, e, id){
21648         return true;
21649     },
21650
21651     // private
21652     onDragOut : function(e, id){
21653         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21654         if(this.beforeDragOut(target, e, id) !== false){
21655             if(target.isNotifyTarget){
21656                 target.notifyOut(this, e, this.dragData);
21657             }
21658             this.proxy.reset();
21659             if(this.afterDragOut){
21660                 /**
21661                  * An empty function by default, but provided so that you can perform a custom action
21662                  * after the dragged item is dragged out of the target without dropping.
21663                  * @param {Roo.dd.DragDrop} target The drop target
21664                  * @param {Event} e The event object
21665                  * @param {String} id The id of the dragged element
21666                  * @method afterDragOut
21667                  */
21668                 this.afterDragOut(target, e, id);
21669             }
21670         }
21671         this.cachedTarget = null;
21672     },
21673
21674     /**
21675      * An empty function by default, but provided so that you can perform a custom action before the dragged
21676      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21677      * @param {Roo.dd.DragDrop} target The drop target
21678      * @param {Event} e The event object
21679      * @param {String} id The id of the dragged element
21680      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21681      */
21682     beforeDragOut : function(target, e, id){
21683         return true;
21684     },
21685     
21686     // private
21687     onDragDrop : function(e, id){
21688         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21689         if(this.beforeDragDrop(target, e, id) !== false){
21690             if(target.isNotifyTarget){
21691                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21692                     this.onValidDrop(target, e, id);
21693                 }else{
21694                     this.onInvalidDrop(target, e, id);
21695                 }
21696             }else{
21697                 this.onValidDrop(target, e, id);
21698             }
21699             
21700             if(this.afterDragDrop){
21701                 /**
21702                  * An empty function by default, but provided so that you can perform a custom action
21703                  * after a valid drag drop has occurred by providing an implementation.
21704                  * @param {Roo.dd.DragDrop} target The drop target
21705                  * @param {Event} e The event object
21706                  * @param {String} id The id of the dropped element
21707                  * @method afterDragDrop
21708                  */
21709                 this.afterDragDrop(target, e, id);
21710             }
21711         }
21712         delete this.cachedTarget;
21713     },
21714
21715     /**
21716      * An empty function by default, but provided so that you can perform a custom action before the dragged
21717      * item is dropped onto the target and optionally cancel the onDragDrop.
21718      * @param {Roo.dd.DragDrop} target The drop target
21719      * @param {Event} e The event object
21720      * @param {String} id The id of the dragged element
21721      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21722      */
21723     beforeDragDrop : function(target, e, id){
21724         return true;
21725     },
21726
21727     // private
21728     onValidDrop : function(target, e, id){
21729         this.hideProxy();
21730         if(this.afterValidDrop){
21731             /**
21732              * An empty function by default, but provided so that you can perform a custom action
21733              * after a valid drop has occurred by providing an implementation.
21734              * @param {Object} target The target DD 
21735              * @param {Event} e The event object
21736              * @param {String} id The id of the dropped element
21737              * @method afterInvalidDrop
21738              */
21739             this.afterValidDrop(target, e, id);
21740         }
21741     },
21742
21743     // private
21744     getRepairXY : function(e, data){
21745         return this.el.getXY();  
21746     },
21747
21748     // private
21749     onInvalidDrop : function(target, e, id){
21750         this.beforeInvalidDrop(target, e, id);
21751         if(this.cachedTarget){
21752             if(this.cachedTarget.isNotifyTarget){
21753                 this.cachedTarget.notifyOut(this, e, this.dragData);
21754             }
21755             this.cacheTarget = null;
21756         }
21757         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21758
21759         if(this.afterInvalidDrop){
21760             /**
21761              * An empty function by default, but provided so that you can perform a custom action
21762              * after an invalid drop has occurred by providing an implementation.
21763              * @param {Event} e The event object
21764              * @param {String} id The id of the dropped element
21765              * @method afterInvalidDrop
21766              */
21767             this.afterInvalidDrop(e, id);
21768         }
21769     },
21770
21771     // private
21772     afterRepair : function(){
21773         if(Roo.enableFx){
21774             this.el.highlight(this.hlColor || "c3daf9");
21775         }
21776         this.dragging = false;
21777     },
21778
21779     /**
21780      * An empty function by default, but provided so that you can perform a custom action after an invalid
21781      * drop has occurred.
21782      * @param {Roo.dd.DragDrop} target The drop target
21783      * @param {Event} e The event object
21784      * @param {String} id The id of the dragged element
21785      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21786      */
21787     beforeInvalidDrop : function(target, e, id){
21788         return true;
21789     },
21790
21791     // private
21792     handleMouseDown : function(e){
21793         if(this.dragging) {
21794             return;
21795         }
21796         var data = this.getDragData(e);
21797         if(data && this.onBeforeDrag(data, e) !== false){
21798             this.dragData = data;
21799             this.proxy.stop();
21800             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21801         } 
21802     },
21803
21804     /**
21805      * An empty function by default, but provided so that you can perform a custom action before the initial
21806      * drag event begins and optionally cancel it.
21807      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21808      * @param {Event} e The event object
21809      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21810      */
21811     onBeforeDrag : function(data, e){
21812         return true;
21813     },
21814
21815     /**
21816      * An empty function by default, but provided so that you can perform a custom action once the initial
21817      * drag event has begun.  The drag cannot be canceled from this function.
21818      * @param {Number} x The x position of the click on the dragged object
21819      * @param {Number} y The y position of the click on the dragged object
21820      */
21821     onStartDrag : Roo.emptyFn,
21822
21823     // private - YUI override
21824     startDrag : function(x, y){
21825         this.proxy.reset();
21826         this.dragging = true;
21827         this.proxy.update("");
21828         this.onInitDrag(x, y);
21829         this.proxy.show();
21830     },
21831
21832     // private
21833     onInitDrag : function(x, y){
21834         var clone = this.el.dom.cloneNode(true);
21835         clone.id = Roo.id(); // prevent duplicate ids
21836         this.proxy.update(clone);
21837         this.onStartDrag(x, y);
21838         return true;
21839     },
21840
21841     /**
21842      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21843      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21844      */
21845     getProxy : function(){
21846         return this.proxy;  
21847     },
21848
21849     /**
21850      * Hides the drag source's {@link Roo.dd.StatusProxy}
21851      */
21852     hideProxy : function(){
21853         this.proxy.hide();  
21854         this.proxy.reset(true);
21855         this.dragging = false;
21856     },
21857
21858     // private
21859     triggerCacheRefresh : function(){
21860         Roo.dd.DDM.refreshCache(this.groups);
21861     },
21862
21863     // private - override to prevent hiding
21864     b4EndDrag: function(e) {
21865     },
21866
21867     // private - override to prevent moving
21868     endDrag : function(e){
21869         this.onEndDrag(this.dragData, e);
21870     },
21871
21872     // private
21873     onEndDrag : function(data, e){
21874     },
21875     
21876     // private - pin to cursor
21877     autoOffset : function(x, y) {
21878         this.setDelta(-12, -20);
21879     }    
21880 });/*
21881  * Based on:
21882  * Ext JS Library 1.1.1
21883  * Copyright(c) 2006-2007, Ext JS, LLC.
21884  *
21885  * Originally Released Under LGPL - original licence link has changed is not relivant.
21886  *
21887  * Fork - LGPL
21888  * <script type="text/javascript">
21889  */
21890
21891
21892 /**
21893  * @class Roo.dd.DropTarget
21894  * @extends Roo.dd.DDTarget
21895  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21896  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21897  * @constructor
21898  * @param {String/HTMLElement/Element} el The container element
21899  * @param {Object} config
21900  */
21901 Roo.dd.DropTarget = function(el, config){
21902     this.el = Roo.get(el);
21903     
21904     var listeners = false; ;
21905     if (config && config.listeners) {
21906         listeners= config.listeners;
21907         delete config.listeners;
21908     }
21909     Roo.apply(this, config);
21910     
21911     if(this.containerScroll){
21912         Roo.dd.ScrollManager.register(this.el);
21913     }
21914     this.addEvents( {
21915          /**
21916          * @scope Roo.dd.DropTarget
21917          */
21918          
21919          /**
21920          * @event enter
21921          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21922          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21923          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21924          * 
21925          * IMPORTANT : it should set this.overClass and this.dropAllowed
21926          * 
21927          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21928          * @param {Event} e The event
21929          * @param {Object} data An object containing arbitrary data supplied by the drag source
21930          */
21931         "enter" : true,
21932         
21933          /**
21934          * @event over
21935          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21936          * This method will be called on every mouse movement while the drag source is over the drop target.
21937          * This default implementation simply returns the dropAllowed config value.
21938          * 
21939          * IMPORTANT : it should set this.dropAllowed
21940          * 
21941          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21942          * @param {Event} e The event
21943          * @param {Object} data An object containing arbitrary data supplied by the drag source
21944          
21945          */
21946         "over" : true,
21947         /**
21948          * @event out
21949          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21950          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21951          * overClass (if any) from the drop element.
21952          * 
21953          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21954          * @param {Event} e The event
21955          * @param {Object} data An object containing arbitrary data supplied by the drag source
21956          */
21957          "out" : true,
21958          
21959         /**
21960          * @event drop
21961          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21962          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21963          * implementation that does something to process the drop event and returns true so that the drag source's
21964          * repair action does not run.
21965          * 
21966          * IMPORTANT : it should set this.success
21967          * 
21968          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21969          * @param {Event} e The event
21970          * @param {Object} data An object containing arbitrary data supplied by the drag source
21971         */
21972          "drop" : true
21973     });
21974             
21975      
21976     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21977         this.el.dom, 
21978         this.ddGroup || this.group,
21979         {
21980             isTarget: true,
21981             listeners : listeners || {} 
21982            
21983         
21984         }
21985     );
21986
21987 };
21988
21989 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21990     /**
21991      * @cfg {String} overClass
21992      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21993      */
21994      /**
21995      * @cfg {String} ddGroup
21996      * The drag drop group to handle drop events for
21997      */
21998      
21999     /**
22000      * @cfg {String} dropAllowed
22001      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22002      */
22003     dropAllowed : "x-dd-drop-ok",
22004     /**
22005      * @cfg {String} dropNotAllowed
22006      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22007      */
22008     dropNotAllowed : "x-dd-drop-nodrop",
22009     /**
22010      * @cfg {boolean} success
22011      * set this after drop listener.. 
22012      */
22013     success : false,
22014     /**
22015      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22016      * if the drop point is valid for over/enter..
22017      */
22018     valid : false,
22019     // private
22020     isTarget : true,
22021
22022     // private
22023     isNotifyTarget : true,
22024     
22025     /**
22026      * @hide
22027      */
22028     notifyEnter : function(dd, e, data)
22029     {
22030         this.valid = true;
22031         this.fireEvent('enter', dd, e, data);
22032         if(this.overClass){
22033             this.el.addClass(this.overClass);
22034         }
22035         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22036             this.valid ? this.dropAllowed : this.dropNotAllowed
22037         );
22038     },
22039
22040     /**
22041      * @hide
22042      */
22043     notifyOver : function(dd, e, data)
22044     {
22045         this.valid = true;
22046         this.fireEvent('over', dd, e, data);
22047         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22048             this.valid ? this.dropAllowed : this.dropNotAllowed
22049         );
22050     },
22051
22052     /**
22053      * @hide
22054      */
22055     notifyOut : function(dd, e, data)
22056     {
22057         this.fireEvent('out', dd, e, data);
22058         if(this.overClass){
22059             this.el.removeClass(this.overClass);
22060         }
22061     },
22062
22063     /**
22064      * @hide
22065      */
22066     notifyDrop : function(dd, e, data)
22067     {
22068         this.success = false;
22069         this.fireEvent('drop', dd, e, data);
22070         return this.success;
22071     }
22072 });/*
22073  * Based on:
22074  * Ext JS Library 1.1.1
22075  * Copyright(c) 2006-2007, Ext JS, LLC.
22076  *
22077  * Originally Released Under LGPL - original licence link has changed is not relivant.
22078  *
22079  * Fork - LGPL
22080  * <script type="text/javascript">
22081  */
22082
22083
22084 /**
22085  * @class Roo.dd.DragZone
22086  * @extends Roo.dd.DragSource
22087  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22088  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22089  * @constructor
22090  * @param {String/HTMLElement/Element} el The container element
22091  * @param {Object} config
22092  */
22093 Roo.dd.DragZone = function(el, config){
22094     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22095     if(this.containerScroll){
22096         Roo.dd.ScrollManager.register(this.el);
22097     }
22098 };
22099
22100 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22101     /**
22102      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22103      * for auto scrolling during drag operations.
22104      */
22105     /**
22106      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22107      * method after a failed drop (defaults to "c3daf9" - light blue)
22108      */
22109
22110     /**
22111      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22112      * for a valid target to drag based on the mouse down. Override this method
22113      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22114      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22115      * @param {EventObject} e The mouse down event
22116      * @return {Object} The dragData
22117      */
22118     getDragData : function(e){
22119         return Roo.dd.Registry.getHandleFromEvent(e);
22120     },
22121     
22122     /**
22123      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22124      * this.dragData.ddel
22125      * @param {Number} x The x position of the click on the dragged object
22126      * @param {Number} y The y position of the click on the dragged object
22127      * @return {Boolean} true to continue the drag, false to cancel
22128      */
22129     onInitDrag : function(x, y){
22130         this.proxy.update(this.dragData.ddel.cloneNode(true));
22131         this.onStartDrag(x, y);
22132         return true;
22133     },
22134     
22135     /**
22136      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22137      */
22138     afterRepair : function(){
22139         if(Roo.enableFx){
22140             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22141         }
22142         this.dragging = false;
22143     },
22144
22145     /**
22146      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22147      * the XY of this.dragData.ddel
22148      * @param {EventObject} e The mouse up event
22149      * @return {Array} The xy location (e.g. [100, 200])
22150      */
22151     getRepairXY : function(e){
22152         return Roo.Element.fly(this.dragData.ddel).getXY();  
22153     }
22154 });/*
22155  * Based on:
22156  * Ext JS Library 1.1.1
22157  * Copyright(c) 2006-2007, Ext JS, LLC.
22158  *
22159  * Originally Released Under LGPL - original licence link has changed is not relivant.
22160  *
22161  * Fork - LGPL
22162  * <script type="text/javascript">
22163  */
22164 /**
22165  * @class Roo.dd.DropZone
22166  * @extends Roo.dd.DropTarget
22167  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22168  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22169  * @constructor
22170  * @param {String/HTMLElement/Element} el The container element
22171  * @param {Object} config
22172  */
22173 Roo.dd.DropZone = function(el, config){
22174     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22175 };
22176
22177 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22178     /**
22179      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22180      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22181      * provide your own custom lookup.
22182      * @param {Event} e The event
22183      * @return {Object} data The custom data
22184      */
22185     getTargetFromEvent : function(e){
22186         return Roo.dd.Registry.getTargetFromEvent(e);
22187     },
22188
22189     /**
22190      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22191      * that it has registered.  This method has no default implementation and should be overridden to provide
22192      * node-specific processing if necessary.
22193      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22194      * {@link #getTargetFromEvent} for this node)
22195      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22196      * @param {Event} e The event
22197      * @param {Object} data An object containing arbitrary data supplied by the drag source
22198      */
22199     onNodeEnter : function(n, dd, e, data){
22200         
22201     },
22202
22203     /**
22204      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22205      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22206      * overridden to provide the proper feedback.
22207      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22208      * {@link #getTargetFromEvent} for this node)
22209      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22210      * @param {Event} e The event
22211      * @param {Object} data An object containing arbitrary data supplied by the drag source
22212      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22213      * underlying {@link Roo.dd.StatusProxy} can be updated
22214      */
22215     onNodeOver : function(n, dd, e, data){
22216         return this.dropAllowed;
22217     },
22218
22219     /**
22220      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22221      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22222      * node-specific processing if necessary.
22223      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22224      * {@link #getTargetFromEvent} for this node)
22225      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22226      * @param {Event} e The event
22227      * @param {Object} data An object containing arbitrary data supplied by the drag source
22228      */
22229     onNodeOut : function(n, dd, e, data){
22230         
22231     },
22232
22233     /**
22234      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22235      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22236      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22237      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22238      * {@link #getTargetFromEvent} for this node)
22239      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22240      * @param {Event} e The event
22241      * @param {Object} data An object containing arbitrary data supplied by the drag source
22242      * @return {Boolean} True if the drop was valid, else false
22243      */
22244     onNodeDrop : function(n, dd, e, data){
22245         return false;
22246     },
22247
22248     /**
22249      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22250      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22251      * it should be overridden to provide the proper feedback if necessary.
22252      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22253      * @param {Event} e The event
22254      * @param {Object} data An object containing arbitrary data supplied by the drag source
22255      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22256      * underlying {@link Roo.dd.StatusProxy} can be updated
22257      */
22258     onContainerOver : function(dd, e, data){
22259         return this.dropNotAllowed;
22260     },
22261
22262     /**
22263      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22264      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22265      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22266      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22267      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22268      * @param {Event} e The event
22269      * @param {Object} data An object containing arbitrary data supplied by the drag source
22270      * @return {Boolean} True if the drop was valid, else false
22271      */
22272     onContainerDrop : function(dd, e, data){
22273         return false;
22274     },
22275
22276     /**
22277      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22278      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22279      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22280      * you should override this method and provide a custom implementation.
22281      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22282      * @param {Event} e The event
22283      * @param {Object} data An object containing arbitrary data supplied by the drag source
22284      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22285      * underlying {@link Roo.dd.StatusProxy} can be updated
22286      */
22287     notifyEnter : function(dd, e, data){
22288         return this.dropNotAllowed;
22289     },
22290
22291     /**
22292      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22293      * This method will be called on every mouse movement while the drag source is over the drop zone.
22294      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22295      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22296      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22297      * registered node, it will call {@link #onContainerOver}.
22298      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22299      * @param {Event} e The event
22300      * @param {Object} data An object containing arbitrary data supplied by the drag source
22301      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22302      * underlying {@link Roo.dd.StatusProxy} can be updated
22303      */
22304     notifyOver : function(dd, e, data){
22305         var n = this.getTargetFromEvent(e);
22306         if(!n){ // not over valid drop target
22307             if(this.lastOverNode){
22308                 this.onNodeOut(this.lastOverNode, dd, e, data);
22309                 this.lastOverNode = null;
22310             }
22311             return this.onContainerOver(dd, e, data);
22312         }
22313         if(this.lastOverNode != n){
22314             if(this.lastOverNode){
22315                 this.onNodeOut(this.lastOverNode, dd, e, data);
22316             }
22317             this.onNodeEnter(n, dd, e, data);
22318             this.lastOverNode = n;
22319         }
22320         return this.onNodeOver(n, dd, e, data);
22321     },
22322
22323     /**
22324      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22325      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22326      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22327      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22328      * @param {Event} e The event
22329      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22330      */
22331     notifyOut : function(dd, e, data){
22332         if(this.lastOverNode){
22333             this.onNodeOut(this.lastOverNode, dd, e, data);
22334             this.lastOverNode = null;
22335         }
22336     },
22337
22338     /**
22339      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22340      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22341      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22342      * otherwise it will call {@link #onContainerDrop}.
22343      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22344      * @param {Event} e The event
22345      * @param {Object} data An object containing arbitrary data supplied by the drag source
22346      * @return {Boolean} True if the drop was valid, else false
22347      */
22348     notifyDrop : function(dd, e, data){
22349         if(this.lastOverNode){
22350             this.onNodeOut(this.lastOverNode, dd, e, data);
22351             this.lastOverNode = null;
22352         }
22353         var n = this.getTargetFromEvent(e);
22354         return n ?
22355             this.onNodeDrop(n, dd, e, data) :
22356             this.onContainerDrop(dd, e, data);
22357     },
22358
22359     // private
22360     triggerCacheRefresh : function(){
22361         Roo.dd.DDM.refreshCache(this.groups);
22362     }  
22363 });