roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isEdge = ua.indexOf("edge") > -1,
61         isGecko = !isSafari && ua.indexOf("gecko") > -1,
62         isBorderBox = isIE && !isStrict,
63         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65         isLinux = (ua.indexOf("linux") != -1),
66         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67         isIOS = /iphone|ipad/.test(ua),
68         isAndroid = /android/.test(ua),
69         isTouch =  (function() {
70             try {
71                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72                     window.addEventListener('touchstart', function __set_has_touch__ () {
73                         Roo.isTouch = true;
74                         window.removeEventListener('touchstart', __set_has_touch__);
75                     });
76                     return false; // no touch on chrome!?
77                 }
78                 document.createEvent("TouchEvent");  
79                 return true;  
80             } catch (e) {  
81                 return false;  
82             } 
83             
84         })();
85     // remove css image flicker
86         if(isIE && !isIE7){
87         try{
88             document.execCommand("BackgroundImageCache", false, true);
89         }catch(e){}
90     }
91     
92     Roo.apply(Roo, {
93         /**
94          * True if the browser is in strict mode
95          * @type Boolean
96          */
97         isStrict : isStrict,
98         /**
99          * True if the page is running over SSL
100          * @type Boolean
101          */
102         isSecure : isSecure,
103         /**
104          * True when the document is fully initialized and ready for action
105          * @type Boolean
106          */
107         isReady : false,
108         /**
109          * Turn on debugging output (currently only the factory uses this)
110          * @type Boolean
111          */
112         
113         debug: false,
114
115         /**
116          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
117          * @type Boolean
118          */
119         enableGarbageCollector : true,
120
121         /**
122          * True to automatically purge event listeners after uncaching an element (defaults to false).
123          * Note: this only happens if enableGarbageCollector is true.
124          * @type Boolean
125          */
126         enableListenerCollection:false,
127
128         /**
129          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130          * the IE insecure content warning (defaults to javascript:false).
131          * @type String
132          */
133         SSL_SECURE_URL : "javascript:false",
134
135         /**
136          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
138          * @type String
139          */
140         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
141
142         emptyFn : function(){},
143         
144         /**
145          * Copies all the properties of config to obj if they don't already exist.
146          * @param {Object} obj The receiver of the properties
147          * @param {Object} config The source of the properties
148          * @return {Object} returns obj
149          */
150         applyIf : function(o, c){
151             if(o && c){
152                 for(var p in c){
153                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
154                 }
155             }
156             return o;
157         },
158
159         /**
160          * Applies event listeners to elements by selectors when the document is ready.
161          * The event name is specified with an @ suffix.
162 <pre><code>
163 Roo.addBehaviors({
164    // add a listener for click on all anchors in element with id foo
165    '#foo a@click' : function(e, t){
166        // do something
167    },
168
169    // add the same listener to multiple selectors (separated by comma BEFORE the @)
170    '#foo a, #bar span.some-class@mouseover' : function(){
171        // do something
172    }
173 });
174 </code></pre>
175          * @param {Object} obj The list of behaviors to apply
176          */
177         addBehaviors : function(o){
178             if(!Roo.isReady){
179                 Roo.onReady(function(){
180                     Roo.addBehaviors(o);
181                 });
182                 return;
183             }
184             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
185             for(var b in o){
186                 var parts = b.split('@');
187                 if(parts[1]){ // for Object prototype breakers
188                     var s = parts[0];
189                     if(!cache[s]){
190                         cache[s] = Roo.select(s);
191                     }
192                     cache[s].on(parts[1], o[b]);
193                 }
194             }
195             cache = null;
196         },
197
198         /**
199          * Generates unique ids. If the element already has an id, it is unchanged
200          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202          * @return {String} The generated Id.
203          */
204         id : function(el, prefix){
205             prefix = prefix || "roo-gen";
206             el = Roo.getDom(el);
207             var id = prefix + (++idSeed);
208             return el ? (el.id ? el.id : (el.id = id)) : id;
209         },
210          
211        
212         /**
213          * Extends one class with another class and optionally overrides members with the passed literal. This class
214          * also adds the function "override()" to the class that can be used to override
215          * members on an instance.
216          * @param {Object} subclass The class inheriting the functionality
217          * @param {Object} superclass The class being extended
218          * @param {Object} overrides (optional) A literal with members
219          * @method extend
220          */
221         extend : function(){
222             // inline overrides
223             var io = function(o){
224                 for(var m in o){
225                     this[m] = o[m];
226                 }
227             };
228             return function(sb, sp, overrides){
229                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
230                     overrides = sp;
231                     sp = sb;
232                     sb = function(){sp.apply(this, arguments);};
233                 }
234                 var F = function(){}, sbp, spp = sp.prototype;
235                 F.prototype = spp;
236                 sbp = sb.prototype = new F();
237                 sbp.constructor=sb;
238                 sb.superclass=spp;
239                 
240                 if(spp.constructor == Object.prototype.constructor){
241                     spp.constructor=sp;
242                    
243                 }
244                 
245                 sb.override = function(o){
246                     Roo.override(sb, o);
247                 };
248                 sbp.override = io;
249                 Roo.override(sb, overrides);
250                 return sb;
251             };
252         }(),
253
254         /**
255          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
256          * Usage:<pre><code>
257 Roo.override(MyClass, {
258     newMethod1: function(){
259         // etc.
260     },
261     newMethod2: function(foo){
262         // etc.
263     }
264 });
265  </code></pre>
266          * @param {Object} origclass The class to override
267          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
268          * containing one or more methods.
269          * @method override
270          */
271         override : function(origclass, overrides){
272             if(overrides){
273                 var p = origclass.prototype;
274                 for(var method in overrides){
275                     p[method] = overrides[method];
276                 }
277             }
278         },
279         /**
280          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
281          * <pre><code>
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
285 </code></pre>
286          * @param {String} namespace1
287          * @param {String} namespace2
288          * @param {String} etc
289          * @method namespace
290          */
291         namespace : function(){
292             var a=arguments, o=null, i, j, d, rt;
293             for (i=0; i<a.length; ++i) {
294                 d=a[i].split(".");
295                 rt = d[0];
296                 /** eval:var:o */
297                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298                 for (j=1; j<d.length; ++j) {
299                     o[d[j]]=o[d[j]] || {};
300                     o=o[d[j]];
301                 }
302             }
303         },
304         /**
305          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
306          * <pre><code>
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
309 </code></pre>
310          * @param {String} classname
311          * @param {String} namespace (optional)
312          * @method factory
313          */
314          
315         factory : function(c, ns)
316         {
317             // no xtype, no ns or c.xns - or forced off by c.xns
318             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
319                 return c;
320             }
321             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322             if (c.constructor == ns[c.xtype]) {// already created...
323                 return c;
324             }
325             if (ns[c.xtype]) {
326                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327                 var ret = new ns[c.xtype](c);
328                 ret.xns = false;
329                 return ret;
330             }
331             c.xns = false; // prevent recursion..
332             return c;
333         },
334          /**
335          * Logs to console if it can.
336          *
337          * @param {String|Object} string
338          * @method log
339          */
340         log : function(s)
341         {
342             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
343                 return; // alerT?
344             }
345             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         Roo.each(strings, function(k,v) {
16606             var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
16607             if (md !== false) {
16608                 component['strings'][md] = v;
16609             }
16610             
16611         });
16612         
16613     },
16614     
16615         
16616         /**
16617          * Event Object.
16618          *
16619          *
16620          */
16621         event: false, 
16622     /**
16623          * wrapper for event.on - aliased later..  
16624          * Typically use to register a event handler for register:
16625          *
16626          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16627          *
16628          */
16629     on : false
16630    
16631     
16632     
16633 });
16634
16635 Roo.XComponent.event = new Roo.util.Observable({
16636                 events : { 
16637                         /**
16638                          * @event register
16639                          * Fires when an Component is registered,
16640                          * set the disable property on the Component to stop registration.
16641                          * @param {Roo.XComponent} c the component being registerd.
16642                          * 
16643                          */
16644                         'register' : true,
16645             /**
16646                          * @event beforebuild
16647                          * Fires before each Component is built
16648                          * can be used to apply permissions.
16649                          * @param {Roo.XComponent} c the component being registerd.
16650                          * 
16651                          */
16652                         'beforebuild' : true,
16653                         /**
16654                          * @event buildcomplete
16655                          * Fires on the top level element when all elements have been built
16656                          * @param {Roo.XComponent} the top level component.
16657                          */
16658                         'buildcomplete' : true
16659                         
16660                 }
16661 });
16662
16663 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16664  //
16665  /**
16666  * marked - a markdown parser
16667  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16668  * https://github.com/chjj/marked
16669  */
16670
16671
16672 /**
16673  *
16674  * Roo.Markdown - is a very crude wrapper around marked..
16675  *
16676  * usage:
16677  * 
16678  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16679  * 
16680  * Note: move the sample code to the bottom of this
16681  * file before uncommenting it.
16682  *
16683  */
16684
16685 Roo.Markdown = {};
16686 Roo.Markdown.toHtml = function(text) {
16687     
16688     var c = new Roo.Markdown.marked.setOptions({
16689             renderer: new Roo.Markdown.marked.Renderer(),
16690             gfm: true,
16691             tables: true,
16692             breaks: false,
16693             pedantic: false,
16694             sanitize: false,
16695             smartLists: true,
16696             smartypants: false
16697           });
16698     // A FEW HACKS!!?
16699     
16700     text = text.replace(/\\\n/g,' ');
16701     return Roo.Markdown.marked(text);
16702 };
16703 //
16704 // converter
16705 //
16706 // Wraps all "globals" so that the only thing
16707 // exposed is makeHtml().
16708 //
16709 (function() {
16710     
16711     /**
16712      * Block-Level Grammar
16713      */
16714     
16715     var block = {
16716       newline: /^\n+/,
16717       code: /^( {4}[^\n]+\n*)+/,
16718       fences: noop,
16719       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16720       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16721       nptable: noop,
16722       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16723       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16724       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16725       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16726       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16727       table: noop,
16728       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16729       text: /^[^\n]+/
16730     };
16731     
16732     block.bullet = /(?:[*+-]|\d+\.)/;
16733     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16734     block.item = replace(block.item, 'gm')
16735       (/bull/g, block.bullet)
16736       ();
16737     
16738     block.list = replace(block.list)
16739       (/bull/g, block.bullet)
16740       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16741       ('def', '\\n+(?=' + block.def.source + ')')
16742       ();
16743     
16744     block.blockquote = replace(block.blockquote)
16745       ('def', block.def)
16746       ();
16747     
16748     block._tag = '(?!(?:'
16749       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16750       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16751       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16752     
16753     block.html = replace(block.html)
16754       ('comment', /<!--[\s\S]*?-->/)
16755       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16756       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16757       (/tag/g, block._tag)
16758       ();
16759     
16760     block.paragraph = replace(block.paragraph)
16761       ('hr', block.hr)
16762       ('heading', block.heading)
16763       ('lheading', block.lheading)
16764       ('blockquote', block.blockquote)
16765       ('tag', '<' + block._tag)
16766       ('def', block.def)
16767       ();
16768     
16769     /**
16770      * Normal Block Grammar
16771      */
16772     
16773     block.normal = merge({}, block);
16774     
16775     /**
16776      * GFM Block Grammar
16777      */
16778     
16779     block.gfm = merge({}, block.normal, {
16780       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16781       paragraph: /^/,
16782       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16783     });
16784     
16785     block.gfm.paragraph = replace(block.paragraph)
16786       ('(?!', '(?!'
16787         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16788         + block.list.source.replace('\\1', '\\3') + '|')
16789       ();
16790     
16791     /**
16792      * GFM + Tables Block Grammar
16793      */
16794     
16795     block.tables = merge({}, block.gfm, {
16796       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16797       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16798     });
16799     
16800     /**
16801      * Block Lexer
16802      */
16803     
16804     function Lexer(options) {
16805       this.tokens = [];
16806       this.tokens.links = {};
16807       this.options = options || marked.defaults;
16808       this.rules = block.normal;
16809     
16810       if (this.options.gfm) {
16811         if (this.options.tables) {
16812           this.rules = block.tables;
16813         } else {
16814           this.rules = block.gfm;
16815         }
16816       }
16817     }
16818     
16819     /**
16820      * Expose Block Rules
16821      */
16822     
16823     Lexer.rules = block;
16824     
16825     /**
16826      * Static Lex Method
16827      */
16828     
16829     Lexer.lex = function(src, options) {
16830       var lexer = new Lexer(options);
16831       return lexer.lex(src);
16832     };
16833     
16834     /**
16835      * Preprocessing
16836      */
16837     
16838     Lexer.prototype.lex = function(src) {
16839       src = src
16840         .replace(/\r\n|\r/g, '\n')
16841         .replace(/\t/g, '    ')
16842         .replace(/\u00a0/g, ' ')
16843         .replace(/\u2424/g, '\n');
16844     
16845       return this.token(src, true);
16846     };
16847     
16848     /**
16849      * Lexing
16850      */
16851     
16852     Lexer.prototype.token = function(src, top, bq) {
16853       var src = src.replace(/^ +$/gm, '')
16854         , next
16855         , loose
16856         , cap
16857         , bull
16858         , b
16859         , item
16860         , space
16861         , i
16862         , l;
16863     
16864       while (src) {
16865         // newline
16866         if (cap = this.rules.newline.exec(src)) {
16867           src = src.substring(cap[0].length);
16868           if (cap[0].length > 1) {
16869             this.tokens.push({
16870               type: 'space'
16871             });
16872           }
16873         }
16874     
16875         // code
16876         if (cap = this.rules.code.exec(src)) {
16877           src = src.substring(cap[0].length);
16878           cap = cap[0].replace(/^ {4}/gm, '');
16879           this.tokens.push({
16880             type: 'code',
16881             text: !this.options.pedantic
16882               ? cap.replace(/\n+$/, '')
16883               : cap
16884           });
16885           continue;
16886         }
16887     
16888         // fences (gfm)
16889         if (cap = this.rules.fences.exec(src)) {
16890           src = src.substring(cap[0].length);
16891           this.tokens.push({
16892             type: 'code',
16893             lang: cap[2],
16894             text: cap[3] || ''
16895           });
16896           continue;
16897         }
16898     
16899         // heading
16900         if (cap = this.rules.heading.exec(src)) {
16901           src = src.substring(cap[0].length);
16902           this.tokens.push({
16903             type: 'heading',
16904             depth: cap[1].length,
16905             text: cap[2]
16906           });
16907           continue;
16908         }
16909     
16910         // table no leading pipe (gfm)
16911         if (top && (cap = this.rules.nptable.exec(src))) {
16912           src = src.substring(cap[0].length);
16913     
16914           item = {
16915             type: 'table',
16916             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16917             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16918             cells: cap[3].replace(/\n$/, '').split('\n')
16919           };
16920     
16921           for (i = 0; i < item.align.length; i++) {
16922             if (/^ *-+: *$/.test(item.align[i])) {
16923               item.align[i] = 'right';
16924             } else if (/^ *:-+: *$/.test(item.align[i])) {
16925               item.align[i] = 'center';
16926             } else if (/^ *:-+ *$/.test(item.align[i])) {
16927               item.align[i] = 'left';
16928             } else {
16929               item.align[i] = null;
16930             }
16931           }
16932     
16933           for (i = 0; i < item.cells.length; i++) {
16934             item.cells[i] = item.cells[i].split(/ *\| */);
16935           }
16936     
16937           this.tokens.push(item);
16938     
16939           continue;
16940         }
16941     
16942         // lheading
16943         if (cap = this.rules.lheading.exec(src)) {
16944           src = src.substring(cap[0].length);
16945           this.tokens.push({
16946             type: 'heading',
16947             depth: cap[2] === '=' ? 1 : 2,
16948             text: cap[1]
16949           });
16950           continue;
16951         }
16952     
16953         // hr
16954         if (cap = this.rules.hr.exec(src)) {
16955           src = src.substring(cap[0].length);
16956           this.tokens.push({
16957             type: 'hr'
16958           });
16959           continue;
16960         }
16961     
16962         // blockquote
16963         if (cap = this.rules.blockquote.exec(src)) {
16964           src = src.substring(cap[0].length);
16965     
16966           this.tokens.push({
16967             type: 'blockquote_start'
16968           });
16969     
16970           cap = cap[0].replace(/^ *> ?/gm, '');
16971     
16972           // Pass `top` to keep the current
16973           // "toplevel" state. This is exactly
16974           // how markdown.pl works.
16975           this.token(cap, top, true);
16976     
16977           this.tokens.push({
16978             type: 'blockquote_end'
16979           });
16980     
16981           continue;
16982         }
16983     
16984         // list
16985         if (cap = this.rules.list.exec(src)) {
16986           src = src.substring(cap[0].length);
16987           bull = cap[2];
16988     
16989           this.tokens.push({
16990             type: 'list_start',
16991             ordered: bull.length > 1
16992           });
16993     
16994           // Get each top-level item.
16995           cap = cap[0].match(this.rules.item);
16996     
16997           next = false;
16998           l = cap.length;
16999           i = 0;
17000     
17001           for (; i < l; i++) {
17002             item = cap[i];
17003     
17004             // Remove the list item's bullet
17005             // so it is seen as the next token.
17006             space = item.length;
17007             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17008     
17009             // Outdent whatever the
17010             // list item contains. Hacky.
17011             if (~item.indexOf('\n ')) {
17012               space -= item.length;
17013               item = !this.options.pedantic
17014                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17015                 : item.replace(/^ {1,4}/gm, '');
17016             }
17017     
17018             // Determine whether the next list item belongs here.
17019             // Backpedal if it does not belong in this list.
17020             if (this.options.smartLists && i !== l - 1) {
17021               b = block.bullet.exec(cap[i + 1])[0];
17022               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17023                 src = cap.slice(i + 1).join('\n') + src;
17024                 i = l - 1;
17025               }
17026             }
17027     
17028             // Determine whether item is loose or not.
17029             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17030             // for discount behavior.
17031             loose = next || /\n\n(?!\s*$)/.test(item);
17032             if (i !== l - 1) {
17033               next = item.charAt(item.length - 1) === '\n';
17034               if (!loose) { loose = next; }
17035             }
17036     
17037             this.tokens.push({
17038               type: loose
17039                 ? 'loose_item_start'
17040                 : 'list_item_start'
17041             });
17042     
17043             // Recurse.
17044             this.token(item, false, bq);
17045     
17046             this.tokens.push({
17047               type: 'list_item_end'
17048             });
17049           }
17050     
17051           this.tokens.push({
17052             type: 'list_end'
17053           });
17054     
17055           continue;
17056         }
17057     
17058         // html
17059         if (cap = this.rules.html.exec(src)) {
17060           src = src.substring(cap[0].length);
17061           this.tokens.push({
17062             type: this.options.sanitize
17063               ? 'paragraph'
17064               : 'html',
17065             pre: !this.options.sanitizer
17066               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17067             text: cap[0]
17068           });
17069           continue;
17070         }
17071     
17072         // def
17073         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17074           src = src.substring(cap[0].length);
17075           this.tokens.links[cap[1].toLowerCase()] = {
17076             href: cap[2],
17077             title: cap[3]
17078           };
17079           continue;
17080         }
17081     
17082         // table (gfm)
17083         if (top && (cap = this.rules.table.exec(src))) {
17084           src = src.substring(cap[0].length);
17085     
17086           item = {
17087             type: 'table',
17088             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17089             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17090             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17091           };
17092     
17093           for (i = 0; i < item.align.length; i++) {
17094             if (/^ *-+: *$/.test(item.align[i])) {
17095               item.align[i] = 'right';
17096             } else if (/^ *:-+: *$/.test(item.align[i])) {
17097               item.align[i] = 'center';
17098             } else if (/^ *:-+ *$/.test(item.align[i])) {
17099               item.align[i] = 'left';
17100             } else {
17101               item.align[i] = null;
17102             }
17103           }
17104     
17105           for (i = 0; i < item.cells.length; i++) {
17106             item.cells[i] = item.cells[i]
17107               .replace(/^ *\| *| *\| *$/g, '')
17108               .split(/ *\| */);
17109           }
17110     
17111           this.tokens.push(item);
17112     
17113           continue;
17114         }
17115     
17116         // top-level paragraph
17117         if (top && (cap = this.rules.paragraph.exec(src))) {
17118           src = src.substring(cap[0].length);
17119           this.tokens.push({
17120             type: 'paragraph',
17121             text: cap[1].charAt(cap[1].length - 1) === '\n'
17122               ? cap[1].slice(0, -1)
17123               : cap[1]
17124           });
17125           continue;
17126         }
17127     
17128         // text
17129         if (cap = this.rules.text.exec(src)) {
17130           // Top-level should never reach here.
17131           src = src.substring(cap[0].length);
17132           this.tokens.push({
17133             type: 'text',
17134             text: cap[0]
17135           });
17136           continue;
17137         }
17138     
17139         if (src) {
17140           throw new
17141             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17142         }
17143       }
17144     
17145       return this.tokens;
17146     };
17147     
17148     /**
17149      * Inline-Level Grammar
17150      */
17151     
17152     var inline = {
17153       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17154       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17155       url: noop,
17156       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17157       link: /^!?\[(inside)\]\(href\)/,
17158       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17159       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17160       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17161       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17162       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17163       br: /^ {2,}\n(?!\s*$)/,
17164       del: noop,
17165       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17166     };
17167     
17168     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17169     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17170     
17171     inline.link = replace(inline.link)
17172       ('inside', inline._inside)
17173       ('href', inline._href)
17174       ();
17175     
17176     inline.reflink = replace(inline.reflink)
17177       ('inside', inline._inside)
17178       ();
17179     
17180     /**
17181      * Normal Inline Grammar
17182      */
17183     
17184     inline.normal = merge({}, inline);
17185     
17186     /**
17187      * Pedantic Inline Grammar
17188      */
17189     
17190     inline.pedantic = merge({}, inline.normal, {
17191       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17192       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17193     });
17194     
17195     /**
17196      * GFM Inline Grammar
17197      */
17198     
17199     inline.gfm = merge({}, inline.normal, {
17200       escape: replace(inline.escape)('])', '~|])')(),
17201       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17202       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17203       text: replace(inline.text)
17204         (']|', '~]|')
17205         ('|', '|https?://|')
17206         ()
17207     });
17208     
17209     /**
17210      * GFM + Line Breaks Inline Grammar
17211      */
17212     
17213     inline.breaks = merge({}, inline.gfm, {
17214       br: replace(inline.br)('{2,}', '*')(),
17215       text: replace(inline.gfm.text)('{2,}', '*')()
17216     });
17217     
17218     /**
17219      * Inline Lexer & Compiler
17220      */
17221     
17222     function InlineLexer(links, options) {
17223       this.options = options || marked.defaults;
17224       this.links = links;
17225       this.rules = inline.normal;
17226       this.renderer = this.options.renderer || new Renderer;
17227       this.renderer.options = this.options;
17228     
17229       if (!this.links) {
17230         throw new
17231           Error('Tokens array requires a `links` property.');
17232       }
17233     
17234       if (this.options.gfm) {
17235         if (this.options.breaks) {
17236           this.rules = inline.breaks;
17237         } else {
17238           this.rules = inline.gfm;
17239         }
17240       } else if (this.options.pedantic) {
17241         this.rules = inline.pedantic;
17242       }
17243     }
17244     
17245     /**
17246      * Expose Inline Rules
17247      */
17248     
17249     InlineLexer.rules = inline;
17250     
17251     /**
17252      * Static Lexing/Compiling Method
17253      */
17254     
17255     InlineLexer.output = function(src, links, options) {
17256       var inline = new InlineLexer(links, options);
17257       return inline.output(src);
17258     };
17259     
17260     /**
17261      * Lexing/Compiling
17262      */
17263     
17264     InlineLexer.prototype.output = function(src) {
17265       var out = ''
17266         , link
17267         , text
17268         , href
17269         , cap;
17270     
17271       while (src) {
17272         // escape
17273         if (cap = this.rules.escape.exec(src)) {
17274           src = src.substring(cap[0].length);
17275           out += cap[1];
17276           continue;
17277         }
17278     
17279         // autolink
17280         if (cap = this.rules.autolink.exec(src)) {
17281           src = src.substring(cap[0].length);
17282           if (cap[2] === '@') {
17283             text = cap[1].charAt(6) === ':'
17284               ? this.mangle(cap[1].substring(7))
17285               : this.mangle(cap[1]);
17286             href = this.mangle('mailto:') + text;
17287           } else {
17288             text = escape(cap[1]);
17289             href = text;
17290           }
17291           out += this.renderer.link(href, null, text);
17292           continue;
17293         }
17294     
17295         // url (gfm)
17296         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17297           src = src.substring(cap[0].length);
17298           text = escape(cap[1]);
17299           href = text;
17300           out += this.renderer.link(href, null, text);
17301           continue;
17302         }
17303     
17304         // tag
17305         if (cap = this.rules.tag.exec(src)) {
17306           if (!this.inLink && /^<a /i.test(cap[0])) {
17307             this.inLink = true;
17308           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17309             this.inLink = false;
17310           }
17311           src = src.substring(cap[0].length);
17312           out += this.options.sanitize
17313             ? this.options.sanitizer
17314               ? this.options.sanitizer(cap[0])
17315               : escape(cap[0])
17316             : cap[0];
17317           continue;
17318         }
17319     
17320         // link
17321         if (cap = this.rules.link.exec(src)) {
17322           src = src.substring(cap[0].length);
17323           this.inLink = true;
17324           out += this.outputLink(cap, {
17325             href: cap[2],
17326             title: cap[3]
17327           });
17328           this.inLink = false;
17329           continue;
17330         }
17331     
17332         // reflink, nolink
17333         if ((cap = this.rules.reflink.exec(src))
17334             || (cap = this.rules.nolink.exec(src))) {
17335           src = src.substring(cap[0].length);
17336           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17337           link = this.links[link.toLowerCase()];
17338           if (!link || !link.href) {
17339             out += cap[0].charAt(0);
17340             src = cap[0].substring(1) + src;
17341             continue;
17342           }
17343           this.inLink = true;
17344           out += this.outputLink(cap, link);
17345           this.inLink = false;
17346           continue;
17347         }
17348     
17349         // strong
17350         if (cap = this.rules.strong.exec(src)) {
17351           src = src.substring(cap[0].length);
17352           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17353           continue;
17354         }
17355     
17356         // em
17357         if (cap = this.rules.em.exec(src)) {
17358           src = src.substring(cap[0].length);
17359           out += this.renderer.em(this.output(cap[2] || cap[1]));
17360           continue;
17361         }
17362     
17363         // code
17364         if (cap = this.rules.code.exec(src)) {
17365           src = src.substring(cap[0].length);
17366           out += this.renderer.codespan(escape(cap[2], true));
17367           continue;
17368         }
17369     
17370         // br
17371         if (cap = this.rules.br.exec(src)) {
17372           src = src.substring(cap[0].length);
17373           out += this.renderer.br();
17374           continue;
17375         }
17376     
17377         // del (gfm)
17378         if (cap = this.rules.del.exec(src)) {
17379           src = src.substring(cap[0].length);
17380           out += this.renderer.del(this.output(cap[1]));
17381           continue;
17382         }
17383     
17384         // text
17385         if (cap = this.rules.text.exec(src)) {
17386           src = src.substring(cap[0].length);
17387           out += this.renderer.text(escape(this.smartypants(cap[0])));
17388           continue;
17389         }
17390     
17391         if (src) {
17392           throw new
17393             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17394         }
17395       }
17396     
17397       return out;
17398     };
17399     
17400     /**
17401      * Compile Link
17402      */
17403     
17404     InlineLexer.prototype.outputLink = function(cap, link) {
17405       var href = escape(link.href)
17406         , title = link.title ? escape(link.title) : null;
17407     
17408       return cap[0].charAt(0) !== '!'
17409         ? this.renderer.link(href, title, this.output(cap[1]))
17410         : this.renderer.image(href, title, escape(cap[1]));
17411     };
17412     
17413     /**
17414      * Smartypants Transformations
17415      */
17416     
17417     InlineLexer.prototype.smartypants = function(text) {
17418       if (!this.options.smartypants)  { return text; }
17419       return text
17420         // em-dashes
17421         .replace(/---/g, '\u2014')
17422         // en-dashes
17423         .replace(/--/g, '\u2013')
17424         // opening singles
17425         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17426         // closing singles & apostrophes
17427         .replace(/'/g, '\u2019')
17428         // opening doubles
17429         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17430         // closing doubles
17431         .replace(/"/g, '\u201d')
17432         // ellipses
17433         .replace(/\.{3}/g, '\u2026');
17434     };
17435     
17436     /**
17437      * Mangle Links
17438      */
17439     
17440     InlineLexer.prototype.mangle = function(text) {
17441       if (!this.options.mangle) { return text; }
17442       var out = ''
17443         , l = text.length
17444         , i = 0
17445         , ch;
17446     
17447       for (; i < l; i++) {
17448         ch = text.charCodeAt(i);
17449         if (Math.random() > 0.5) {
17450           ch = 'x' + ch.toString(16);
17451         }
17452         out += '&#' + ch + ';';
17453       }
17454     
17455       return out;
17456     };
17457     
17458     /**
17459      * Renderer
17460      */
17461     
17462     function Renderer(options) {
17463       this.options = options || {};
17464     }
17465     
17466     Renderer.prototype.code = function(code, lang, escaped) {
17467       if (this.options.highlight) {
17468         var out = this.options.highlight(code, lang);
17469         if (out != null && out !== code) {
17470           escaped = true;
17471           code = out;
17472         }
17473       } else {
17474             // hack!!! - it's already escapeD?
17475             escaped = true;
17476       }
17477     
17478       if (!lang) {
17479         return '<pre><code>'
17480           + (escaped ? code : escape(code, true))
17481           + '\n</code></pre>';
17482       }
17483     
17484       return '<pre><code class="'
17485         + this.options.langPrefix
17486         + escape(lang, true)
17487         + '">'
17488         + (escaped ? code : escape(code, true))
17489         + '\n</code></pre>\n';
17490     };
17491     
17492     Renderer.prototype.blockquote = function(quote) {
17493       return '<blockquote>\n' + quote + '</blockquote>\n';
17494     };
17495     
17496     Renderer.prototype.html = function(html) {
17497       return html;
17498     };
17499     
17500     Renderer.prototype.heading = function(text, level, raw) {
17501       return '<h'
17502         + level
17503         + ' id="'
17504         + this.options.headerPrefix
17505         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17506         + '">'
17507         + text
17508         + '</h'
17509         + level
17510         + '>\n';
17511     };
17512     
17513     Renderer.prototype.hr = function() {
17514       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17515     };
17516     
17517     Renderer.prototype.list = function(body, ordered) {
17518       var type = ordered ? 'ol' : 'ul';
17519       return '<' + type + '>\n' + body + '</' + type + '>\n';
17520     };
17521     
17522     Renderer.prototype.listitem = function(text) {
17523       return '<li>' + text + '</li>\n';
17524     };
17525     
17526     Renderer.prototype.paragraph = function(text) {
17527       return '<p>' + text + '</p>\n';
17528     };
17529     
17530     Renderer.prototype.table = function(header, body) {
17531       return '<table class="table table-striped">\n'
17532         + '<thead>\n'
17533         + header
17534         + '</thead>\n'
17535         + '<tbody>\n'
17536         + body
17537         + '</tbody>\n'
17538         + '</table>\n';
17539     };
17540     
17541     Renderer.prototype.tablerow = function(content) {
17542       return '<tr>\n' + content + '</tr>\n';
17543     };
17544     
17545     Renderer.prototype.tablecell = function(content, flags) {
17546       var type = flags.header ? 'th' : 'td';
17547       var tag = flags.align
17548         ? '<' + type + ' style="text-align:' + flags.align + '">'
17549         : '<' + type + '>';
17550       return tag + content + '</' + type + '>\n';
17551     };
17552     
17553     // span level renderer
17554     Renderer.prototype.strong = function(text) {
17555       return '<strong>' + text + '</strong>';
17556     };
17557     
17558     Renderer.prototype.em = function(text) {
17559       return '<em>' + text + '</em>';
17560     };
17561     
17562     Renderer.prototype.codespan = function(text) {
17563       return '<code>' + text + '</code>';
17564     };
17565     
17566     Renderer.prototype.br = function() {
17567       return this.options.xhtml ? '<br/>' : '<br>';
17568     };
17569     
17570     Renderer.prototype.del = function(text) {
17571       return '<del>' + text + '</del>';
17572     };
17573     
17574     Renderer.prototype.link = function(href, title, text) {
17575       if (this.options.sanitize) {
17576         try {
17577           var prot = decodeURIComponent(unescape(href))
17578             .replace(/[^\w:]/g, '')
17579             .toLowerCase();
17580         } catch (e) {
17581           return '';
17582         }
17583         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17584           return '';
17585         }
17586       }
17587       var out = '<a href="' + href + '"';
17588       if (title) {
17589         out += ' title="' + title + '"';
17590       }
17591       out += '>' + text + '</a>';
17592       return out;
17593     };
17594     
17595     Renderer.prototype.image = function(href, title, text) {
17596       var out = '<img src="' + href + '" alt="' + text + '"';
17597       if (title) {
17598         out += ' title="' + title + '"';
17599       }
17600       out += this.options.xhtml ? '/>' : '>';
17601       return out;
17602     };
17603     
17604     Renderer.prototype.text = function(text) {
17605       return text;
17606     };
17607     
17608     /**
17609      * Parsing & Compiling
17610      */
17611     
17612     function Parser(options) {
17613       this.tokens = [];
17614       this.token = null;
17615       this.options = options || marked.defaults;
17616       this.options.renderer = this.options.renderer || new Renderer;
17617       this.renderer = this.options.renderer;
17618       this.renderer.options = this.options;
17619     }
17620     
17621     /**
17622      * Static Parse Method
17623      */
17624     
17625     Parser.parse = function(src, options, renderer) {
17626       var parser = new Parser(options, renderer);
17627       return parser.parse(src);
17628     };
17629     
17630     /**
17631      * Parse Loop
17632      */
17633     
17634     Parser.prototype.parse = function(src) {
17635       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17636       this.tokens = src.reverse();
17637     
17638       var out = '';
17639       while (this.next()) {
17640         out += this.tok();
17641       }
17642     
17643       return out;
17644     };
17645     
17646     /**
17647      * Next Token
17648      */
17649     
17650     Parser.prototype.next = function() {
17651       return this.token = this.tokens.pop();
17652     };
17653     
17654     /**
17655      * Preview Next Token
17656      */
17657     
17658     Parser.prototype.peek = function() {
17659       return this.tokens[this.tokens.length - 1] || 0;
17660     };
17661     
17662     /**
17663      * Parse Text Tokens
17664      */
17665     
17666     Parser.prototype.parseText = function() {
17667       var body = this.token.text;
17668     
17669       while (this.peek().type === 'text') {
17670         body += '\n' + this.next().text;
17671       }
17672     
17673       return this.inline.output(body);
17674     };
17675     
17676     /**
17677      * Parse Current Token
17678      */
17679     
17680     Parser.prototype.tok = function() {
17681       switch (this.token.type) {
17682         case 'space': {
17683           return '';
17684         }
17685         case 'hr': {
17686           return this.renderer.hr();
17687         }
17688         case 'heading': {
17689           return this.renderer.heading(
17690             this.inline.output(this.token.text),
17691             this.token.depth,
17692             this.token.text);
17693         }
17694         case 'code': {
17695           return this.renderer.code(this.token.text,
17696             this.token.lang,
17697             this.token.escaped);
17698         }
17699         case 'table': {
17700           var header = ''
17701             , body = ''
17702             , i
17703             , row
17704             , cell
17705             , flags
17706             , j;
17707     
17708           // header
17709           cell = '';
17710           for (i = 0; i < this.token.header.length; i++) {
17711             flags = { header: true, align: this.token.align[i] };
17712             cell += this.renderer.tablecell(
17713               this.inline.output(this.token.header[i]),
17714               { header: true, align: this.token.align[i] }
17715             );
17716           }
17717           header += this.renderer.tablerow(cell);
17718     
17719           for (i = 0; i < this.token.cells.length; i++) {
17720             row = this.token.cells[i];
17721     
17722             cell = '';
17723             for (j = 0; j < row.length; j++) {
17724               cell += this.renderer.tablecell(
17725                 this.inline.output(row[j]),
17726                 { header: false, align: this.token.align[j] }
17727               );
17728             }
17729     
17730             body += this.renderer.tablerow(cell);
17731           }
17732           return this.renderer.table(header, body);
17733         }
17734         case 'blockquote_start': {
17735           var body = '';
17736     
17737           while (this.next().type !== 'blockquote_end') {
17738             body += this.tok();
17739           }
17740     
17741           return this.renderer.blockquote(body);
17742         }
17743         case 'list_start': {
17744           var body = ''
17745             , ordered = this.token.ordered;
17746     
17747           while (this.next().type !== 'list_end') {
17748             body += this.tok();
17749           }
17750     
17751           return this.renderer.list(body, ordered);
17752         }
17753         case 'list_item_start': {
17754           var body = '';
17755     
17756           while (this.next().type !== 'list_item_end') {
17757             body += this.token.type === 'text'
17758               ? this.parseText()
17759               : this.tok();
17760           }
17761     
17762           return this.renderer.listitem(body);
17763         }
17764         case 'loose_item_start': {
17765           var body = '';
17766     
17767           while (this.next().type !== 'list_item_end') {
17768             body += this.tok();
17769           }
17770     
17771           return this.renderer.listitem(body);
17772         }
17773         case 'html': {
17774           var html = !this.token.pre && !this.options.pedantic
17775             ? this.inline.output(this.token.text)
17776             : this.token.text;
17777           return this.renderer.html(html);
17778         }
17779         case 'paragraph': {
17780           return this.renderer.paragraph(this.inline.output(this.token.text));
17781         }
17782         case 'text': {
17783           return this.renderer.paragraph(this.parseText());
17784         }
17785       }
17786     };
17787     
17788     /**
17789      * Helpers
17790      */
17791     
17792     function escape(html, encode) {
17793       return html
17794         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17795         .replace(/</g, '&lt;')
17796         .replace(/>/g, '&gt;')
17797         .replace(/"/g, '&quot;')
17798         .replace(/'/g, '&#39;');
17799     }
17800     
17801     function unescape(html) {
17802         // explicitly match decimal, hex, and named HTML entities 
17803       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17804         n = n.toLowerCase();
17805         if (n === 'colon') { return ':'; }
17806         if (n.charAt(0) === '#') {
17807           return n.charAt(1) === 'x'
17808             ? String.fromCharCode(parseInt(n.substring(2), 16))
17809             : String.fromCharCode(+n.substring(1));
17810         }
17811         return '';
17812       });
17813     }
17814     
17815     function replace(regex, opt) {
17816       regex = regex.source;
17817       opt = opt || '';
17818       return function self(name, val) {
17819         if (!name) { return new RegExp(regex, opt); }
17820         val = val.source || val;
17821         val = val.replace(/(^|[^\[])\^/g, '$1');
17822         regex = regex.replace(name, val);
17823         return self;
17824       };
17825     }
17826     
17827     function noop() {}
17828     noop.exec = noop;
17829     
17830     function merge(obj) {
17831       var i = 1
17832         , target
17833         , key;
17834     
17835       for (; i < arguments.length; i++) {
17836         target = arguments[i];
17837         for (key in target) {
17838           if (Object.prototype.hasOwnProperty.call(target, key)) {
17839             obj[key] = target[key];
17840           }
17841         }
17842       }
17843     
17844       return obj;
17845     }
17846     
17847     
17848     /**
17849      * Marked
17850      */
17851     
17852     function marked(src, opt, callback) {
17853       if (callback || typeof opt === 'function') {
17854         if (!callback) {
17855           callback = opt;
17856           opt = null;
17857         }
17858     
17859         opt = merge({}, marked.defaults, opt || {});
17860     
17861         var highlight = opt.highlight
17862           , tokens
17863           , pending
17864           , i = 0;
17865     
17866         try {
17867           tokens = Lexer.lex(src, opt)
17868         } catch (e) {
17869           return callback(e);
17870         }
17871     
17872         pending = tokens.length;
17873     
17874         var done = function(err) {
17875           if (err) {
17876             opt.highlight = highlight;
17877             return callback(err);
17878           }
17879     
17880           var out;
17881     
17882           try {
17883             out = Parser.parse(tokens, opt);
17884           } catch (e) {
17885             err = e;
17886           }
17887     
17888           opt.highlight = highlight;
17889     
17890           return err
17891             ? callback(err)
17892             : callback(null, out);
17893         };
17894     
17895         if (!highlight || highlight.length < 3) {
17896           return done();
17897         }
17898     
17899         delete opt.highlight;
17900     
17901         if (!pending) { return done(); }
17902     
17903         for (; i < tokens.length; i++) {
17904           (function(token) {
17905             if (token.type !== 'code') {
17906               return --pending || done();
17907             }
17908             return highlight(token.text, token.lang, function(err, code) {
17909               if (err) { return done(err); }
17910               if (code == null || code === token.text) {
17911                 return --pending || done();
17912               }
17913               token.text = code;
17914               token.escaped = true;
17915               --pending || done();
17916             });
17917           })(tokens[i]);
17918         }
17919     
17920         return;
17921       }
17922       try {
17923         if (opt) { opt = merge({}, marked.defaults, opt); }
17924         return Parser.parse(Lexer.lex(src, opt), opt);
17925       } catch (e) {
17926         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17927         if ((opt || marked.defaults).silent) {
17928           return '<p>An error occured:</p><pre>'
17929             + escape(e.message + '', true)
17930             + '</pre>';
17931         }
17932         throw e;
17933       }
17934     }
17935     
17936     /**
17937      * Options
17938      */
17939     
17940     marked.options =
17941     marked.setOptions = function(opt) {
17942       merge(marked.defaults, opt);
17943       return marked;
17944     };
17945     
17946     marked.defaults = {
17947       gfm: true,
17948       tables: true,
17949       breaks: false,
17950       pedantic: false,
17951       sanitize: false,
17952       sanitizer: null,
17953       mangle: true,
17954       smartLists: false,
17955       silent: false,
17956       highlight: null,
17957       langPrefix: 'lang-',
17958       smartypants: false,
17959       headerPrefix: '',
17960       renderer: new Renderer,
17961       xhtml: false
17962     };
17963     
17964     /**
17965      * Expose
17966      */
17967     
17968     marked.Parser = Parser;
17969     marked.parser = Parser.parse;
17970     
17971     marked.Renderer = Renderer;
17972     
17973     marked.Lexer = Lexer;
17974     marked.lexer = Lexer.lex;
17975     
17976     marked.InlineLexer = InlineLexer;
17977     marked.inlineLexer = InlineLexer.output;
17978     
17979     marked.parse = marked;
17980     
17981     Roo.Markdown.marked = marked;
17982
17983 })();/*
17984  * Based on:
17985  * Ext JS Library 1.1.1
17986  * Copyright(c) 2006-2007, Ext JS, LLC.
17987  *
17988  * Originally Released Under LGPL - original licence link has changed is not relivant.
17989  *
17990  * Fork - LGPL
17991  * <script type="text/javascript">
17992  */
17993
17994
17995
17996 /*
17997  * These classes are derivatives of the similarly named classes in the YUI Library.
17998  * The original license:
17999  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18000  * Code licensed under the BSD License:
18001  * http://developer.yahoo.net/yui/license.txt
18002  */
18003
18004 (function() {
18005
18006 var Event=Roo.EventManager;
18007 var Dom=Roo.lib.Dom;
18008
18009 /**
18010  * @class Roo.dd.DragDrop
18011  * @extends Roo.util.Observable
18012  * Defines the interface and base operation of items that that can be
18013  * dragged or can be drop targets.  It was designed to be extended, overriding
18014  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18015  * Up to three html elements can be associated with a DragDrop instance:
18016  * <ul>
18017  * <li>linked element: the element that is passed into the constructor.
18018  * This is the element which defines the boundaries for interaction with
18019  * other DragDrop objects.</li>
18020  * <li>handle element(s): The drag operation only occurs if the element that
18021  * was clicked matches a handle element.  By default this is the linked
18022  * element, but there are times that you will want only a portion of the
18023  * linked element to initiate the drag operation, and the setHandleElId()
18024  * method provides a way to define this.</li>
18025  * <li>drag element: this represents the element that would be moved along
18026  * with the cursor during a drag operation.  By default, this is the linked
18027  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
18028  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18029  * </li>
18030  * </ul>
18031  * This class should not be instantiated until the onload event to ensure that
18032  * the associated elements are available.
18033  * The following would define a DragDrop obj that would interact with any
18034  * other DragDrop obj in the "group1" group:
18035  * <pre>
18036  *  dd = new Roo.dd.DragDrop("div1", "group1");
18037  * </pre>
18038  * Since none of the event handlers have been implemented, nothing would
18039  * actually happen if you were to run the code above.  Normally you would
18040  * override this class or one of the default implementations, but you can
18041  * also override the methods you want on an instance of the class...
18042  * <pre>
18043  *  dd.onDragDrop = function(e, id) {
18044  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
18045  *  }
18046  * </pre>
18047  * @constructor
18048  * @param {String} id of the element that is linked to this instance
18049  * @param {String} sGroup the group of related DragDrop objects
18050  * @param {object} config an object containing configurable attributes
18051  *                Valid properties for DragDrop:
18052  *                    padding, isTarget, maintainOffset, primaryButtonOnly
18053  */
18054 Roo.dd.DragDrop = function(id, sGroup, config) {
18055     if (id) {
18056         this.init(id, sGroup, config);
18057     }
18058     
18059 };
18060
18061 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18062
18063     /**
18064      * The id of the element associated with this object.  This is what we
18065      * refer to as the "linked element" because the size and position of
18066      * this element is used to determine when the drag and drop objects have
18067      * interacted.
18068      * @property id
18069      * @type String
18070      */
18071     id: null,
18072
18073     /**
18074      * Configuration attributes passed into the constructor
18075      * @property config
18076      * @type object
18077      */
18078     config: null,
18079
18080     /**
18081      * The id of the element that will be dragged.  By default this is same
18082      * as the linked element , but could be changed to another element. Ex:
18083      * Roo.dd.DDProxy
18084      * @property dragElId
18085      * @type String
18086      * @private
18087      */
18088     dragElId: null,
18089
18090     /**
18091      * the id of the element that initiates the drag operation.  By default
18092      * this is the linked element, but could be changed to be a child of this
18093      * element.  This lets us do things like only starting the drag when the
18094      * header element within the linked html element is clicked.
18095      * @property handleElId
18096      * @type String
18097      * @private
18098      */
18099     handleElId: null,
18100
18101     /**
18102      * An associative array of HTML tags that will be ignored if clicked.
18103      * @property invalidHandleTypes
18104      * @type {string: string}
18105      */
18106     invalidHandleTypes: null,
18107
18108     /**
18109      * An associative array of ids for elements that will be ignored if clicked
18110      * @property invalidHandleIds
18111      * @type {string: string}
18112      */
18113     invalidHandleIds: null,
18114
18115     /**
18116      * An indexted array of css class names for elements that will be ignored
18117      * if clicked.
18118      * @property invalidHandleClasses
18119      * @type string[]
18120      */
18121     invalidHandleClasses: null,
18122
18123     /**
18124      * The linked element's absolute X position at the time the drag was
18125      * started
18126      * @property startPageX
18127      * @type int
18128      * @private
18129      */
18130     startPageX: 0,
18131
18132     /**
18133      * The linked element's absolute X position at the time the drag was
18134      * started
18135      * @property startPageY
18136      * @type int
18137      * @private
18138      */
18139     startPageY: 0,
18140
18141     /**
18142      * The group defines a logical collection of DragDrop objects that are
18143      * related.  Instances only get events when interacting with other
18144      * DragDrop object in the same group.  This lets us define multiple
18145      * groups using a single DragDrop subclass if we want.
18146      * @property groups
18147      * @type {string: string}
18148      */
18149     groups: null,
18150
18151     /**
18152      * Individual drag/drop instances can be locked.  This will prevent
18153      * onmousedown start drag.
18154      * @property locked
18155      * @type boolean
18156      * @private
18157      */
18158     locked: false,
18159
18160     /**
18161      * Lock this instance
18162      * @method lock
18163      */
18164     lock: function() { this.locked = true; },
18165
18166     /**
18167      * Unlock this instace
18168      * @method unlock
18169      */
18170     unlock: function() { this.locked = false; },
18171
18172     /**
18173      * By default, all insances can be a drop target.  This can be disabled by
18174      * setting isTarget to false.
18175      * @method isTarget
18176      * @type boolean
18177      */
18178     isTarget: true,
18179
18180     /**
18181      * The padding configured for this drag and drop object for calculating
18182      * the drop zone intersection with this object.
18183      * @method padding
18184      * @type int[]
18185      */
18186     padding: null,
18187
18188     /**
18189      * Cached reference to the linked element
18190      * @property _domRef
18191      * @private
18192      */
18193     _domRef: null,
18194
18195     /**
18196      * Internal typeof flag
18197      * @property __ygDragDrop
18198      * @private
18199      */
18200     __ygDragDrop: true,
18201
18202     /**
18203      * Set to true when horizontal contraints are applied
18204      * @property constrainX
18205      * @type boolean
18206      * @private
18207      */
18208     constrainX: false,
18209
18210     /**
18211      * Set to true when vertical contraints are applied
18212      * @property constrainY
18213      * @type boolean
18214      * @private
18215      */
18216     constrainY: false,
18217
18218     /**
18219      * The left constraint
18220      * @property minX
18221      * @type int
18222      * @private
18223      */
18224     minX: 0,
18225
18226     /**
18227      * The right constraint
18228      * @property maxX
18229      * @type int
18230      * @private
18231      */
18232     maxX: 0,
18233
18234     /**
18235      * The up constraint
18236      * @property minY
18237      * @type int
18238      * @type int
18239      * @private
18240      */
18241     minY: 0,
18242
18243     /**
18244      * The down constraint
18245      * @property maxY
18246      * @type int
18247      * @private
18248      */
18249     maxY: 0,
18250
18251     /**
18252      * Maintain offsets when we resetconstraints.  Set to true when you want
18253      * the position of the element relative to its parent to stay the same
18254      * when the page changes
18255      *
18256      * @property maintainOffset
18257      * @type boolean
18258      */
18259     maintainOffset: false,
18260
18261     /**
18262      * Array of pixel locations the element will snap to if we specified a
18263      * horizontal graduation/interval.  This array is generated automatically
18264      * when you define a tick interval.
18265      * @property xTicks
18266      * @type int[]
18267      */
18268     xTicks: null,
18269
18270     /**
18271      * Array of pixel locations the element will snap to if we specified a
18272      * vertical graduation/interval.  This array is generated automatically
18273      * when you define a tick interval.
18274      * @property yTicks
18275      * @type int[]
18276      */
18277     yTicks: null,
18278
18279     /**
18280      * By default the drag and drop instance will only respond to the primary
18281      * button click (left button for a right-handed mouse).  Set to true to
18282      * allow drag and drop to start with any mouse click that is propogated
18283      * by the browser
18284      * @property primaryButtonOnly
18285      * @type boolean
18286      */
18287     primaryButtonOnly: true,
18288
18289     /**
18290      * The availabe property is false until the linked dom element is accessible.
18291      * @property available
18292      * @type boolean
18293      */
18294     available: false,
18295
18296     /**
18297      * By default, drags can only be initiated if the mousedown occurs in the
18298      * region the linked element is.  This is done in part to work around a
18299      * bug in some browsers that mis-report the mousedown if the previous
18300      * mouseup happened outside of the window.  This property is set to true
18301      * if outer handles are defined.
18302      *
18303      * @property hasOuterHandles
18304      * @type boolean
18305      * @default false
18306      */
18307     hasOuterHandles: false,
18308
18309     /**
18310      * Code that executes immediately before the startDrag event
18311      * @method b4StartDrag
18312      * @private
18313      */
18314     b4StartDrag: function(x, y) { },
18315
18316     /**
18317      * Abstract method called after a drag/drop object is clicked
18318      * and the drag or mousedown time thresholds have beeen met.
18319      * @method startDrag
18320      * @param {int} X click location
18321      * @param {int} Y click location
18322      */
18323     startDrag: function(x, y) { /* override this */ },
18324
18325     /**
18326      * Code that executes immediately before the onDrag event
18327      * @method b4Drag
18328      * @private
18329      */
18330     b4Drag: function(e) { },
18331
18332     /**
18333      * Abstract method called during the onMouseMove event while dragging an
18334      * object.
18335      * @method onDrag
18336      * @param {Event} e the mousemove event
18337      */
18338     onDrag: function(e) { /* override this */ },
18339
18340     /**
18341      * Abstract method called when this element fist begins hovering over
18342      * another DragDrop obj
18343      * @method onDragEnter
18344      * @param {Event} e the mousemove event
18345      * @param {String|DragDrop[]} id In POINT mode, the element
18346      * id this is hovering over.  In INTERSECT mode, an array of one or more
18347      * dragdrop items being hovered over.
18348      */
18349     onDragEnter: function(e, id) { /* override this */ },
18350
18351     /**
18352      * Code that executes immediately before the onDragOver event
18353      * @method b4DragOver
18354      * @private
18355      */
18356     b4DragOver: function(e) { },
18357
18358     /**
18359      * Abstract method called when this element is hovering over another
18360      * DragDrop obj
18361      * @method onDragOver
18362      * @param {Event} e the mousemove event
18363      * @param {String|DragDrop[]} id In POINT mode, the element
18364      * id this is hovering over.  In INTERSECT mode, an array of dd items
18365      * being hovered over.
18366      */
18367     onDragOver: function(e, id) { /* override this */ },
18368
18369     /**
18370      * Code that executes immediately before the onDragOut event
18371      * @method b4DragOut
18372      * @private
18373      */
18374     b4DragOut: function(e) { },
18375
18376     /**
18377      * Abstract method called when we are no longer hovering over an element
18378      * @method onDragOut
18379      * @param {Event} e the mousemove event
18380      * @param {String|DragDrop[]} id In POINT mode, the element
18381      * id this was hovering over.  In INTERSECT mode, an array of dd items
18382      * that the mouse is no longer over.
18383      */
18384     onDragOut: function(e, id) { /* override this */ },
18385
18386     /**
18387      * Code that executes immediately before the onDragDrop event
18388      * @method b4DragDrop
18389      * @private
18390      */
18391     b4DragDrop: function(e) { },
18392
18393     /**
18394      * Abstract method called when this item is dropped on another DragDrop
18395      * obj
18396      * @method onDragDrop
18397      * @param {Event} e the mouseup event
18398      * @param {String|DragDrop[]} id In POINT mode, the element
18399      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18400      * was dropped on.
18401      */
18402     onDragDrop: function(e, id) { /* override this */ },
18403
18404     /**
18405      * Abstract method called when this item is dropped on an area with no
18406      * drop target
18407      * @method onInvalidDrop
18408      * @param {Event} e the mouseup event
18409      */
18410     onInvalidDrop: function(e) { /* override this */ },
18411
18412     /**
18413      * Code that executes immediately before the endDrag event
18414      * @method b4EndDrag
18415      * @private
18416      */
18417     b4EndDrag: function(e) { },
18418
18419     /**
18420      * Fired when we are done dragging the object
18421      * @method endDrag
18422      * @param {Event} e the mouseup event
18423      */
18424     endDrag: function(e) { /* override this */ },
18425
18426     /**
18427      * Code executed immediately before the onMouseDown event
18428      * @method b4MouseDown
18429      * @param {Event} e the mousedown event
18430      * @private
18431      */
18432     b4MouseDown: function(e) {  },
18433
18434     /**
18435      * Event handler that fires when a drag/drop obj gets a mousedown
18436      * @method onMouseDown
18437      * @param {Event} e the mousedown event
18438      */
18439     onMouseDown: function(e) { /* override this */ },
18440
18441     /**
18442      * Event handler that fires when a drag/drop obj gets a mouseup
18443      * @method onMouseUp
18444      * @param {Event} e the mouseup event
18445      */
18446     onMouseUp: function(e) { /* override this */ },
18447
18448     /**
18449      * Override the onAvailable method to do what is needed after the initial
18450      * position was determined.
18451      * @method onAvailable
18452      */
18453     onAvailable: function () {
18454     },
18455
18456     /*
18457      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18458      * @type Object
18459      */
18460     defaultPadding : {left:0, right:0, top:0, bottom:0},
18461
18462     /*
18463      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18464  *
18465  * Usage:
18466  <pre><code>
18467  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18468                 { dragElId: "existingProxyDiv" });
18469  dd.startDrag = function(){
18470      this.constrainTo("parent-id");
18471  };
18472  </code></pre>
18473  * Or you can initalize it using the {@link Roo.Element} object:
18474  <pre><code>
18475  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18476      startDrag : function(){
18477          this.constrainTo("parent-id");
18478      }
18479  });
18480  </code></pre>
18481      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18482      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18483      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18484      * an object containing the sides to pad. For example: {right:10, bottom:10}
18485      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18486      */
18487     constrainTo : function(constrainTo, pad, inContent){
18488         if(typeof pad == "number"){
18489             pad = {left: pad, right:pad, top:pad, bottom:pad};
18490         }
18491         pad = pad || this.defaultPadding;
18492         var b = Roo.get(this.getEl()).getBox();
18493         var ce = Roo.get(constrainTo);
18494         var s = ce.getScroll();
18495         var c, cd = ce.dom;
18496         if(cd == document.body){
18497             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18498         }else{
18499             xy = ce.getXY();
18500             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18501         }
18502
18503
18504         var topSpace = b.y - c.y;
18505         var leftSpace = b.x - c.x;
18506
18507         this.resetConstraints();
18508         this.setXConstraint(leftSpace - (pad.left||0), // left
18509                 c.width - leftSpace - b.width - (pad.right||0) //right
18510         );
18511         this.setYConstraint(topSpace - (pad.top||0), //top
18512                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18513         );
18514     },
18515
18516     /**
18517      * Returns a reference to the linked element
18518      * @method getEl
18519      * @return {HTMLElement} the html element
18520      */
18521     getEl: function() {
18522         if (!this._domRef) {
18523             this._domRef = Roo.getDom(this.id);
18524         }
18525
18526         return this._domRef;
18527     },
18528
18529     /**
18530      * Returns a reference to the actual element to drag.  By default this is
18531      * the same as the html element, but it can be assigned to another
18532      * element. An example of this can be found in Roo.dd.DDProxy
18533      * @method getDragEl
18534      * @return {HTMLElement} the html element
18535      */
18536     getDragEl: function() {
18537         return Roo.getDom(this.dragElId);
18538     },
18539
18540     /**
18541      * Sets up the DragDrop object.  Must be called in the constructor of any
18542      * Roo.dd.DragDrop subclass
18543      * @method init
18544      * @param id the id of the linked element
18545      * @param {String} sGroup the group of related items
18546      * @param {object} config configuration attributes
18547      */
18548     init: function(id, sGroup, config) {
18549         this.initTarget(id, sGroup, config);
18550         if (!Roo.isTouch) {
18551             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18552         }
18553         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18554         // Event.on(this.id, "selectstart", Event.preventDefault);
18555     },
18556
18557     /**
18558      * Initializes Targeting functionality only... the object does not
18559      * get a mousedown handler.
18560      * @method initTarget
18561      * @param id the id of the linked element
18562      * @param {String} sGroup the group of related items
18563      * @param {object} config configuration attributes
18564      */
18565     initTarget: function(id, sGroup, config) {
18566
18567         // configuration attributes
18568         this.config = config || {};
18569
18570         // create a local reference to the drag and drop manager
18571         this.DDM = Roo.dd.DDM;
18572         // initialize the groups array
18573         this.groups = {};
18574
18575         // assume that we have an element reference instead of an id if the
18576         // parameter is not a string
18577         if (typeof id !== "string") {
18578             id = Roo.id(id);
18579         }
18580
18581         // set the id
18582         this.id = id;
18583
18584         // add to an interaction group
18585         this.addToGroup((sGroup) ? sGroup : "default");
18586
18587         // We don't want to register this as the handle with the manager
18588         // so we just set the id rather than calling the setter.
18589         this.handleElId = id;
18590
18591         // the linked element is the element that gets dragged by default
18592         this.setDragElId(id);
18593
18594         // by default, clicked anchors will not start drag operations.
18595         this.invalidHandleTypes = { A: "A" };
18596         this.invalidHandleIds = {};
18597         this.invalidHandleClasses = [];
18598
18599         this.applyConfig();
18600
18601         this.handleOnAvailable();
18602     },
18603
18604     /**
18605      * Applies the configuration parameters that were passed into the constructor.
18606      * This is supposed to happen at each level through the inheritance chain.  So
18607      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18608      * DragDrop in order to get all of the parameters that are available in
18609      * each object.
18610      * @method applyConfig
18611      */
18612     applyConfig: function() {
18613
18614         // configurable properties:
18615         //    padding, isTarget, maintainOffset, primaryButtonOnly
18616         this.padding           = this.config.padding || [0, 0, 0, 0];
18617         this.isTarget          = (this.config.isTarget !== false);
18618         this.maintainOffset    = (this.config.maintainOffset);
18619         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18620
18621     },
18622
18623     /**
18624      * Executed when the linked element is available
18625      * @method handleOnAvailable
18626      * @private
18627      */
18628     handleOnAvailable: function() {
18629         this.available = true;
18630         this.resetConstraints();
18631         this.onAvailable();
18632     },
18633
18634      /**
18635      * Configures the padding for the target zone in px.  Effectively expands
18636      * (or reduces) the virtual object size for targeting calculations.
18637      * Supports css-style shorthand; if only one parameter is passed, all sides
18638      * will have that padding, and if only two are passed, the top and bottom
18639      * will have the first param, the left and right the second.
18640      * @method setPadding
18641      * @param {int} iTop    Top pad
18642      * @param {int} iRight  Right pad
18643      * @param {int} iBot    Bot pad
18644      * @param {int} iLeft   Left pad
18645      */
18646     setPadding: function(iTop, iRight, iBot, iLeft) {
18647         // this.padding = [iLeft, iRight, iTop, iBot];
18648         if (!iRight && 0 !== iRight) {
18649             this.padding = [iTop, iTop, iTop, iTop];
18650         } else if (!iBot && 0 !== iBot) {
18651             this.padding = [iTop, iRight, iTop, iRight];
18652         } else {
18653             this.padding = [iTop, iRight, iBot, iLeft];
18654         }
18655     },
18656
18657     /**
18658      * Stores the initial placement of the linked element.
18659      * @method setInitialPosition
18660      * @param {int} diffX   the X offset, default 0
18661      * @param {int} diffY   the Y offset, default 0
18662      */
18663     setInitPosition: function(diffX, diffY) {
18664         var el = this.getEl();
18665
18666         if (!this.DDM.verifyEl(el)) {
18667             return;
18668         }
18669
18670         var dx = diffX || 0;
18671         var dy = diffY || 0;
18672
18673         var p = Dom.getXY( el );
18674
18675         this.initPageX = p[0] - dx;
18676         this.initPageY = p[1] - dy;
18677
18678         this.lastPageX = p[0];
18679         this.lastPageY = p[1];
18680
18681
18682         this.setStartPosition(p);
18683     },
18684
18685     /**
18686      * Sets the start position of the element.  This is set when the obj
18687      * is initialized, the reset when a drag is started.
18688      * @method setStartPosition
18689      * @param pos current position (from previous lookup)
18690      * @private
18691      */
18692     setStartPosition: function(pos) {
18693         var p = pos || Dom.getXY( this.getEl() );
18694         this.deltaSetXY = null;
18695
18696         this.startPageX = p[0];
18697         this.startPageY = p[1];
18698     },
18699
18700     /**
18701      * Add this instance to a group of related drag/drop objects.  All
18702      * instances belong to at least one group, and can belong to as many
18703      * groups as needed.
18704      * @method addToGroup
18705      * @param sGroup {string} the name of the group
18706      */
18707     addToGroup: function(sGroup) {
18708         this.groups[sGroup] = true;
18709         this.DDM.regDragDrop(this, sGroup);
18710     },
18711
18712     /**
18713      * Remove's this instance from the supplied interaction group
18714      * @method removeFromGroup
18715      * @param {string}  sGroup  The group to drop
18716      */
18717     removeFromGroup: function(sGroup) {
18718         if (this.groups[sGroup]) {
18719             delete this.groups[sGroup];
18720         }
18721
18722         this.DDM.removeDDFromGroup(this, sGroup);
18723     },
18724
18725     /**
18726      * Allows you to specify that an element other than the linked element
18727      * will be moved with the cursor during a drag
18728      * @method setDragElId
18729      * @param id {string} the id of the element that will be used to initiate the drag
18730      */
18731     setDragElId: function(id) {
18732         this.dragElId = id;
18733     },
18734
18735     /**
18736      * Allows you to specify a child of the linked element that should be
18737      * used to initiate the drag operation.  An example of this would be if
18738      * you have a content div with text and links.  Clicking anywhere in the
18739      * content area would normally start the drag operation.  Use this method
18740      * to specify that an element inside of the content div is the element
18741      * that starts the drag operation.
18742      * @method setHandleElId
18743      * @param id {string} the id of the element that will be used to
18744      * initiate the drag.
18745      */
18746     setHandleElId: function(id) {
18747         if (typeof id !== "string") {
18748             id = Roo.id(id);
18749         }
18750         this.handleElId = id;
18751         this.DDM.regHandle(this.id, id);
18752     },
18753
18754     /**
18755      * Allows you to set an element outside of the linked element as a drag
18756      * handle
18757      * @method setOuterHandleElId
18758      * @param id the id of the element that will be used to initiate the drag
18759      */
18760     setOuterHandleElId: function(id) {
18761         if (typeof id !== "string") {
18762             id = Roo.id(id);
18763         }
18764         Event.on(id, "mousedown",
18765                 this.handleMouseDown, this);
18766         this.setHandleElId(id);
18767
18768         this.hasOuterHandles = true;
18769     },
18770
18771     /**
18772      * Remove all drag and drop hooks for this element
18773      * @method unreg
18774      */
18775     unreg: function() {
18776         Event.un(this.id, "mousedown",
18777                 this.handleMouseDown);
18778         Event.un(this.id, "touchstart",
18779                 this.handleMouseDown);
18780         this._domRef = null;
18781         this.DDM._remove(this);
18782     },
18783
18784     destroy : function(){
18785         this.unreg();
18786     },
18787
18788     /**
18789      * Returns true if this instance is locked, or the drag drop mgr is locked
18790      * (meaning that all drag/drop is disabled on the page.)
18791      * @method isLocked
18792      * @return {boolean} true if this obj or all drag/drop is locked, else
18793      * false
18794      */
18795     isLocked: function() {
18796         return (this.DDM.isLocked() || this.locked);
18797     },
18798
18799     /**
18800      * Fired when this object is clicked
18801      * @method handleMouseDown
18802      * @param {Event} e
18803      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18804      * @private
18805      */
18806     handleMouseDown: function(e, oDD){
18807      
18808         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18809             //Roo.log('not touch/ button !=0');
18810             return;
18811         }
18812         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18813             return; // double touch..
18814         }
18815         
18816
18817         if (this.isLocked()) {
18818             //Roo.log('locked');
18819             return;
18820         }
18821
18822         this.DDM.refreshCache(this.groups);
18823 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18824         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18825         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18826             //Roo.log('no outer handes or not over target');
18827                 // do nothing.
18828         } else {
18829 //            Roo.log('check validator');
18830             if (this.clickValidator(e)) {
18831 //                Roo.log('validate success');
18832                 // set the initial element position
18833                 this.setStartPosition();
18834
18835
18836                 this.b4MouseDown(e);
18837                 this.onMouseDown(e);
18838
18839                 this.DDM.handleMouseDown(e, this);
18840
18841                 this.DDM.stopEvent(e);
18842             } else {
18843
18844
18845             }
18846         }
18847     },
18848
18849     clickValidator: function(e) {
18850         var target = e.getTarget();
18851         return ( this.isValidHandleChild(target) &&
18852                     (this.id == this.handleElId ||
18853                         this.DDM.handleWasClicked(target, this.id)) );
18854     },
18855
18856     /**
18857      * Allows you to specify a tag name that should not start a drag operation
18858      * when clicked.  This is designed to facilitate embedding links within a
18859      * drag handle that do something other than start the drag.
18860      * @method addInvalidHandleType
18861      * @param {string} tagName the type of element to exclude
18862      */
18863     addInvalidHandleType: function(tagName) {
18864         var type = tagName.toUpperCase();
18865         this.invalidHandleTypes[type] = type;
18866     },
18867
18868     /**
18869      * Lets you to specify an element id for a child of a drag handle
18870      * that should not initiate a drag
18871      * @method addInvalidHandleId
18872      * @param {string} id the element id of the element you wish to ignore
18873      */
18874     addInvalidHandleId: function(id) {
18875         if (typeof id !== "string") {
18876             id = Roo.id(id);
18877         }
18878         this.invalidHandleIds[id] = id;
18879     },
18880
18881     /**
18882      * Lets you specify a css class of elements that will not initiate a drag
18883      * @method addInvalidHandleClass
18884      * @param {string} cssClass the class of the elements you wish to ignore
18885      */
18886     addInvalidHandleClass: function(cssClass) {
18887         this.invalidHandleClasses.push(cssClass);
18888     },
18889
18890     /**
18891      * Unsets an excluded tag name set by addInvalidHandleType
18892      * @method removeInvalidHandleType
18893      * @param {string} tagName the type of element to unexclude
18894      */
18895     removeInvalidHandleType: function(tagName) {
18896         var type = tagName.toUpperCase();
18897         // this.invalidHandleTypes[type] = null;
18898         delete this.invalidHandleTypes[type];
18899     },
18900
18901     /**
18902      * Unsets an invalid handle id
18903      * @method removeInvalidHandleId
18904      * @param {string} id the id of the element to re-enable
18905      */
18906     removeInvalidHandleId: function(id) {
18907         if (typeof id !== "string") {
18908             id = Roo.id(id);
18909         }
18910         delete this.invalidHandleIds[id];
18911     },
18912
18913     /**
18914      * Unsets an invalid css class
18915      * @method removeInvalidHandleClass
18916      * @param {string} cssClass the class of the element(s) you wish to
18917      * re-enable
18918      */
18919     removeInvalidHandleClass: function(cssClass) {
18920         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18921             if (this.invalidHandleClasses[i] == cssClass) {
18922                 delete this.invalidHandleClasses[i];
18923             }
18924         }
18925     },
18926
18927     /**
18928      * Checks the tag exclusion list to see if this click should be ignored
18929      * @method isValidHandleChild
18930      * @param {HTMLElement} node the HTMLElement to evaluate
18931      * @return {boolean} true if this is a valid tag type, false if not
18932      */
18933     isValidHandleChild: function(node) {
18934
18935         var valid = true;
18936         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18937         var nodeName;
18938         try {
18939             nodeName = node.nodeName.toUpperCase();
18940         } catch(e) {
18941             nodeName = node.nodeName;
18942         }
18943         valid = valid && !this.invalidHandleTypes[nodeName];
18944         valid = valid && !this.invalidHandleIds[node.id];
18945
18946         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18947             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18948         }
18949
18950
18951         return valid;
18952
18953     },
18954
18955     /**
18956      * Create the array of horizontal tick marks if an interval was specified
18957      * in setXConstraint().
18958      * @method setXTicks
18959      * @private
18960      */
18961     setXTicks: function(iStartX, iTickSize) {
18962         this.xTicks = [];
18963         this.xTickSize = iTickSize;
18964
18965         var tickMap = {};
18966
18967         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18968             if (!tickMap[i]) {
18969                 this.xTicks[this.xTicks.length] = i;
18970                 tickMap[i] = true;
18971             }
18972         }
18973
18974         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18975             if (!tickMap[i]) {
18976                 this.xTicks[this.xTicks.length] = i;
18977                 tickMap[i] = true;
18978             }
18979         }
18980
18981         this.xTicks.sort(this.DDM.numericSort) ;
18982     },
18983
18984     /**
18985      * Create the array of vertical tick marks if an interval was specified in
18986      * setYConstraint().
18987      * @method setYTicks
18988      * @private
18989      */
18990     setYTicks: function(iStartY, iTickSize) {
18991         this.yTicks = [];
18992         this.yTickSize = iTickSize;
18993
18994         var tickMap = {};
18995
18996         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18997             if (!tickMap[i]) {
18998                 this.yTicks[this.yTicks.length] = i;
18999                 tickMap[i] = true;
19000             }
19001         }
19002
19003         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19004             if (!tickMap[i]) {
19005                 this.yTicks[this.yTicks.length] = i;
19006                 tickMap[i] = true;
19007             }
19008         }
19009
19010         this.yTicks.sort(this.DDM.numericSort) ;
19011     },
19012
19013     /**
19014      * By default, the element can be dragged any place on the screen.  Use
19015      * this method to limit the horizontal travel of the element.  Pass in
19016      * 0,0 for the parameters if you want to lock the drag to the y axis.
19017      * @method setXConstraint
19018      * @param {int} iLeft the number of pixels the element can move to the left
19019      * @param {int} iRight the number of pixels the element can move to the
19020      * right
19021      * @param {int} iTickSize optional parameter for specifying that the
19022      * element
19023      * should move iTickSize pixels at a time.
19024      */
19025     setXConstraint: function(iLeft, iRight, iTickSize) {
19026         this.leftConstraint = iLeft;
19027         this.rightConstraint = iRight;
19028
19029         this.minX = this.initPageX - iLeft;
19030         this.maxX = this.initPageX + iRight;
19031         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19032
19033         this.constrainX = true;
19034     },
19035
19036     /**
19037      * Clears any constraints applied to this instance.  Also clears ticks
19038      * since they can't exist independent of a constraint at this time.
19039      * @method clearConstraints
19040      */
19041     clearConstraints: function() {
19042         this.constrainX = false;
19043         this.constrainY = false;
19044         this.clearTicks();
19045     },
19046
19047     /**
19048      * Clears any tick interval defined for this instance
19049      * @method clearTicks
19050      */
19051     clearTicks: function() {
19052         this.xTicks = null;
19053         this.yTicks = null;
19054         this.xTickSize = 0;
19055         this.yTickSize = 0;
19056     },
19057
19058     /**
19059      * By default, the element can be dragged any place on the screen.  Set
19060      * this to limit the vertical travel of the element.  Pass in 0,0 for the
19061      * parameters if you want to lock the drag to the x axis.
19062      * @method setYConstraint
19063      * @param {int} iUp the number of pixels the element can move up
19064      * @param {int} iDown the number of pixels the element can move down
19065      * @param {int} iTickSize optional parameter for specifying that the
19066      * element should move iTickSize pixels at a time.
19067      */
19068     setYConstraint: function(iUp, iDown, iTickSize) {
19069         this.topConstraint = iUp;
19070         this.bottomConstraint = iDown;
19071
19072         this.minY = this.initPageY - iUp;
19073         this.maxY = this.initPageY + iDown;
19074         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19075
19076         this.constrainY = true;
19077
19078     },
19079
19080     /**
19081      * resetConstraints must be called if you manually reposition a dd element.
19082      * @method resetConstraints
19083      * @param {boolean} maintainOffset
19084      */
19085     resetConstraints: function() {
19086
19087
19088         // Maintain offsets if necessary
19089         if (this.initPageX || this.initPageX === 0) {
19090             // figure out how much this thing has moved
19091             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19092             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19093
19094             this.setInitPosition(dx, dy);
19095
19096         // This is the first time we have detected the element's position
19097         } else {
19098             this.setInitPosition();
19099         }
19100
19101         if (this.constrainX) {
19102             this.setXConstraint( this.leftConstraint,
19103                                  this.rightConstraint,
19104                                  this.xTickSize        );
19105         }
19106
19107         if (this.constrainY) {
19108             this.setYConstraint( this.topConstraint,
19109                                  this.bottomConstraint,
19110                                  this.yTickSize         );
19111         }
19112     },
19113
19114     /**
19115      * Normally the drag element is moved pixel by pixel, but we can specify
19116      * that it move a number of pixels at a time.  This method resolves the
19117      * location when we have it set up like this.
19118      * @method getTick
19119      * @param {int} val where we want to place the object
19120      * @param {int[]} tickArray sorted array of valid points
19121      * @return {int} the closest tick
19122      * @private
19123      */
19124     getTick: function(val, tickArray) {
19125
19126         if (!tickArray) {
19127             // If tick interval is not defined, it is effectively 1 pixel,
19128             // so we return the value passed to us.
19129             return val;
19130         } else if (tickArray[0] >= val) {
19131             // The value is lower than the first tick, so we return the first
19132             // tick.
19133             return tickArray[0];
19134         } else {
19135             for (var i=0, len=tickArray.length; i<len; ++i) {
19136                 var next = i + 1;
19137                 if (tickArray[next] && tickArray[next] >= val) {
19138                     var diff1 = val - tickArray[i];
19139                     var diff2 = tickArray[next] - val;
19140                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19141                 }
19142             }
19143
19144             // The value is larger than the last tick, so we return the last
19145             // tick.
19146             return tickArray[tickArray.length - 1];
19147         }
19148     },
19149
19150     /**
19151      * toString method
19152      * @method toString
19153      * @return {string} string representation of the dd obj
19154      */
19155     toString: function() {
19156         return ("DragDrop " + this.id);
19157     }
19158
19159 });
19160
19161 })();
19162 /*
19163  * Based on:
19164  * Ext JS Library 1.1.1
19165  * Copyright(c) 2006-2007, Ext JS, LLC.
19166  *
19167  * Originally Released Under LGPL - original licence link has changed is not relivant.
19168  *
19169  * Fork - LGPL
19170  * <script type="text/javascript">
19171  */
19172
19173
19174 /**
19175  * The drag and drop utility provides a framework for building drag and drop
19176  * applications.  In addition to enabling drag and drop for specific elements,
19177  * the drag and drop elements are tracked by the manager class, and the
19178  * interactions between the various elements are tracked during the drag and
19179  * the implementing code is notified about these important moments.
19180  */
19181
19182 // Only load the library once.  Rewriting the manager class would orphan
19183 // existing drag and drop instances.
19184 if (!Roo.dd.DragDropMgr) {
19185
19186 /**
19187  * @class Roo.dd.DragDropMgr
19188  * DragDropMgr is a singleton that tracks the element interaction for
19189  * all DragDrop items in the window.  Generally, you will not call
19190  * this class directly, but it does have helper methods that could
19191  * be useful in your DragDrop implementations.
19192  * @singleton
19193  */
19194 Roo.dd.DragDropMgr = function() {
19195
19196     var Event = Roo.EventManager;
19197
19198     return {
19199
19200         /**
19201          * Two dimensional Array of registered DragDrop objects.  The first
19202          * dimension is the DragDrop item group, the second the DragDrop
19203          * object.
19204          * @property ids
19205          * @type {string: string}
19206          * @private
19207          * @static
19208          */
19209         ids: {},
19210
19211         /**
19212          * Array of element ids defined as drag handles.  Used to determine
19213          * if the element that generated the mousedown event is actually the
19214          * handle and not the html element itself.
19215          * @property handleIds
19216          * @type {string: string}
19217          * @private
19218          * @static
19219          */
19220         handleIds: {},
19221
19222         /**
19223          * the DragDrop object that is currently being dragged
19224          * @property dragCurrent
19225          * @type DragDrop
19226          * @private
19227          * @static
19228          **/
19229         dragCurrent: null,
19230
19231         /**
19232          * the DragDrop object(s) that are being hovered over
19233          * @property dragOvers
19234          * @type Array
19235          * @private
19236          * @static
19237          */
19238         dragOvers: {},
19239
19240         /**
19241          * the X distance between the cursor and the object being dragged
19242          * @property deltaX
19243          * @type int
19244          * @private
19245          * @static
19246          */
19247         deltaX: 0,
19248
19249         /**
19250          * the Y distance between the cursor and the object being dragged
19251          * @property deltaY
19252          * @type int
19253          * @private
19254          * @static
19255          */
19256         deltaY: 0,
19257
19258         /**
19259          * Flag to determine if we should prevent the default behavior of the
19260          * events we define. By default this is true, but this can be set to
19261          * false if you need the default behavior (not recommended)
19262          * @property preventDefault
19263          * @type boolean
19264          * @static
19265          */
19266         preventDefault: true,
19267
19268         /**
19269          * Flag to determine if we should stop the propagation of the events
19270          * we generate. This is true by default but you may want to set it to
19271          * false if the html element contains other features that require the
19272          * mouse click.
19273          * @property stopPropagation
19274          * @type boolean
19275          * @static
19276          */
19277         stopPropagation: true,
19278
19279         /**
19280          * Internal flag that is set to true when drag and drop has been
19281          * intialized
19282          * @property initialized
19283          * @private
19284          * @static
19285          */
19286         initalized: false,
19287
19288         /**
19289          * All drag and drop can be disabled.
19290          * @property locked
19291          * @private
19292          * @static
19293          */
19294         locked: false,
19295
19296         /**
19297          * Called the first time an element is registered.
19298          * @method init
19299          * @private
19300          * @static
19301          */
19302         init: function() {
19303             this.initialized = true;
19304         },
19305
19306         /**
19307          * In point mode, drag and drop interaction is defined by the
19308          * location of the cursor during the drag/drop
19309          * @property POINT
19310          * @type int
19311          * @static
19312          */
19313         POINT: 0,
19314
19315         /**
19316          * In intersect mode, drag and drop interactio nis defined by the
19317          * overlap of two or more drag and drop objects.
19318          * @property INTERSECT
19319          * @type int
19320          * @static
19321          */
19322         INTERSECT: 1,
19323
19324         /**
19325          * The current drag and drop mode.  Default: POINT
19326          * @property mode
19327          * @type int
19328          * @static
19329          */
19330         mode: 0,
19331
19332         /**
19333          * Runs method on all drag and drop objects
19334          * @method _execOnAll
19335          * @private
19336          * @static
19337          */
19338         _execOnAll: function(sMethod, args) {
19339             for (var i in this.ids) {
19340                 for (var j in this.ids[i]) {
19341                     var oDD = this.ids[i][j];
19342                     if (! this.isTypeOfDD(oDD)) {
19343                         continue;
19344                     }
19345                     oDD[sMethod].apply(oDD, args);
19346                 }
19347             }
19348         },
19349
19350         /**
19351          * Drag and drop initialization.  Sets up the global event handlers
19352          * @method _onLoad
19353          * @private
19354          * @static
19355          */
19356         _onLoad: function() {
19357
19358             this.init();
19359
19360             if (!Roo.isTouch) {
19361                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19362                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19363             }
19364             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19365             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19366             
19367             Event.on(window,   "unload",    this._onUnload, this, true);
19368             Event.on(window,   "resize",    this._onResize, this, true);
19369             // Event.on(window,   "mouseout",    this._test);
19370
19371         },
19372
19373         /**
19374          * Reset constraints on all drag and drop objs
19375          * @method _onResize
19376          * @private
19377          * @static
19378          */
19379         _onResize: function(e) {
19380             this._execOnAll("resetConstraints", []);
19381         },
19382
19383         /**
19384          * Lock all drag and drop functionality
19385          * @method lock
19386          * @static
19387          */
19388         lock: function() { this.locked = true; },
19389
19390         /**
19391          * Unlock all drag and drop functionality
19392          * @method unlock
19393          * @static
19394          */
19395         unlock: function() { this.locked = false; },
19396
19397         /**
19398          * Is drag and drop locked?
19399          * @method isLocked
19400          * @return {boolean} True if drag and drop is locked, false otherwise.
19401          * @static
19402          */
19403         isLocked: function() { return this.locked; },
19404
19405         /**
19406          * Location cache that is set for all drag drop objects when a drag is
19407          * initiated, cleared when the drag is finished.
19408          * @property locationCache
19409          * @private
19410          * @static
19411          */
19412         locationCache: {},
19413
19414         /**
19415          * Set useCache to false if you want to force object the lookup of each
19416          * drag and drop linked element constantly during a drag.
19417          * @property useCache
19418          * @type boolean
19419          * @static
19420          */
19421         useCache: true,
19422
19423         /**
19424          * The number of pixels that the mouse needs to move after the
19425          * mousedown before the drag is initiated.  Default=3;
19426          * @property clickPixelThresh
19427          * @type int
19428          * @static
19429          */
19430         clickPixelThresh: 3,
19431
19432         /**
19433          * The number of milliseconds after the mousedown event to initiate the
19434          * drag if we don't get a mouseup event. Default=1000
19435          * @property clickTimeThresh
19436          * @type int
19437          * @static
19438          */
19439         clickTimeThresh: 350,
19440
19441         /**
19442          * Flag that indicates that either the drag pixel threshold or the
19443          * mousdown time threshold has been met
19444          * @property dragThreshMet
19445          * @type boolean
19446          * @private
19447          * @static
19448          */
19449         dragThreshMet: false,
19450
19451         /**
19452          * Timeout used for the click time threshold
19453          * @property clickTimeout
19454          * @type Object
19455          * @private
19456          * @static
19457          */
19458         clickTimeout: null,
19459
19460         /**
19461          * The X position of the mousedown event stored for later use when a
19462          * drag threshold is met.
19463          * @property startX
19464          * @type int
19465          * @private
19466          * @static
19467          */
19468         startX: 0,
19469
19470         /**
19471          * The Y position of the mousedown event stored for later use when a
19472          * drag threshold is met.
19473          * @property startY
19474          * @type int
19475          * @private
19476          * @static
19477          */
19478         startY: 0,
19479
19480         /**
19481          * Each DragDrop instance must be registered with the DragDropMgr.
19482          * This is executed in DragDrop.init()
19483          * @method regDragDrop
19484          * @param {DragDrop} oDD the DragDrop object to register
19485          * @param {String} sGroup the name of the group this element belongs to
19486          * @static
19487          */
19488         regDragDrop: function(oDD, sGroup) {
19489             if (!this.initialized) { this.init(); }
19490
19491             if (!this.ids[sGroup]) {
19492                 this.ids[sGroup] = {};
19493             }
19494             this.ids[sGroup][oDD.id] = oDD;
19495         },
19496
19497         /**
19498          * Removes the supplied dd instance from the supplied group. Executed
19499          * by DragDrop.removeFromGroup, so don't call this function directly.
19500          * @method removeDDFromGroup
19501          * @private
19502          * @static
19503          */
19504         removeDDFromGroup: function(oDD, sGroup) {
19505             if (!this.ids[sGroup]) {
19506                 this.ids[sGroup] = {};
19507             }
19508
19509             var obj = this.ids[sGroup];
19510             if (obj && obj[oDD.id]) {
19511                 delete obj[oDD.id];
19512             }
19513         },
19514
19515         /**
19516          * Unregisters a drag and drop item.  This is executed in
19517          * DragDrop.unreg, use that method instead of calling this directly.
19518          * @method _remove
19519          * @private
19520          * @static
19521          */
19522         _remove: function(oDD) {
19523             for (var g in oDD.groups) {
19524                 if (g && this.ids[g][oDD.id]) {
19525                     delete this.ids[g][oDD.id];
19526                 }
19527             }
19528             delete this.handleIds[oDD.id];
19529         },
19530
19531         /**
19532          * Each DragDrop handle element must be registered.  This is done
19533          * automatically when executing DragDrop.setHandleElId()
19534          * @method regHandle
19535          * @param {String} sDDId the DragDrop id this element is a handle for
19536          * @param {String} sHandleId the id of the element that is the drag
19537          * handle
19538          * @static
19539          */
19540         regHandle: function(sDDId, sHandleId) {
19541             if (!this.handleIds[sDDId]) {
19542                 this.handleIds[sDDId] = {};
19543             }
19544             this.handleIds[sDDId][sHandleId] = sHandleId;
19545         },
19546
19547         /**
19548          * Utility function to determine if a given element has been
19549          * registered as a drag drop item.
19550          * @method isDragDrop
19551          * @param {String} id the element id to check
19552          * @return {boolean} true if this element is a DragDrop item,
19553          * false otherwise
19554          * @static
19555          */
19556         isDragDrop: function(id) {
19557             return ( this.getDDById(id) ) ? true : false;
19558         },
19559
19560         /**
19561          * Returns the drag and drop instances that are in all groups the
19562          * passed in instance belongs to.
19563          * @method getRelated
19564          * @param {DragDrop} p_oDD the obj to get related data for
19565          * @param {boolean} bTargetsOnly if true, only return targetable objs
19566          * @return {DragDrop[]} the related instances
19567          * @static
19568          */
19569         getRelated: function(p_oDD, bTargetsOnly) {
19570             var oDDs = [];
19571             for (var i in p_oDD.groups) {
19572                 for (j in this.ids[i]) {
19573                     var dd = this.ids[i][j];
19574                     if (! this.isTypeOfDD(dd)) {
19575                         continue;
19576                     }
19577                     if (!bTargetsOnly || dd.isTarget) {
19578                         oDDs[oDDs.length] = dd;
19579                     }
19580                 }
19581             }
19582
19583             return oDDs;
19584         },
19585
19586         /**
19587          * Returns true if the specified dd target is a legal target for
19588          * the specifice drag obj
19589          * @method isLegalTarget
19590          * @param {DragDrop} the drag obj
19591          * @param {DragDrop} the target
19592          * @return {boolean} true if the target is a legal target for the
19593          * dd obj
19594          * @static
19595          */
19596         isLegalTarget: function (oDD, oTargetDD) {
19597             var targets = this.getRelated(oDD, true);
19598             for (var i=0, len=targets.length;i<len;++i) {
19599                 if (targets[i].id == oTargetDD.id) {
19600                     return true;
19601                 }
19602             }
19603
19604             return false;
19605         },
19606
19607         /**
19608          * My goal is to be able to transparently determine if an object is
19609          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19610          * returns "object", oDD.constructor.toString() always returns
19611          * "DragDrop" and not the name of the subclass.  So for now it just
19612          * evaluates a well-known variable in DragDrop.
19613          * @method isTypeOfDD
19614          * @param {Object} the object to evaluate
19615          * @return {boolean} true if typeof oDD = DragDrop
19616          * @static
19617          */
19618         isTypeOfDD: function (oDD) {
19619             return (oDD && oDD.__ygDragDrop);
19620         },
19621
19622         /**
19623          * Utility function to determine if a given element has been
19624          * registered as a drag drop handle for the given Drag Drop object.
19625          * @method isHandle
19626          * @param {String} id the element id to check
19627          * @return {boolean} true if this element is a DragDrop handle, false
19628          * otherwise
19629          * @static
19630          */
19631         isHandle: function(sDDId, sHandleId) {
19632             return ( this.handleIds[sDDId] &&
19633                             this.handleIds[sDDId][sHandleId] );
19634         },
19635
19636         /**
19637          * Returns the DragDrop instance for a given id
19638          * @method getDDById
19639          * @param {String} id the id of the DragDrop object
19640          * @return {DragDrop} the drag drop object, null if it is not found
19641          * @static
19642          */
19643         getDDById: function(id) {
19644             for (var i in this.ids) {
19645                 if (this.ids[i][id]) {
19646                     return this.ids[i][id];
19647                 }
19648             }
19649             return null;
19650         },
19651
19652         /**
19653          * Fired after a registered DragDrop object gets the mousedown event.
19654          * Sets up the events required to track the object being dragged
19655          * @method handleMouseDown
19656          * @param {Event} e the event
19657          * @param oDD the DragDrop object being dragged
19658          * @private
19659          * @static
19660          */
19661         handleMouseDown: function(e, oDD) {
19662             if(Roo.QuickTips){
19663                 Roo.QuickTips.disable();
19664             }
19665             this.currentTarget = e.getTarget();
19666
19667             this.dragCurrent = oDD;
19668
19669             var el = oDD.getEl();
19670
19671             // track start position
19672             this.startX = e.getPageX();
19673             this.startY = e.getPageY();
19674
19675             this.deltaX = this.startX - el.offsetLeft;
19676             this.deltaY = this.startY - el.offsetTop;
19677
19678             this.dragThreshMet = false;
19679
19680             this.clickTimeout = setTimeout(
19681                     function() {
19682                         var DDM = Roo.dd.DDM;
19683                         DDM.startDrag(DDM.startX, DDM.startY);
19684                     },
19685                     this.clickTimeThresh );
19686         },
19687
19688         /**
19689          * Fired when either the drag pixel threshol or the mousedown hold
19690          * time threshold has been met.
19691          * @method startDrag
19692          * @param x {int} the X position of the original mousedown
19693          * @param y {int} the Y position of the original mousedown
19694          * @static
19695          */
19696         startDrag: function(x, y) {
19697             clearTimeout(this.clickTimeout);
19698             if (this.dragCurrent) {
19699                 this.dragCurrent.b4StartDrag(x, y);
19700                 this.dragCurrent.startDrag(x, y);
19701             }
19702             this.dragThreshMet = true;
19703         },
19704
19705         /**
19706          * Internal function to handle the mouseup event.  Will be invoked
19707          * from the context of the document.
19708          * @method handleMouseUp
19709          * @param {Event} e the event
19710          * @private
19711          * @static
19712          */
19713         handleMouseUp: function(e) {
19714
19715             if(Roo.QuickTips){
19716                 Roo.QuickTips.enable();
19717             }
19718             if (! this.dragCurrent) {
19719                 return;
19720             }
19721
19722             clearTimeout(this.clickTimeout);
19723
19724             if (this.dragThreshMet) {
19725                 this.fireEvents(e, true);
19726             } else {
19727             }
19728
19729             this.stopDrag(e);
19730
19731             this.stopEvent(e);
19732         },
19733
19734         /**
19735          * Utility to stop event propagation and event default, if these
19736          * features are turned on.
19737          * @method stopEvent
19738          * @param {Event} e the event as returned by this.getEvent()
19739          * @static
19740          */
19741         stopEvent: function(e){
19742             if(this.stopPropagation) {
19743                 e.stopPropagation();
19744             }
19745
19746             if (this.preventDefault) {
19747                 e.preventDefault();
19748             }
19749         },
19750
19751         /**
19752          * Internal function to clean up event handlers after the drag
19753          * operation is complete
19754          * @method stopDrag
19755          * @param {Event} e the event
19756          * @private
19757          * @static
19758          */
19759         stopDrag: function(e) {
19760             // Fire the drag end event for the item that was dragged
19761             if (this.dragCurrent) {
19762                 if (this.dragThreshMet) {
19763                     this.dragCurrent.b4EndDrag(e);
19764                     this.dragCurrent.endDrag(e);
19765                 }
19766
19767                 this.dragCurrent.onMouseUp(e);
19768             }
19769
19770             this.dragCurrent = null;
19771             this.dragOvers = {};
19772         },
19773
19774         /**
19775          * Internal function to handle the mousemove event.  Will be invoked
19776          * from the context of the html element.
19777          *
19778          * @TODO figure out what we can do about mouse events lost when the
19779          * user drags objects beyond the window boundary.  Currently we can
19780          * detect this in internet explorer by verifying that the mouse is
19781          * down during the mousemove event.  Firefox doesn't give us the
19782          * button state on the mousemove event.
19783          * @method handleMouseMove
19784          * @param {Event} e the event
19785          * @private
19786          * @static
19787          */
19788         handleMouseMove: function(e) {
19789             if (! this.dragCurrent) {
19790                 return true;
19791             }
19792
19793             // var button = e.which || e.button;
19794
19795             // check for IE mouseup outside of page boundary
19796             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19797                 this.stopEvent(e);
19798                 return this.handleMouseUp(e);
19799             }
19800
19801             if (!this.dragThreshMet) {
19802                 var diffX = Math.abs(this.startX - e.getPageX());
19803                 var diffY = Math.abs(this.startY - e.getPageY());
19804                 if (diffX > this.clickPixelThresh ||
19805                             diffY > this.clickPixelThresh) {
19806                     this.startDrag(this.startX, this.startY);
19807                 }
19808             }
19809
19810             if (this.dragThreshMet) {
19811                 this.dragCurrent.b4Drag(e);
19812                 this.dragCurrent.onDrag(e);
19813                 if(!this.dragCurrent.moveOnly){
19814                     this.fireEvents(e, false);
19815                 }
19816             }
19817
19818             this.stopEvent(e);
19819
19820             return true;
19821         },
19822
19823         /**
19824          * Iterates over all of the DragDrop elements to find ones we are
19825          * hovering over or dropping on
19826          * @method fireEvents
19827          * @param {Event} e the event
19828          * @param {boolean} isDrop is this a drop op or a mouseover op?
19829          * @private
19830          * @static
19831          */
19832         fireEvents: function(e, isDrop) {
19833             var dc = this.dragCurrent;
19834
19835             // If the user did the mouse up outside of the window, we could
19836             // get here even though we have ended the drag.
19837             if (!dc || dc.isLocked()) {
19838                 return;
19839             }
19840
19841             var pt = e.getPoint();
19842
19843             // cache the previous dragOver array
19844             var oldOvers = [];
19845
19846             var outEvts   = [];
19847             var overEvts  = [];
19848             var dropEvts  = [];
19849             var enterEvts = [];
19850
19851             // Check to see if the object(s) we were hovering over is no longer
19852             // being hovered over so we can fire the onDragOut event
19853             for (var i in this.dragOvers) {
19854
19855                 var ddo = this.dragOvers[i];
19856
19857                 if (! this.isTypeOfDD(ddo)) {
19858                     continue;
19859                 }
19860
19861                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19862                     outEvts.push( ddo );
19863                 }
19864
19865                 oldOvers[i] = true;
19866                 delete this.dragOvers[i];
19867             }
19868
19869             for (var sGroup in dc.groups) {
19870
19871                 if ("string" != typeof sGroup) {
19872                     continue;
19873                 }
19874
19875                 for (i in this.ids[sGroup]) {
19876                     var oDD = this.ids[sGroup][i];
19877                     if (! this.isTypeOfDD(oDD)) {
19878                         continue;
19879                     }
19880
19881                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19882                         if (this.isOverTarget(pt, oDD, this.mode)) {
19883                             // look for drop interactions
19884                             if (isDrop) {
19885                                 dropEvts.push( oDD );
19886                             // look for drag enter and drag over interactions
19887                             } else {
19888
19889                                 // initial drag over: dragEnter fires
19890                                 if (!oldOvers[oDD.id]) {
19891                                     enterEvts.push( oDD );
19892                                 // subsequent drag overs: dragOver fires
19893                                 } else {
19894                                     overEvts.push( oDD );
19895                                 }
19896
19897                                 this.dragOvers[oDD.id] = oDD;
19898                             }
19899                         }
19900                     }
19901                 }
19902             }
19903
19904             if (this.mode) {
19905                 if (outEvts.length) {
19906                     dc.b4DragOut(e, outEvts);
19907                     dc.onDragOut(e, outEvts);
19908                 }
19909
19910                 if (enterEvts.length) {
19911                     dc.onDragEnter(e, enterEvts);
19912                 }
19913
19914                 if (overEvts.length) {
19915                     dc.b4DragOver(e, overEvts);
19916                     dc.onDragOver(e, overEvts);
19917                 }
19918
19919                 if (dropEvts.length) {
19920                     dc.b4DragDrop(e, dropEvts);
19921                     dc.onDragDrop(e, dropEvts);
19922                 }
19923
19924             } else {
19925                 // fire dragout events
19926                 var len = 0;
19927                 for (i=0, len=outEvts.length; i<len; ++i) {
19928                     dc.b4DragOut(e, outEvts[i].id);
19929                     dc.onDragOut(e, outEvts[i].id);
19930                 }
19931
19932                 // fire enter events
19933                 for (i=0,len=enterEvts.length; i<len; ++i) {
19934                     // dc.b4DragEnter(e, oDD.id);
19935                     dc.onDragEnter(e, enterEvts[i].id);
19936                 }
19937
19938                 // fire over events
19939                 for (i=0,len=overEvts.length; i<len; ++i) {
19940                     dc.b4DragOver(e, overEvts[i].id);
19941                     dc.onDragOver(e, overEvts[i].id);
19942                 }
19943
19944                 // fire drop events
19945                 for (i=0, len=dropEvts.length; i<len; ++i) {
19946                     dc.b4DragDrop(e, dropEvts[i].id);
19947                     dc.onDragDrop(e, dropEvts[i].id);
19948                 }
19949
19950             }
19951
19952             // notify about a drop that did not find a target
19953             if (isDrop && !dropEvts.length) {
19954                 dc.onInvalidDrop(e);
19955             }
19956
19957         },
19958
19959         /**
19960          * Helper function for getting the best match from the list of drag
19961          * and drop objects returned by the drag and drop events when we are
19962          * in INTERSECT mode.  It returns either the first object that the
19963          * cursor is over, or the object that has the greatest overlap with
19964          * the dragged element.
19965          * @method getBestMatch
19966          * @param  {DragDrop[]} dds The array of drag and drop objects
19967          * targeted
19968          * @return {DragDrop}       The best single match
19969          * @static
19970          */
19971         getBestMatch: function(dds) {
19972             var winner = null;
19973             // Return null if the input is not what we expect
19974             //if (!dds || !dds.length || dds.length == 0) {
19975                // winner = null;
19976             // If there is only one item, it wins
19977             //} else if (dds.length == 1) {
19978
19979             var len = dds.length;
19980
19981             if (len == 1) {
19982                 winner = dds[0];
19983             } else {
19984                 // Loop through the targeted items
19985                 for (var i=0; i<len; ++i) {
19986                     var dd = dds[i];
19987                     // If the cursor is over the object, it wins.  If the
19988                     // cursor is over multiple matches, the first one we come
19989                     // to wins.
19990                     if (dd.cursorIsOver) {
19991                         winner = dd;
19992                         break;
19993                     // Otherwise the object with the most overlap wins
19994                     } else {
19995                         if (!winner ||
19996                             winner.overlap.getArea() < dd.overlap.getArea()) {
19997                             winner = dd;
19998                         }
19999                     }
20000                 }
20001             }
20002
20003             return winner;
20004         },
20005
20006         /**
20007          * Refreshes the cache of the top-left and bottom-right points of the
20008          * drag and drop objects in the specified group(s).  This is in the
20009          * format that is stored in the drag and drop instance, so typical
20010          * usage is:
20011          * <code>
20012          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20013          * </code>
20014          * Alternatively:
20015          * <code>
20016          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20017          * </code>
20018          * @TODO this really should be an indexed array.  Alternatively this
20019          * method could accept both.
20020          * @method refreshCache
20021          * @param {Object} groups an associative array of groups to refresh
20022          * @static
20023          */
20024         refreshCache: function(groups) {
20025             for (var sGroup in groups) {
20026                 if ("string" != typeof sGroup) {
20027                     continue;
20028                 }
20029                 for (var i in this.ids[sGroup]) {
20030                     var oDD = this.ids[sGroup][i];
20031
20032                     if (this.isTypeOfDD(oDD)) {
20033                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20034                         var loc = this.getLocation(oDD);
20035                         if (loc) {
20036                             this.locationCache[oDD.id] = loc;
20037                         } else {
20038                             delete this.locationCache[oDD.id];
20039                             // this will unregister the drag and drop object if
20040                             // the element is not in a usable state
20041                             // oDD.unreg();
20042                         }
20043                     }
20044                 }
20045             }
20046         },
20047
20048         /**
20049          * This checks to make sure an element exists and is in the DOM.  The
20050          * main purpose is to handle cases where innerHTML is used to remove
20051          * drag and drop objects from the DOM.  IE provides an 'unspecified
20052          * error' when trying to access the offsetParent of such an element
20053          * @method verifyEl
20054          * @param {HTMLElement} el the element to check
20055          * @return {boolean} true if the element looks usable
20056          * @static
20057          */
20058         verifyEl: function(el) {
20059             if (el) {
20060                 var parent;
20061                 if(Roo.isIE){
20062                     try{
20063                         parent = el.offsetParent;
20064                     }catch(e){}
20065                 }else{
20066                     parent = el.offsetParent;
20067                 }
20068                 if (parent) {
20069                     return true;
20070                 }
20071             }
20072
20073             return false;
20074         },
20075
20076         /**
20077          * Returns a Region object containing the drag and drop element's position
20078          * and size, including the padding configured for it
20079          * @method getLocation
20080          * @param {DragDrop} oDD the drag and drop object to get the
20081          *                       location for
20082          * @return {Roo.lib.Region} a Region object representing the total area
20083          *                             the element occupies, including any padding
20084          *                             the instance is configured for.
20085          * @static
20086          */
20087         getLocation: function(oDD) {
20088             if (! this.isTypeOfDD(oDD)) {
20089                 return null;
20090             }
20091
20092             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20093
20094             try {
20095                 pos= Roo.lib.Dom.getXY(el);
20096             } catch (e) { }
20097
20098             if (!pos) {
20099                 return null;
20100             }
20101
20102             x1 = pos[0];
20103             x2 = x1 + el.offsetWidth;
20104             y1 = pos[1];
20105             y2 = y1 + el.offsetHeight;
20106
20107             t = y1 - oDD.padding[0];
20108             r = x2 + oDD.padding[1];
20109             b = y2 + oDD.padding[2];
20110             l = x1 - oDD.padding[3];
20111
20112             return new Roo.lib.Region( t, r, b, l );
20113         },
20114
20115         /**
20116          * Checks the cursor location to see if it over the target
20117          * @method isOverTarget
20118          * @param {Roo.lib.Point} pt The point to evaluate
20119          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20120          * @return {boolean} true if the mouse is over the target
20121          * @private
20122          * @static
20123          */
20124         isOverTarget: function(pt, oTarget, intersect) {
20125             // use cache if available
20126             var loc = this.locationCache[oTarget.id];
20127             if (!loc || !this.useCache) {
20128                 loc = this.getLocation(oTarget);
20129                 this.locationCache[oTarget.id] = loc;
20130
20131             }
20132
20133             if (!loc) {
20134                 return false;
20135             }
20136
20137             oTarget.cursorIsOver = loc.contains( pt );
20138
20139             // DragDrop is using this as a sanity check for the initial mousedown
20140             // in this case we are done.  In POINT mode, if the drag obj has no
20141             // contraints, we are also done. Otherwise we need to evaluate the
20142             // location of the target as related to the actual location of the
20143             // dragged element.
20144             var dc = this.dragCurrent;
20145             if (!dc || !dc.getTargetCoord ||
20146                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20147                 return oTarget.cursorIsOver;
20148             }
20149
20150             oTarget.overlap = null;
20151
20152             // Get the current location of the drag element, this is the
20153             // location of the mouse event less the delta that represents
20154             // where the original mousedown happened on the element.  We
20155             // need to consider constraints and ticks as well.
20156             var pos = dc.getTargetCoord(pt.x, pt.y);
20157
20158             var el = dc.getDragEl();
20159             var curRegion = new Roo.lib.Region( pos.y,
20160                                                    pos.x + el.offsetWidth,
20161                                                    pos.y + el.offsetHeight,
20162                                                    pos.x );
20163
20164             var overlap = curRegion.intersect(loc);
20165
20166             if (overlap) {
20167                 oTarget.overlap = overlap;
20168                 return (intersect) ? true : oTarget.cursorIsOver;
20169             } else {
20170                 return false;
20171             }
20172         },
20173
20174         /**
20175          * unload event handler
20176          * @method _onUnload
20177          * @private
20178          * @static
20179          */
20180         _onUnload: function(e, me) {
20181             Roo.dd.DragDropMgr.unregAll();
20182         },
20183
20184         /**
20185          * Cleans up the drag and drop events and objects.
20186          * @method unregAll
20187          * @private
20188          * @static
20189          */
20190         unregAll: function() {
20191
20192             if (this.dragCurrent) {
20193                 this.stopDrag();
20194                 this.dragCurrent = null;
20195             }
20196
20197             this._execOnAll("unreg", []);
20198
20199             for (i in this.elementCache) {
20200                 delete this.elementCache[i];
20201             }
20202
20203             this.elementCache = {};
20204             this.ids = {};
20205         },
20206
20207         /**
20208          * A cache of DOM elements
20209          * @property elementCache
20210          * @private
20211          * @static
20212          */
20213         elementCache: {},
20214
20215         /**
20216          * Get the wrapper for the DOM element specified
20217          * @method getElWrapper
20218          * @param {String} id the id of the element to get
20219          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20220          * @private
20221          * @deprecated This wrapper isn't that useful
20222          * @static
20223          */
20224         getElWrapper: function(id) {
20225             var oWrapper = this.elementCache[id];
20226             if (!oWrapper || !oWrapper.el) {
20227                 oWrapper = this.elementCache[id] =
20228                     new this.ElementWrapper(Roo.getDom(id));
20229             }
20230             return oWrapper;
20231         },
20232
20233         /**
20234          * Returns the actual DOM element
20235          * @method getElement
20236          * @param {String} id the id of the elment to get
20237          * @return {Object} The element
20238          * @deprecated use Roo.getDom instead
20239          * @static
20240          */
20241         getElement: function(id) {
20242             return Roo.getDom(id);
20243         },
20244
20245         /**
20246          * Returns the style property for the DOM element (i.e.,
20247          * document.getElById(id).style)
20248          * @method getCss
20249          * @param {String} id the id of the elment to get
20250          * @return {Object} The style property of the element
20251          * @deprecated use Roo.getDom instead
20252          * @static
20253          */
20254         getCss: function(id) {
20255             var el = Roo.getDom(id);
20256             return (el) ? el.style : null;
20257         },
20258
20259         /**
20260          * Inner class for cached elements
20261          * @class DragDropMgr.ElementWrapper
20262          * @for DragDropMgr
20263          * @private
20264          * @deprecated
20265          */
20266         ElementWrapper: function(el) {
20267                 /**
20268                  * The element
20269                  * @property el
20270                  */
20271                 this.el = el || null;
20272                 /**
20273                  * The element id
20274                  * @property id
20275                  */
20276                 this.id = this.el && el.id;
20277                 /**
20278                  * A reference to the style property
20279                  * @property css
20280                  */
20281                 this.css = this.el && el.style;
20282             },
20283
20284         /**
20285          * Returns the X position of an html element
20286          * @method getPosX
20287          * @param el the element for which to get the position
20288          * @return {int} the X coordinate
20289          * @for DragDropMgr
20290          * @deprecated use Roo.lib.Dom.getX instead
20291          * @static
20292          */
20293         getPosX: function(el) {
20294             return Roo.lib.Dom.getX(el);
20295         },
20296
20297         /**
20298          * Returns the Y position of an html element
20299          * @method getPosY
20300          * @param el the element for which to get the position
20301          * @return {int} the Y coordinate
20302          * @deprecated use Roo.lib.Dom.getY instead
20303          * @static
20304          */
20305         getPosY: function(el) {
20306             return Roo.lib.Dom.getY(el);
20307         },
20308
20309         /**
20310          * Swap two nodes.  In IE, we use the native method, for others we
20311          * emulate the IE behavior
20312          * @method swapNode
20313          * @param n1 the first node to swap
20314          * @param n2 the other node to swap
20315          * @static
20316          */
20317         swapNode: function(n1, n2) {
20318             if (n1.swapNode) {
20319                 n1.swapNode(n2);
20320             } else {
20321                 var p = n2.parentNode;
20322                 var s = n2.nextSibling;
20323
20324                 if (s == n1) {
20325                     p.insertBefore(n1, n2);
20326                 } else if (n2 == n1.nextSibling) {
20327                     p.insertBefore(n2, n1);
20328                 } else {
20329                     n1.parentNode.replaceChild(n2, n1);
20330                     p.insertBefore(n1, s);
20331                 }
20332             }
20333         },
20334
20335         /**
20336          * Returns the current scroll position
20337          * @method getScroll
20338          * @private
20339          * @static
20340          */
20341         getScroll: function () {
20342             var t, l, dde=document.documentElement, db=document.body;
20343             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20344                 t = dde.scrollTop;
20345                 l = dde.scrollLeft;
20346             } else if (db) {
20347                 t = db.scrollTop;
20348                 l = db.scrollLeft;
20349             } else {
20350
20351             }
20352             return { top: t, left: l };
20353         },
20354
20355         /**
20356          * Returns the specified element style property
20357          * @method getStyle
20358          * @param {HTMLElement} el          the element
20359          * @param {string}      styleProp   the style property
20360          * @return {string} The value of the style property
20361          * @deprecated use Roo.lib.Dom.getStyle
20362          * @static
20363          */
20364         getStyle: function(el, styleProp) {
20365             return Roo.fly(el).getStyle(styleProp);
20366         },
20367
20368         /**
20369          * Gets the scrollTop
20370          * @method getScrollTop
20371          * @return {int} the document's scrollTop
20372          * @static
20373          */
20374         getScrollTop: function () { return this.getScroll().top; },
20375
20376         /**
20377          * Gets the scrollLeft
20378          * @method getScrollLeft
20379          * @return {int} the document's scrollTop
20380          * @static
20381          */
20382         getScrollLeft: function () { return this.getScroll().left; },
20383
20384         /**
20385          * Sets the x/y position of an element to the location of the
20386          * target element.
20387          * @method moveToEl
20388          * @param {HTMLElement} moveEl      The element to move
20389          * @param {HTMLElement} targetEl    The position reference element
20390          * @static
20391          */
20392         moveToEl: function (moveEl, targetEl) {
20393             var aCoord = Roo.lib.Dom.getXY(targetEl);
20394             Roo.lib.Dom.setXY(moveEl, aCoord);
20395         },
20396
20397         /**
20398          * Numeric array sort function
20399          * @method numericSort
20400          * @static
20401          */
20402         numericSort: function(a, b) { return (a - b); },
20403
20404         /**
20405          * Internal counter
20406          * @property _timeoutCount
20407          * @private
20408          * @static
20409          */
20410         _timeoutCount: 0,
20411
20412         /**
20413          * Trying to make the load order less important.  Without this we get
20414          * an error if this file is loaded before the Event Utility.
20415          * @method _addListeners
20416          * @private
20417          * @static
20418          */
20419         _addListeners: function() {
20420             var DDM = Roo.dd.DDM;
20421             if ( Roo.lib.Event && document ) {
20422                 DDM._onLoad();
20423             } else {
20424                 if (DDM._timeoutCount > 2000) {
20425                 } else {
20426                     setTimeout(DDM._addListeners, 10);
20427                     if (document && document.body) {
20428                         DDM._timeoutCount += 1;
20429                     }
20430                 }
20431             }
20432         },
20433
20434         /**
20435          * Recursively searches the immediate parent and all child nodes for
20436          * the handle element in order to determine wheter or not it was
20437          * clicked.
20438          * @method handleWasClicked
20439          * @param node the html element to inspect
20440          * @static
20441          */
20442         handleWasClicked: function(node, id) {
20443             if (this.isHandle(id, node.id)) {
20444                 return true;
20445             } else {
20446                 // check to see if this is a text node child of the one we want
20447                 var p = node.parentNode;
20448
20449                 while (p) {
20450                     if (this.isHandle(id, p.id)) {
20451                         return true;
20452                     } else {
20453                         p = p.parentNode;
20454                     }
20455                 }
20456             }
20457
20458             return false;
20459         }
20460
20461     };
20462
20463 }();
20464
20465 // shorter alias, save a few bytes
20466 Roo.dd.DDM = Roo.dd.DragDropMgr;
20467 Roo.dd.DDM._addListeners();
20468
20469 }/*
20470  * Based on:
20471  * Ext JS Library 1.1.1
20472  * Copyright(c) 2006-2007, Ext JS, LLC.
20473  *
20474  * Originally Released Under LGPL - original licence link has changed is not relivant.
20475  *
20476  * Fork - LGPL
20477  * <script type="text/javascript">
20478  */
20479
20480 /**
20481  * @class Roo.dd.DD
20482  * A DragDrop implementation where the linked element follows the
20483  * mouse cursor during a drag.
20484  * @extends Roo.dd.DragDrop
20485  * @constructor
20486  * @param {String} id the id of the linked element
20487  * @param {String} sGroup the group of related DragDrop items
20488  * @param {object} config an object containing configurable attributes
20489  *                Valid properties for DD:
20490  *                    scroll
20491  */
20492 Roo.dd.DD = function(id, sGroup, config) {
20493     if (id) {
20494         this.init(id, sGroup, config);
20495     }
20496 };
20497
20498 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20499
20500     /**
20501      * When set to true, the utility automatically tries to scroll the browser
20502      * window wehn a drag and drop element is dragged near the viewport boundary.
20503      * Defaults to true.
20504      * @property scroll
20505      * @type boolean
20506      */
20507     scroll: true,
20508
20509     /**
20510      * Sets the pointer offset to the distance between the linked element's top
20511      * left corner and the location the element was clicked
20512      * @method autoOffset
20513      * @param {int} iPageX the X coordinate of the click
20514      * @param {int} iPageY the Y coordinate of the click
20515      */
20516     autoOffset: function(iPageX, iPageY) {
20517         var x = iPageX - this.startPageX;
20518         var y = iPageY - this.startPageY;
20519         this.setDelta(x, y);
20520     },
20521
20522     /**
20523      * Sets the pointer offset.  You can call this directly to force the
20524      * offset to be in a particular location (e.g., pass in 0,0 to set it
20525      * to the center of the object)
20526      * @method setDelta
20527      * @param {int} iDeltaX the distance from the left
20528      * @param {int} iDeltaY the distance from the top
20529      */
20530     setDelta: function(iDeltaX, iDeltaY) {
20531         this.deltaX = iDeltaX;
20532         this.deltaY = iDeltaY;
20533     },
20534
20535     /**
20536      * Sets the drag element to the location of the mousedown or click event,
20537      * maintaining the cursor location relative to the location on the element
20538      * that was clicked.  Override this if you want to place the element in a
20539      * location other than where the cursor is.
20540      * @method setDragElPos
20541      * @param {int} iPageX the X coordinate of the mousedown or drag event
20542      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20543      */
20544     setDragElPos: function(iPageX, iPageY) {
20545         // the first time we do this, we are going to check to make sure
20546         // the element has css positioning
20547
20548         var el = this.getDragEl();
20549         this.alignElWithMouse(el, iPageX, iPageY);
20550     },
20551
20552     /**
20553      * Sets the element to the location of the mousedown or click event,
20554      * maintaining the cursor location relative to the location on the element
20555      * that was clicked.  Override this if you want to place the element in a
20556      * location other than where the cursor is.
20557      * @method alignElWithMouse
20558      * @param {HTMLElement} el the element to move
20559      * @param {int} iPageX the X coordinate of the mousedown or drag event
20560      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20561      */
20562     alignElWithMouse: function(el, iPageX, iPageY) {
20563         var oCoord = this.getTargetCoord(iPageX, iPageY);
20564         var fly = el.dom ? el : Roo.fly(el);
20565         if (!this.deltaSetXY) {
20566             var aCoord = [oCoord.x, oCoord.y];
20567             fly.setXY(aCoord);
20568             var newLeft = fly.getLeft(true);
20569             var newTop  = fly.getTop(true);
20570             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20571         } else {
20572             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20573         }
20574
20575         this.cachePosition(oCoord.x, oCoord.y);
20576         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20577         return oCoord;
20578     },
20579
20580     /**
20581      * Saves the most recent position so that we can reset the constraints and
20582      * tick marks on-demand.  We need to know this so that we can calculate the
20583      * number of pixels the element is offset from its original position.
20584      * @method cachePosition
20585      * @param iPageX the current x position (optional, this just makes it so we
20586      * don't have to look it up again)
20587      * @param iPageY the current y position (optional, this just makes it so we
20588      * don't have to look it up again)
20589      */
20590     cachePosition: function(iPageX, iPageY) {
20591         if (iPageX) {
20592             this.lastPageX = iPageX;
20593             this.lastPageY = iPageY;
20594         } else {
20595             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20596             this.lastPageX = aCoord[0];
20597             this.lastPageY = aCoord[1];
20598         }
20599     },
20600
20601     /**
20602      * Auto-scroll the window if the dragged object has been moved beyond the
20603      * visible window boundary.
20604      * @method autoScroll
20605      * @param {int} x the drag element's x position
20606      * @param {int} y the drag element's y position
20607      * @param {int} h the height of the drag element
20608      * @param {int} w the width of the drag element
20609      * @private
20610      */
20611     autoScroll: function(x, y, h, w) {
20612
20613         if (this.scroll) {
20614             // The client height
20615             var clientH = Roo.lib.Dom.getViewWidth();
20616
20617             // The client width
20618             var clientW = Roo.lib.Dom.getViewHeight();
20619
20620             // The amt scrolled down
20621             var st = this.DDM.getScrollTop();
20622
20623             // The amt scrolled right
20624             var sl = this.DDM.getScrollLeft();
20625
20626             // Location of the bottom of the element
20627             var bot = h + y;
20628
20629             // Location of the right of the element
20630             var right = w + x;
20631
20632             // The distance from the cursor to the bottom of the visible area,
20633             // adjusted so that we don't scroll if the cursor is beyond the
20634             // element drag constraints
20635             var toBot = (clientH + st - y - this.deltaY);
20636
20637             // The distance from the cursor to the right of the visible area
20638             var toRight = (clientW + sl - x - this.deltaX);
20639
20640
20641             // How close to the edge the cursor must be before we scroll
20642             // var thresh = (document.all) ? 100 : 40;
20643             var thresh = 40;
20644
20645             // How many pixels to scroll per autoscroll op.  This helps to reduce
20646             // clunky scrolling. IE is more sensitive about this ... it needs this
20647             // value to be higher.
20648             var scrAmt = (document.all) ? 80 : 30;
20649
20650             // Scroll down if we are near the bottom of the visible page and the
20651             // obj extends below the crease
20652             if ( bot > clientH && toBot < thresh ) {
20653                 window.scrollTo(sl, st + scrAmt);
20654             }
20655
20656             // Scroll up if the window is scrolled down and the top of the object
20657             // goes above the top border
20658             if ( y < st && st > 0 && y - st < thresh ) {
20659                 window.scrollTo(sl, st - scrAmt);
20660             }
20661
20662             // Scroll right if the obj is beyond the right border and the cursor is
20663             // near the border.
20664             if ( right > clientW && toRight < thresh ) {
20665                 window.scrollTo(sl + scrAmt, st);
20666             }
20667
20668             // Scroll left if the window has been scrolled to the right and the obj
20669             // extends past the left border
20670             if ( x < sl && sl > 0 && x - sl < thresh ) {
20671                 window.scrollTo(sl - scrAmt, st);
20672             }
20673         }
20674     },
20675
20676     /**
20677      * Finds the location the element should be placed if we want to move
20678      * it to where the mouse location less the click offset would place us.
20679      * @method getTargetCoord
20680      * @param {int} iPageX the X coordinate of the click
20681      * @param {int} iPageY the Y coordinate of the click
20682      * @return an object that contains the coordinates (Object.x and Object.y)
20683      * @private
20684      */
20685     getTargetCoord: function(iPageX, iPageY) {
20686
20687
20688         var x = iPageX - this.deltaX;
20689         var y = iPageY - this.deltaY;
20690
20691         if (this.constrainX) {
20692             if (x < this.minX) { x = this.minX; }
20693             if (x > this.maxX) { x = this.maxX; }
20694         }
20695
20696         if (this.constrainY) {
20697             if (y < this.minY) { y = this.minY; }
20698             if (y > this.maxY) { y = this.maxY; }
20699         }
20700
20701         x = this.getTick(x, this.xTicks);
20702         y = this.getTick(y, this.yTicks);
20703
20704
20705         return {x:x, y:y};
20706     },
20707
20708     /*
20709      * Sets up config options specific to this class. Overrides
20710      * Roo.dd.DragDrop, but all versions of this method through the
20711      * inheritance chain are called
20712      */
20713     applyConfig: function() {
20714         Roo.dd.DD.superclass.applyConfig.call(this);
20715         this.scroll = (this.config.scroll !== false);
20716     },
20717
20718     /*
20719      * Event that fires prior to the onMouseDown event.  Overrides
20720      * Roo.dd.DragDrop.
20721      */
20722     b4MouseDown: function(e) {
20723         // this.resetConstraints();
20724         this.autoOffset(e.getPageX(),
20725                             e.getPageY());
20726     },
20727
20728     /*
20729      * Event that fires prior to the onDrag event.  Overrides
20730      * Roo.dd.DragDrop.
20731      */
20732     b4Drag: function(e) {
20733         this.setDragElPos(e.getPageX(),
20734                             e.getPageY());
20735     },
20736
20737     toString: function() {
20738         return ("DD " + this.id);
20739     }
20740
20741     //////////////////////////////////////////////////////////////////////////
20742     // Debugging ygDragDrop events that can be overridden
20743     //////////////////////////////////////////////////////////////////////////
20744     /*
20745     startDrag: function(x, y) {
20746     },
20747
20748     onDrag: function(e) {
20749     },
20750
20751     onDragEnter: function(e, id) {
20752     },
20753
20754     onDragOver: function(e, id) {
20755     },
20756
20757     onDragOut: function(e, id) {
20758     },
20759
20760     onDragDrop: function(e, id) {
20761     },
20762
20763     endDrag: function(e) {
20764     }
20765
20766     */
20767
20768 });/*
20769  * Based on:
20770  * Ext JS Library 1.1.1
20771  * Copyright(c) 2006-2007, Ext JS, LLC.
20772  *
20773  * Originally Released Under LGPL - original licence link has changed is not relivant.
20774  *
20775  * Fork - LGPL
20776  * <script type="text/javascript">
20777  */
20778
20779 /**
20780  * @class Roo.dd.DDProxy
20781  * A DragDrop implementation that inserts an empty, bordered div into
20782  * the document that follows the cursor during drag operations.  At the time of
20783  * the click, the frame div is resized to the dimensions of the linked html
20784  * element, and moved to the exact location of the linked element.
20785  *
20786  * References to the "frame" element refer to the single proxy element that
20787  * was created to be dragged in place of all DDProxy elements on the
20788  * page.
20789  *
20790  * @extends Roo.dd.DD
20791  * @constructor
20792  * @param {String} id the id of the linked html element
20793  * @param {String} sGroup the group of related DragDrop objects
20794  * @param {object} config an object containing configurable attributes
20795  *                Valid properties for DDProxy in addition to those in DragDrop:
20796  *                   resizeFrame, centerFrame, dragElId
20797  */
20798 Roo.dd.DDProxy = function(id, sGroup, config) {
20799     if (id) {
20800         this.init(id, sGroup, config);
20801         this.initFrame();
20802     }
20803 };
20804
20805 /**
20806  * The default drag frame div id
20807  * @property Roo.dd.DDProxy.dragElId
20808  * @type String
20809  * @static
20810  */
20811 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20812
20813 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20814
20815     /**
20816      * By default we resize the drag frame to be the same size as the element
20817      * we want to drag (this is to get the frame effect).  We can turn it off
20818      * if we want a different behavior.
20819      * @property resizeFrame
20820      * @type boolean
20821      */
20822     resizeFrame: true,
20823
20824     /**
20825      * By default the frame is positioned exactly where the drag element is, so
20826      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20827      * you do not have constraints on the obj is to have the drag frame centered
20828      * around the cursor.  Set centerFrame to true for this effect.
20829      * @property centerFrame
20830      * @type boolean
20831      */
20832     centerFrame: false,
20833
20834     /**
20835      * Creates the proxy element if it does not yet exist
20836      * @method createFrame
20837      */
20838     createFrame: function() {
20839         var self = this;
20840         var body = document.body;
20841
20842         if (!body || !body.firstChild) {
20843             setTimeout( function() { self.createFrame(); }, 50 );
20844             return;
20845         }
20846
20847         var div = this.getDragEl();
20848
20849         if (!div) {
20850             div    = document.createElement("div");
20851             div.id = this.dragElId;
20852             var s  = div.style;
20853
20854             s.position   = "absolute";
20855             s.visibility = "hidden";
20856             s.cursor     = "move";
20857             s.border     = "2px solid #aaa";
20858             s.zIndex     = 999;
20859
20860             // appendChild can blow up IE if invoked prior to the window load event
20861             // while rendering a table.  It is possible there are other scenarios
20862             // that would cause this to happen as well.
20863             body.insertBefore(div, body.firstChild);
20864         }
20865     },
20866
20867     /**
20868      * Initialization for the drag frame element.  Must be called in the
20869      * constructor of all subclasses
20870      * @method initFrame
20871      */
20872     initFrame: function() {
20873         this.createFrame();
20874     },
20875
20876     applyConfig: function() {
20877         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20878
20879         this.resizeFrame = (this.config.resizeFrame !== false);
20880         this.centerFrame = (this.config.centerFrame);
20881         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20882     },
20883
20884     /**
20885      * Resizes the drag frame to the dimensions of the clicked object, positions
20886      * it over the object, and finally displays it
20887      * @method showFrame
20888      * @param {int} iPageX X click position
20889      * @param {int} iPageY Y click position
20890      * @private
20891      */
20892     showFrame: function(iPageX, iPageY) {
20893         var el = this.getEl();
20894         var dragEl = this.getDragEl();
20895         var s = dragEl.style;
20896
20897         this._resizeProxy();
20898
20899         if (this.centerFrame) {
20900             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20901                            Math.round(parseInt(s.height, 10)/2) );
20902         }
20903
20904         this.setDragElPos(iPageX, iPageY);
20905
20906         Roo.fly(dragEl).show();
20907     },
20908
20909     /**
20910      * The proxy is automatically resized to the dimensions of the linked
20911      * element when a drag is initiated, unless resizeFrame is set to false
20912      * @method _resizeProxy
20913      * @private
20914      */
20915     _resizeProxy: function() {
20916         if (this.resizeFrame) {
20917             var el = this.getEl();
20918             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20919         }
20920     },
20921
20922     // overrides Roo.dd.DragDrop
20923     b4MouseDown: function(e) {
20924         var x = e.getPageX();
20925         var y = e.getPageY();
20926         this.autoOffset(x, y);
20927         this.setDragElPos(x, y);
20928     },
20929
20930     // overrides Roo.dd.DragDrop
20931     b4StartDrag: function(x, y) {
20932         // show the drag frame
20933         this.showFrame(x, y);
20934     },
20935
20936     // overrides Roo.dd.DragDrop
20937     b4EndDrag: function(e) {
20938         Roo.fly(this.getDragEl()).hide();
20939     },
20940
20941     // overrides Roo.dd.DragDrop
20942     // By default we try to move the element to the last location of the frame.
20943     // This is so that the default behavior mirrors that of Roo.dd.DD.
20944     endDrag: function(e) {
20945
20946         var lel = this.getEl();
20947         var del = this.getDragEl();
20948
20949         // Show the drag frame briefly so we can get its position
20950         del.style.visibility = "";
20951
20952         this.beforeMove();
20953         // Hide the linked element before the move to get around a Safari
20954         // rendering bug.
20955         lel.style.visibility = "hidden";
20956         Roo.dd.DDM.moveToEl(lel, del);
20957         del.style.visibility = "hidden";
20958         lel.style.visibility = "";
20959
20960         this.afterDrag();
20961     },
20962
20963     beforeMove : function(){
20964
20965     },
20966
20967     afterDrag : function(){
20968
20969     },
20970
20971     toString: function() {
20972         return ("DDProxy " + this.id);
20973     }
20974
20975 });
20976 /*
20977  * Based on:
20978  * Ext JS Library 1.1.1
20979  * Copyright(c) 2006-2007, Ext JS, LLC.
20980  *
20981  * Originally Released Under LGPL - original licence link has changed is not relivant.
20982  *
20983  * Fork - LGPL
20984  * <script type="text/javascript">
20985  */
20986
20987  /**
20988  * @class Roo.dd.DDTarget
20989  * A DragDrop implementation that does not move, but can be a drop
20990  * target.  You would get the same result by simply omitting implementation
20991  * for the event callbacks, but this way we reduce the processing cost of the
20992  * event listener and the callbacks.
20993  * @extends Roo.dd.DragDrop
20994  * @constructor
20995  * @param {String} id the id of the element that is a drop target
20996  * @param {String} sGroup the group of related DragDrop objects
20997  * @param {object} config an object containing configurable attributes
20998  *                 Valid properties for DDTarget in addition to those in
20999  *                 DragDrop:
21000  *                    none
21001  */
21002 Roo.dd.DDTarget = function(id, sGroup, config) {
21003     if (id) {
21004         this.initTarget(id, sGroup, config);
21005     }
21006     if (config.listeners || config.events) { 
21007        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
21008             listeners : config.listeners || {}, 
21009             events : config.events || {} 
21010         });    
21011     }
21012 };
21013
21014 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21015 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21016     toString: function() {
21017         return ("DDTarget " + this.id);
21018     }
21019 });
21020 /*
21021  * Based on:
21022  * Ext JS Library 1.1.1
21023  * Copyright(c) 2006-2007, Ext JS, LLC.
21024  *
21025  * Originally Released Under LGPL - original licence link has changed is not relivant.
21026  *
21027  * Fork - LGPL
21028  * <script type="text/javascript">
21029  */
21030  
21031
21032 /**
21033  * @class Roo.dd.ScrollManager
21034  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21035  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21036  * @singleton
21037  */
21038 Roo.dd.ScrollManager = function(){
21039     var ddm = Roo.dd.DragDropMgr;
21040     var els = {};
21041     var dragEl = null;
21042     var proc = {};
21043     
21044     
21045     
21046     var onStop = function(e){
21047         dragEl = null;
21048         clearProc();
21049     };
21050     
21051     var triggerRefresh = function(){
21052         if(ddm.dragCurrent){
21053              ddm.refreshCache(ddm.dragCurrent.groups);
21054         }
21055     };
21056     
21057     var doScroll = function(){
21058         if(ddm.dragCurrent){
21059             var dds = Roo.dd.ScrollManager;
21060             if(!dds.animate){
21061                 if(proc.el.scroll(proc.dir, dds.increment)){
21062                     triggerRefresh();
21063                 }
21064             }else{
21065                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21066             }
21067         }
21068     };
21069     
21070     var clearProc = function(){
21071         if(proc.id){
21072             clearInterval(proc.id);
21073         }
21074         proc.id = 0;
21075         proc.el = null;
21076         proc.dir = "";
21077     };
21078     
21079     var startProc = function(el, dir){
21080          Roo.log('scroll startproc');
21081         clearProc();
21082         proc.el = el;
21083         proc.dir = dir;
21084         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21085     };
21086     
21087     var onFire = function(e, isDrop){
21088        
21089         if(isDrop || !ddm.dragCurrent){ return; }
21090         var dds = Roo.dd.ScrollManager;
21091         if(!dragEl || dragEl != ddm.dragCurrent){
21092             dragEl = ddm.dragCurrent;
21093             // refresh regions on drag start
21094             dds.refreshCache();
21095         }
21096         
21097         var xy = Roo.lib.Event.getXY(e);
21098         var pt = new Roo.lib.Point(xy[0], xy[1]);
21099         for(var id in els){
21100             var el = els[id], r = el._region;
21101             if(r && r.contains(pt) && el.isScrollable()){
21102                 if(r.bottom - pt.y <= dds.thresh){
21103                     if(proc.el != el){
21104                         startProc(el, "down");
21105                     }
21106                     return;
21107                 }else if(r.right - pt.x <= dds.thresh){
21108                     if(proc.el != el){
21109                         startProc(el, "left");
21110                     }
21111                     return;
21112                 }else if(pt.y - r.top <= dds.thresh){
21113                     if(proc.el != el){
21114                         startProc(el, "up");
21115                     }
21116                     return;
21117                 }else if(pt.x - r.left <= dds.thresh){
21118                     if(proc.el != el){
21119                         startProc(el, "right");
21120                     }
21121                     return;
21122                 }
21123             }
21124         }
21125         clearProc();
21126     };
21127     
21128     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21129     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21130     
21131     return {
21132         /**
21133          * Registers new overflow element(s) to auto scroll
21134          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21135          */
21136         register : function(el){
21137             if(el instanceof Array){
21138                 for(var i = 0, len = el.length; i < len; i++) {
21139                         this.register(el[i]);
21140                 }
21141             }else{
21142                 el = Roo.get(el);
21143                 els[el.id] = el;
21144             }
21145             Roo.dd.ScrollManager.els = els;
21146         },
21147         
21148         /**
21149          * Unregisters overflow element(s) so they are no longer scrolled
21150          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21151          */
21152         unregister : function(el){
21153             if(el instanceof Array){
21154                 for(var i = 0, len = el.length; i < len; i++) {
21155                         this.unregister(el[i]);
21156                 }
21157             }else{
21158                 el = Roo.get(el);
21159                 delete els[el.id];
21160             }
21161         },
21162         
21163         /**
21164          * The number of pixels from the edge of a container the pointer needs to be to 
21165          * trigger scrolling (defaults to 25)
21166          * @type Number
21167          */
21168         thresh : 25,
21169         
21170         /**
21171          * The number of pixels to scroll in each scroll increment (defaults to 50)
21172          * @type Number
21173          */
21174         increment : 100,
21175         
21176         /**
21177          * The frequency of scrolls in milliseconds (defaults to 500)
21178          * @type Number
21179          */
21180         frequency : 500,
21181         
21182         /**
21183          * True to animate the scroll (defaults to true)
21184          * @type Boolean
21185          */
21186         animate: true,
21187         
21188         /**
21189          * The animation duration in seconds - 
21190          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21191          * @type Number
21192          */
21193         animDuration: .4,
21194         
21195         /**
21196          * Manually trigger a cache refresh.
21197          */
21198         refreshCache : function(){
21199             for(var id in els){
21200                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21201                     els[id]._region = els[id].getRegion();
21202                 }
21203             }
21204         }
21205     };
21206 }();/*
21207  * Based on:
21208  * Ext JS Library 1.1.1
21209  * Copyright(c) 2006-2007, Ext JS, LLC.
21210  *
21211  * Originally Released Under LGPL - original licence link has changed is not relivant.
21212  *
21213  * Fork - LGPL
21214  * <script type="text/javascript">
21215  */
21216  
21217
21218 /**
21219  * @class Roo.dd.Registry
21220  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21221  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21222  * @singleton
21223  */
21224 Roo.dd.Registry = function(){
21225     var elements = {}; 
21226     var handles = {}; 
21227     var autoIdSeed = 0;
21228
21229     var getId = function(el, autogen){
21230         if(typeof el == "string"){
21231             return el;
21232         }
21233         var id = el.id;
21234         if(!id && autogen !== false){
21235             id = "roodd-" + (++autoIdSeed);
21236             el.id = id;
21237         }
21238         return id;
21239     };
21240     
21241     return {
21242     /**
21243      * Register a drag drop element
21244      * @param {String|HTMLElement} element The id or DOM node to register
21245      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21246      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21247      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21248      * populated in the data object (if applicable):
21249      * <pre>
21250 Value      Description<br />
21251 ---------  ------------------------------------------<br />
21252 handles    Array of DOM nodes that trigger dragging<br />
21253            for the element being registered<br />
21254 isHandle   True if the element passed in triggers<br />
21255            dragging itself, else false
21256 </pre>
21257      */
21258         register : function(el, data){
21259             data = data || {};
21260             if(typeof el == "string"){
21261                 el = document.getElementById(el);
21262             }
21263             data.ddel = el;
21264             elements[getId(el)] = data;
21265             if(data.isHandle !== false){
21266                 handles[data.ddel.id] = data;
21267             }
21268             if(data.handles){
21269                 var hs = data.handles;
21270                 for(var i = 0, len = hs.length; i < len; i++){
21271                         handles[getId(hs[i])] = data;
21272                 }
21273             }
21274         },
21275
21276     /**
21277      * Unregister a drag drop element
21278      * @param {String|HTMLElement}  element The id or DOM node to unregister
21279      */
21280         unregister : function(el){
21281             var id = getId(el, false);
21282             var data = elements[id];
21283             if(data){
21284                 delete elements[id];
21285                 if(data.handles){
21286                     var hs = data.handles;
21287                     for(var i = 0, len = hs.length; i < len; i++){
21288                         delete handles[getId(hs[i], false)];
21289                     }
21290                 }
21291             }
21292         },
21293
21294     /**
21295      * Returns the handle registered for a DOM Node by id
21296      * @param {String|HTMLElement} id The DOM node or id to look up
21297      * @return {Object} handle The custom handle data
21298      */
21299         getHandle : function(id){
21300             if(typeof id != "string"){ // must be element?
21301                 id = id.id;
21302             }
21303             return handles[id];
21304         },
21305
21306     /**
21307      * Returns the handle that is registered for the DOM node that is the target of the event
21308      * @param {Event} e The event
21309      * @return {Object} handle The custom handle data
21310      */
21311         getHandleFromEvent : function(e){
21312             var t = Roo.lib.Event.getTarget(e);
21313             return t ? handles[t.id] : null;
21314         },
21315
21316     /**
21317      * Returns a custom data object that is registered for a DOM node by id
21318      * @param {String|HTMLElement} id The DOM node or id to look up
21319      * @return {Object} data The custom data
21320      */
21321         getTarget : function(id){
21322             if(typeof id != "string"){ // must be element?
21323                 id = id.id;
21324             }
21325             return elements[id];
21326         },
21327
21328     /**
21329      * Returns a custom data object that is registered for the DOM node that is the target of the event
21330      * @param {Event} e The event
21331      * @return {Object} data The custom data
21332      */
21333         getTargetFromEvent : function(e){
21334             var t = Roo.lib.Event.getTarget(e);
21335             return t ? elements[t.id] || handles[t.id] : null;
21336         }
21337     };
21338 }();/*
21339  * Based on:
21340  * Ext JS Library 1.1.1
21341  * Copyright(c) 2006-2007, Ext JS, LLC.
21342  *
21343  * Originally Released Under LGPL - original licence link has changed is not relivant.
21344  *
21345  * Fork - LGPL
21346  * <script type="text/javascript">
21347  */
21348  
21349
21350 /**
21351  * @class Roo.dd.StatusProxy
21352  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21353  * default drag proxy used by all Roo.dd components.
21354  * @constructor
21355  * @param {Object} config
21356  */
21357 Roo.dd.StatusProxy = function(config){
21358     Roo.apply(this, config);
21359     this.id = this.id || Roo.id();
21360     this.el = new Roo.Layer({
21361         dh: {
21362             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21363                 {tag: "div", cls: "x-dd-drop-icon"},
21364                 {tag: "div", cls: "x-dd-drag-ghost"}
21365             ]
21366         }, 
21367         shadow: !config || config.shadow !== false
21368     });
21369     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21370     this.dropStatus = this.dropNotAllowed;
21371 };
21372
21373 Roo.dd.StatusProxy.prototype = {
21374     /**
21375      * @cfg {String} dropAllowed
21376      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21377      */
21378     dropAllowed : "x-dd-drop-ok",
21379     /**
21380      * @cfg {String} dropNotAllowed
21381      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21382      */
21383     dropNotAllowed : "x-dd-drop-nodrop",
21384
21385     /**
21386      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21387      * over the current target element.
21388      * @param {String} cssClass The css class for the new drop status indicator image
21389      */
21390     setStatus : function(cssClass){
21391         cssClass = cssClass || this.dropNotAllowed;
21392         if(this.dropStatus != cssClass){
21393             this.el.replaceClass(this.dropStatus, cssClass);
21394             this.dropStatus = cssClass;
21395         }
21396     },
21397
21398     /**
21399      * Resets the status indicator to the default dropNotAllowed value
21400      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21401      */
21402     reset : function(clearGhost){
21403         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21404         this.dropStatus = this.dropNotAllowed;
21405         if(clearGhost){
21406             this.ghost.update("");
21407         }
21408     },
21409
21410     /**
21411      * Updates the contents of the ghost element
21412      * @param {String} html The html that will replace the current innerHTML of the ghost element
21413      */
21414     update : function(html){
21415         if(typeof html == "string"){
21416             this.ghost.update(html);
21417         }else{
21418             this.ghost.update("");
21419             html.style.margin = "0";
21420             this.ghost.dom.appendChild(html);
21421         }
21422         // ensure float = none set?? cant remember why though.
21423         var el = this.ghost.dom.firstChild;
21424                 if(el){
21425                         Roo.fly(el).setStyle('float', 'none');
21426                 }
21427     },
21428     
21429     /**
21430      * Returns the underlying proxy {@link Roo.Layer}
21431      * @return {Roo.Layer} el
21432     */
21433     getEl : function(){
21434         return this.el;
21435     },
21436
21437     /**
21438      * Returns the ghost element
21439      * @return {Roo.Element} el
21440      */
21441     getGhost : function(){
21442         return this.ghost;
21443     },
21444
21445     /**
21446      * Hides the proxy
21447      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21448      */
21449     hide : function(clear){
21450         this.el.hide();
21451         if(clear){
21452             this.reset(true);
21453         }
21454     },
21455
21456     /**
21457      * Stops the repair animation if it's currently running
21458      */
21459     stop : function(){
21460         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21461             this.anim.stop();
21462         }
21463     },
21464
21465     /**
21466      * Displays this proxy
21467      */
21468     show : function(){
21469         this.el.show();
21470     },
21471
21472     /**
21473      * Force the Layer to sync its shadow and shim positions to the element
21474      */
21475     sync : function(){
21476         this.el.sync();
21477     },
21478
21479     /**
21480      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21481      * invalid drop operation by the item being dragged.
21482      * @param {Array} xy The XY position of the element ([x, y])
21483      * @param {Function} callback The function to call after the repair is complete
21484      * @param {Object} scope The scope in which to execute the callback
21485      */
21486     repair : function(xy, callback, scope){
21487         this.callback = callback;
21488         this.scope = scope;
21489         if(xy && this.animRepair !== false){
21490             this.el.addClass("x-dd-drag-repair");
21491             this.el.hideUnders(true);
21492             this.anim = this.el.shift({
21493                 duration: this.repairDuration || .5,
21494                 easing: 'easeOut',
21495                 xy: xy,
21496                 stopFx: true,
21497                 callback: this.afterRepair,
21498                 scope: this
21499             });
21500         }else{
21501             this.afterRepair();
21502         }
21503     },
21504
21505     // private
21506     afterRepair : function(){
21507         this.hide(true);
21508         if(typeof this.callback == "function"){
21509             this.callback.call(this.scope || this);
21510         }
21511         this.callback = null;
21512         this.scope = null;
21513     }
21514 };/*
21515  * Based on:
21516  * Ext JS Library 1.1.1
21517  * Copyright(c) 2006-2007, Ext JS, LLC.
21518  *
21519  * Originally Released Under LGPL - original licence link has changed is not relivant.
21520  *
21521  * Fork - LGPL
21522  * <script type="text/javascript">
21523  */
21524
21525 /**
21526  * @class Roo.dd.DragSource
21527  * @extends Roo.dd.DDProxy
21528  * A simple class that provides the basic implementation needed to make any element draggable.
21529  * @constructor
21530  * @param {String/HTMLElement/Element} el The container element
21531  * @param {Object} config
21532  */
21533 Roo.dd.DragSource = function(el, config){
21534     this.el = Roo.get(el);
21535     this.dragData = {};
21536     
21537     Roo.apply(this, config);
21538     
21539     if(!this.proxy){
21540         this.proxy = new Roo.dd.StatusProxy();
21541     }
21542
21543     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21544           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21545     
21546     this.dragging = false;
21547 };
21548
21549 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21550     /**
21551      * @cfg {String} dropAllowed
21552      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21553      */
21554     dropAllowed : "x-dd-drop-ok",
21555     /**
21556      * @cfg {String} dropNotAllowed
21557      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21558      */
21559     dropNotAllowed : "x-dd-drop-nodrop",
21560
21561     /**
21562      * Returns the data object associated with this drag source
21563      * @return {Object} data An object containing arbitrary data
21564      */
21565     getDragData : function(e){
21566         return this.dragData;
21567     },
21568
21569     // private
21570     onDragEnter : function(e, id){
21571         var target = Roo.dd.DragDropMgr.getDDById(id);
21572         this.cachedTarget = target;
21573         if(this.beforeDragEnter(target, e, id) !== false){
21574             if(target.isNotifyTarget){
21575                 var status = target.notifyEnter(this, e, this.dragData);
21576                 this.proxy.setStatus(status);
21577             }else{
21578                 this.proxy.setStatus(this.dropAllowed);
21579             }
21580             
21581             if(this.afterDragEnter){
21582                 /**
21583                  * An empty function by default, but provided so that you can perform a custom action
21584                  * when the dragged item enters the drop target by providing an implementation.
21585                  * @param {Roo.dd.DragDrop} target The drop target
21586                  * @param {Event} e The event object
21587                  * @param {String} id The id of the dragged element
21588                  * @method afterDragEnter
21589                  */
21590                 this.afterDragEnter(target, e, id);
21591             }
21592         }
21593     },
21594
21595     /**
21596      * An empty function by default, but provided so that you can perform a custom action
21597      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21598      * @param {Roo.dd.DragDrop} target The drop target
21599      * @param {Event} e The event object
21600      * @param {String} id The id of the dragged element
21601      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21602      */
21603     beforeDragEnter : function(target, e, id){
21604         return true;
21605     },
21606
21607     // private
21608     alignElWithMouse: function() {
21609         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21610         this.proxy.sync();
21611     },
21612
21613     // private
21614     onDragOver : function(e, id){
21615         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21616         if(this.beforeDragOver(target, e, id) !== false){
21617             if(target.isNotifyTarget){
21618                 var status = target.notifyOver(this, e, this.dragData);
21619                 this.proxy.setStatus(status);
21620             }
21621
21622             if(this.afterDragOver){
21623                 /**
21624                  * An empty function by default, but provided so that you can perform a custom action
21625                  * while the dragged item is over the drop target by providing an implementation.
21626                  * @param {Roo.dd.DragDrop} target The drop target
21627                  * @param {Event} e The event object
21628                  * @param {String} id The id of the dragged element
21629                  * @method afterDragOver
21630                  */
21631                 this.afterDragOver(target, e, id);
21632             }
21633         }
21634     },
21635
21636     /**
21637      * An empty function by default, but provided so that you can perform a custom action
21638      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21639      * @param {Roo.dd.DragDrop} target The drop target
21640      * @param {Event} e The event object
21641      * @param {String} id The id of the dragged element
21642      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21643      */
21644     beforeDragOver : function(target, e, id){
21645         return true;
21646     },
21647
21648     // private
21649     onDragOut : function(e, id){
21650         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21651         if(this.beforeDragOut(target, e, id) !== false){
21652             if(target.isNotifyTarget){
21653                 target.notifyOut(this, e, this.dragData);
21654             }
21655             this.proxy.reset();
21656             if(this.afterDragOut){
21657                 /**
21658                  * An empty function by default, but provided so that you can perform a custom action
21659                  * after the dragged item is dragged out of the target without dropping.
21660                  * @param {Roo.dd.DragDrop} target The drop target
21661                  * @param {Event} e The event object
21662                  * @param {String} id The id of the dragged element
21663                  * @method afterDragOut
21664                  */
21665                 this.afterDragOut(target, e, id);
21666             }
21667         }
21668         this.cachedTarget = null;
21669     },
21670
21671     /**
21672      * An empty function by default, but provided so that you can perform a custom action before the dragged
21673      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21674      * @param {Roo.dd.DragDrop} target The drop target
21675      * @param {Event} e The event object
21676      * @param {String} id The id of the dragged element
21677      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21678      */
21679     beforeDragOut : function(target, e, id){
21680         return true;
21681     },
21682     
21683     // private
21684     onDragDrop : function(e, id){
21685         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21686         if(this.beforeDragDrop(target, e, id) !== false){
21687             if(target.isNotifyTarget){
21688                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21689                     this.onValidDrop(target, e, id);
21690                 }else{
21691                     this.onInvalidDrop(target, e, id);
21692                 }
21693             }else{
21694                 this.onValidDrop(target, e, id);
21695             }
21696             
21697             if(this.afterDragDrop){
21698                 /**
21699                  * An empty function by default, but provided so that you can perform a custom action
21700                  * after a valid drag drop has occurred by providing an implementation.
21701                  * @param {Roo.dd.DragDrop} target The drop target
21702                  * @param {Event} e The event object
21703                  * @param {String} id The id of the dropped element
21704                  * @method afterDragDrop
21705                  */
21706                 this.afterDragDrop(target, e, id);
21707             }
21708         }
21709         delete this.cachedTarget;
21710     },
21711
21712     /**
21713      * An empty function by default, but provided so that you can perform a custom action before the dragged
21714      * item is dropped onto the target and optionally cancel the onDragDrop.
21715      * @param {Roo.dd.DragDrop} target The drop target
21716      * @param {Event} e The event object
21717      * @param {String} id The id of the dragged element
21718      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21719      */
21720     beforeDragDrop : function(target, e, id){
21721         return true;
21722     },
21723
21724     // private
21725     onValidDrop : function(target, e, id){
21726         this.hideProxy();
21727         if(this.afterValidDrop){
21728             /**
21729              * An empty function by default, but provided so that you can perform a custom action
21730              * after a valid drop has occurred by providing an implementation.
21731              * @param {Object} target The target DD 
21732              * @param {Event} e The event object
21733              * @param {String} id The id of the dropped element
21734              * @method afterInvalidDrop
21735              */
21736             this.afterValidDrop(target, e, id);
21737         }
21738     },
21739
21740     // private
21741     getRepairXY : function(e, data){
21742         return this.el.getXY();  
21743     },
21744
21745     // private
21746     onInvalidDrop : function(target, e, id){
21747         this.beforeInvalidDrop(target, e, id);
21748         if(this.cachedTarget){
21749             if(this.cachedTarget.isNotifyTarget){
21750                 this.cachedTarget.notifyOut(this, e, this.dragData);
21751             }
21752             this.cacheTarget = null;
21753         }
21754         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21755
21756         if(this.afterInvalidDrop){
21757             /**
21758              * An empty function by default, but provided so that you can perform a custom action
21759              * after an invalid drop has occurred by providing an implementation.
21760              * @param {Event} e The event object
21761              * @param {String} id The id of the dropped element
21762              * @method afterInvalidDrop
21763              */
21764             this.afterInvalidDrop(e, id);
21765         }
21766     },
21767
21768     // private
21769     afterRepair : function(){
21770         if(Roo.enableFx){
21771             this.el.highlight(this.hlColor || "c3daf9");
21772         }
21773         this.dragging = false;
21774     },
21775
21776     /**
21777      * An empty function by default, but provided so that you can perform a custom action after an invalid
21778      * drop has occurred.
21779      * @param {Roo.dd.DragDrop} target The drop target
21780      * @param {Event} e The event object
21781      * @param {String} id The id of the dragged element
21782      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21783      */
21784     beforeInvalidDrop : function(target, e, id){
21785         return true;
21786     },
21787
21788     // private
21789     handleMouseDown : function(e){
21790         if(this.dragging) {
21791             return;
21792         }
21793         var data = this.getDragData(e);
21794         if(data && this.onBeforeDrag(data, e) !== false){
21795             this.dragData = data;
21796             this.proxy.stop();
21797             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21798         } 
21799     },
21800
21801     /**
21802      * An empty function by default, but provided so that you can perform a custom action before the initial
21803      * drag event begins and optionally cancel it.
21804      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21805      * @param {Event} e The event object
21806      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21807      */
21808     onBeforeDrag : function(data, e){
21809         return true;
21810     },
21811
21812     /**
21813      * An empty function by default, but provided so that you can perform a custom action once the initial
21814      * drag event has begun.  The drag cannot be canceled from this function.
21815      * @param {Number} x The x position of the click on the dragged object
21816      * @param {Number} y The y position of the click on the dragged object
21817      */
21818     onStartDrag : Roo.emptyFn,
21819
21820     // private - YUI override
21821     startDrag : function(x, y){
21822         this.proxy.reset();
21823         this.dragging = true;
21824         this.proxy.update("");
21825         this.onInitDrag(x, y);
21826         this.proxy.show();
21827     },
21828
21829     // private
21830     onInitDrag : function(x, y){
21831         var clone = this.el.dom.cloneNode(true);
21832         clone.id = Roo.id(); // prevent duplicate ids
21833         this.proxy.update(clone);
21834         this.onStartDrag(x, y);
21835         return true;
21836     },
21837
21838     /**
21839      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21840      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21841      */
21842     getProxy : function(){
21843         return this.proxy;  
21844     },
21845
21846     /**
21847      * Hides the drag source's {@link Roo.dd.StatusProxy}
21848      */
21849     hideProxy : function(){
21850         this.proxy.hide();  
21851         this.proxy.reset(true);
21852         this.dragging = false;
21853     },
21854
21855     // private
21856     triggerCacheRefresh : function(){
21857         Roo.dd.DDM.refreshCache(this.groups);
21858     },
21859
21860     // private - override to prevent hiding
21861     b4EndDrag: function(e) {
21862     },
21863
21864     // private - override to prevent moving
21865     endDrag : function(e){
21866         this.onEndDrag(this.dragData, e);
21867     },
21868
21869     // private
21870     onEndDrag : function(data, e){
21871     },
21872     
21873     // private - pin to cursor
21874     autoOffset : function(x, y) {
21875         this.setDelta(-12, -20);
21876     }    
21877 });/*
21878  * Based on:
21879  * Ext JS Library 1.1.1
21880  * Copyright(c) 2006-2007, Ext JS, LLC.
21881  *
21882  * Originally Released Under LGPL - original licence link has changed is not relivant.
21883  *
21884  * Fork - LGPL
21885  * <script type="text/javascript">
21886  */
21887
21888
21889 /**
21890  * @class Roo.dd.DropTarget
21891  * @extends Roo.dd.DDTarget
21892  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21893  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21894  * @constructor
21895  * @param {String/HTMLElement/Element} el The container element
21896  * @param {Object} config
21897  */
21898 Roo.dd.DropTarget = function(el, config){
21899     this.el = Roo.get(el);
21900     
21901     var listeners = false; ;
21902     if (config && config.listeners) {
21903         listeners= config.listeners;
21904         delete config.listeners;
21905     }
21906     Roo.apply(this, config);
21907     
21908     if(this.containerScroll){
21909         Roo.dd.ScrollManager.register(this.el);
21910     }
21911     this.addEvents( {
21912          /**
21913          * @scope Roo.dd.DropTarget
21914          */
21915          
21916          /**
21917          * @event enter
21918          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21919          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21920          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21921          * 
21922          * IMPORTANT : it should set this.overClass and this.dropAllowed
21923          * 
21924          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21925          * @param {Event} e The event
21926          * @param {Object} data An object containing arbitrary data supplied by the drag source
21927          */
21928         "enter" : true,
21929         
21930          /**
21931          * @event over
21932          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21933          * This method will be called on every mouse movement while the drag source is over the drop target.
21934          * This default implementation simply returns the dropAllowed config value.
21935          * 
21936          * IMPORTANT : it should set this.dropAllowed
21937          * 
21938          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21939          * @param {Event} e The event
21940          * @param {Object} data An object containing arbitrary data supplied by the drag source
21941          
21942          */
21943         "over" : true,
21944         /**
21945          * @event out
21946          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21947          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21948          * overClass (if any) from the drop element.
21949          * 
21950          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21951          * @param {Event} e The event
21952          * @param {Object} data An object containing arbitrary data supplied by the drag source
21953          */
21954          "out" : true,
21955          
21956         /**
21957          * @event drop
21958          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21959          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21960          * implementation that does something to process the drop event and returns true so that the drag source's
21961          * repair action does not run.
21962          * 
21963          * IMPORTANT : it should set this.success
21964          * 
21965          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21966          * @param {Event} e The event
21967          * @param {Object} data An object containing arbitrary data supplied by the drag source
21968         */
21969          "drop" : true
21970     });
21971             
21972      
21973     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21974         this.el.dom, 
21975         this.ddGroup || this.group,
21976         {
21977             isTarget: true,
21978             listeners : listeners || {} 
21979            
21980         
21981         }
21982     );
21983
21984 };
21985
21986 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21987     /**
21988      * @cfg {String} overClass
21989      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21990      */
21991      /**
21992      * @cfg {String} ddGroup
21993      * The drag drop group to handle drop events for
21994      */
21995      
21996     /**
21997      * @cfg {String} dropAllowed
21998      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21999      */
22000     dropAllowed : "x-dd-drop-ok",
22001     /**
22002      * @cfg {String} dropNotAllowed
22003      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22004      */
22005     dropNotAllowed : "x-dd-drop-nodrop",
22006     /**
22007      * @cfg {boolean} success
22008      * set this after drop listener.. 
22009      */
22010     success : false,
22011     /**
22012      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22013      * if the drop point is valid for over/enter..
22014      */
22015     valid : false,
22016     // private
22017     isTarget : true,
22018
22019     // private
22020     isNotifyTarget : true,
22021     
22022     /**
22023      * @hide
22024      */
22025     notifyEnter : function(dd, e, data)
22026     {
22027         this.valid = true;
22028         this.fireEvent('enter', dd, e, data);
22029         if(this.overClass){
22030             this.el.addClass(this.overClass);
22031         }
22032         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22033             this.valid ? this.dropAllowed : this.dropNotAllowed
22034         );
22035     },
22036
22037     /**
22038      * @hide
22039      */
22040     notifyOver : function(dd, e, data)
22041     {
22042         this.valid = true;
22043         this.fireEvent('over', dd, e, data);
22044         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22045             this.valid ? this.dropAllowed : this.dropNotAllowed
22046         );
22047     },
22048
22049     /**
22050      * @hide
22051      */
22052     notifyOut : function(dd, e, data)
22053     {
22054         this.fireEvent('out', dd, e, data);
22055         if(this.overClass){
22056             this.el.removeClass(this.overClass);
22057         }
22058     },
22059
22060     /**
22061      * @hide
22062      */
22063     notifyDrop : function(dd, e, data)
22064     {
22065         this.success = false;
22066         this.fireEvent('drop', dd, e, data);
22067         return this.success;
22068     }
22069 });/*
22070  * Based on:
22071  * Ext JS Library 1.1.1
22072  * Copyright(c) 2006-2007, Ext JS, LLC.
22073  *
22074  * Originally Released Under LGPL - original licence link has changed is not relivant.
22075  *
22076  * Fork - LGPL
22077  * <script type="text/javascript">
22078  */
22079
22080
22081 /**
22082  * @class Roo.dd.DragZone
22083  * @extends Roo.dd.DragSource
22084  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22085  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22086  * @constructor
22087  * @param {String/HTMLElement/Element} el The container element
22088  * @param {Object} config
22089  */
22090 Roo.dd.DragZone = function(el, config){
22091     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22092     if(this.containerScroll){
22093         Roo.dd.ScrollManager.register(this.el);
22094     }
22095 };
22096
22097 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22098     /**
22099      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22100      * for auto scrolling during drag operations.
22101      */
22102     /**
22103      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22104      * method after a failed drop (defaults to "c3daf9" - light blue)
22105      */
22106
22107     /**
22108      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22109      * for a valid target to drag based on the mouse down. Override this method
22110      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22111      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22112      * @param {EventObject} e The mouse down event
22113      * @return {Object} The dragData
22114      */
22115     getDragData : function(e){
22116         return Roo.dd.Registry.getHandleFromEvent(e);
22117     },
22118     
22119     /**
22120      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22121      * this.dragData.ddel
22122      * @param {Number} x The x position of the click on the dragged object
22123      * @param {Number} y The y position of the click on the dragged object
22124      * @return {Boolean} true to continue the drag, false to cancel
22125      */
22126     onInitDrag : function(x, y){
22127         this.proxy.update(this.dragData.ddel.cloneNode(true));
22128         this.onStartDrag(x, y);
22129         return true;
22130     },
22131     
22132     /**
22133      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22134      */
22135     afterRepair : function(){
22136         if(Roo.enableFx){
22137             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22138         }
22139         this.dragging = false;
22140     },
22141
22142     /**
22143      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22144      * the XY of this.dragData.ddel
22145      * @param {EventObject} e The mouse up event
22146      * @return {Array} The xy location (e.g. [100, 200])
22147      */
22148     getRepairXY : function(e){
22149         return Roo.Element.fly(this.dragData.ddel).getXY();  
22150     }
22151 });/*
22152  * Based on:
22153  * Ext JS Library 1.1.1
22154  * Copyright(c) 2006-2007, Ext JS, LLC.
22155  *
22156  * Originally Released Under LGPL - original licence link has changed is not relivant.
22157  *
22158  * Fork - LGPL
22159  * <script type="text/javascript">
22160  */
22161 /**
22162  * @class Roo.dd.DropZone
22163  * @extends Roo.dd.DropTarget
22164  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22165  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22166  * @constructor
22167  * @param {String/HTMLElement/Element} el The container element
22168  * @param {Object} config
22169  */
22170 Roo.dd.DropZone = function(el, config){
22171     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22172 };
22173
22174 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22175     /**
22176      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22177      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22178      * provide your own custom lookup.
22179      * @param {Event} e The event
22180      * @return {Object} data The custom data
22181      */
22182     getTargetFromEvent : function(e){
22183         return Roo.dd.Registry.getTargetFromEvent(e);
22184     },
22185
22186     /**
22187      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22188      * that it has registered.  This method has no default implementation and should be overridden to provide
22189      * node-specific processing if necessary.
22190      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22191      * {@link #getTargetFromEvent} for this node)
22192      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22193      * @param {Event} e The event
22194      * @param {Object} data An object containing arbitrary data supplied by the drag source
22195      */
22196     onNodeEnter : function(n, dd, e, data){
22197         
22198     },
22199
22200     /**
22201      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22202      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22203      * overridden to provide the proper feedback.
22204      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22205      * {@link #getTargetFromEvent} for this node)
22206      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22207      * @param {Event} e The event
22208      * @param {Object} data An object containing arbitrary data supplied by the drag source
22209      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22210      * underlying {@link Roo.dd.StatusProxy} can be updated
22211      */
22212     onNodeOver : function(n, dd, e, data){
22213         return this.dropAllowed;
22214     },
22215
22216     /**
22217      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22218      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22219      * node-specific processing if necessary.
22220      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22221      * {@link #getTargetFromEvent} for this node)
22222      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22223      * @param {Event} e The event
22224      * @param {Object} data An object containing arbitrary data supplied by the drag source
22225      */
22226     onNodeOut : function(n, dd, e, data){
22227         
22228     },
22229
22230     /**
22231      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22232      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22233      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22234      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22235      * {@link #getTargetFromEvent} for this node)
22236      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22237      * @param {Event} e The event
22238      * @param {Object} data An object containing arbitrary data supplied by the drag source
22239      * @return {Boolean} True if the drop was valid, else false
22240      */
22241     onNodeDrop : function(n, dd, e, data){
22242         return false;
22243     },
22244
22245     /**
22246      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22247      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22248      * it should be overridden to provide the proper feedback if necessary.
22249      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22250      * @param {Event} e The event
22251      * @param {Object} data An object containing arbitrary data supplied by the drag source
22252      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22253      * underlying {@link Roo.dd.StatusProxy} can be updated
22254      */
22255     onContainerOver : function(dd, e, data){
22256         return this.dropNotAllowed;
22257     },
22258
22259     /**
22260      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22261      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22262      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22263      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22264      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22265      * @param {Event} e The event
22266      * @param {Object} data An object containing arbitrary data supplied by the drag source
22267      * @return {Boolean} True if the drop was valid, else false
22268      */
22269     onContainerDrop : function(dd, e, data){
22270         return false;
22271     },
22272
22273     /**
22274      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22275      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22276      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22277      * you should override this method and provide a custom implementation.
22278      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22279      * @param {Event} e The event
22280      * @param {Object} data An object containing arbitrary data supplied by the drag source
22281      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22282      * underlying {@link Roo.dd.StatusProxy} can be updated
22283      */
22284     notifyEnter : function(dd, e, data){
22285         return this.dropNotAllowed;
22286     },
22287
22288     /**
22289      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22290      * This method will be called on every mouse movement while the drag source is over the drop zone.
22291      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22292      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22293      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22294      * registered node, it will call {@link #onContainerOver}.
22295      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22296      * @param {Event} e The event
22297      * @param {Object} data An object containing arbitrary data supplied by the drag source
22298      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22299      * underlying {@link Roo.dd.StatusProxy} can be updated
22300      */
22301     notifyOver : function(dd, e, data){
22302         var n = this.getTargetFromEvent(e);
22303         if(!n){ // not over valid drop target
22304             if(this.lastOverNode){
22305                 this.onNodeOut(this.lastOverNode, dd, e, data);
22306                 this.lastOverNode = null;
22307             }
22308             return this.onContainerOver(dd, e, data);
22309         }
22310         if(this.lastOverNode != n){
22311             if(this.lastOverNode){
22312                 this.onNodeOut(this.lastOverNode, dd, e, data);
22313             }
22314             this.onNodeEnter(n, dd, e, data);
22315             this.lastOverNode = n;
22316         }
22317         return this.onNodeOver(n, dd, e, data);
22318     },
22319
22320     /**
22321      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22322      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22323      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22324      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22325      * @param {Event} e The event
22326      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22327      */
22328     notifyOut : function(dd, e, data){
22329         if(this.lastOverNode){
22330             this.onNodeOut(this.lastOverNode, dd, e, data);
22331             this.lastOverNode = null;
22332         }
22333     },
22334
22335     /**
22336      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22337      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22338      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22339      * otherwise it will call {@link #onContainerDrop}.
22340      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22341      * @param {Event} e The event
22342      * @param {Object} data An object containing arbitrary data supplied by the drag source
22343      * @return {Boolean} True if the drop was valid, else false
22344      */
22345     notifyDrop : function(dd, e, data){
22346         if(this.lastOverNode){
22347             this.onNodeOut(this.lastOverNode, dd, e, data);
22348             this.lastOverNode = null;
22349         }
22350         var n = this.getTargetFromEvent(e);
22351         return n ?
22352             this.onNodeDrop(n, dd, e, data) :
22353             this.onContainerDrop(dd, e, data);
22354     },
22355
22356     // private
22357     triggerCacheRefresh : function(){
22358         Roo.dd.DDM.refreshCache(this.groups);
22359     }  
22360 });