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         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iphone|ipad/.test(ua),
67         isTouch =  (function() {
68             try {
69                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
70                     window.addEventListener('touchstart', function __set_has_touch__ () {
71                         Roo.isTouch = true;
72                         window.removeEventListener('touchstart', __set_has_touch__);
73                     });
74                     return false; // no touch on chrome!?
75                 }
76                 document.createEvent("TouchEvent");  
77                 return true;  
78             } catch (e) {  
79                 return false;  
80             } 
81             
82         })();
83     // remove css image flicker
84         if(isIE && !isIE7){
85         try{
86             document.execCommand("BackgroundImageCache", false, true);
87         }catch(e){}
88     }
89     
90     Roo.apply(Roo, {
91         /**
92          * True if the browser is in strict mode
93          * @type Boolean
94          */
95         isStrict : isStrict,
96         /**
97          * True if the page is running over SSL
98          * @type Boolean
99          */
100         isSecure : isSecure,
101         /**
102          * True when the document is fully initialized and ready for action
103          * @type Boolean
104          */
105         isReady : false,
106         /**
107          * Turn on debugging output (currently only the factory uses this)
108          * @type Boolean
109          */
110         
111         debug: false,
112
113         /**
114          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
115          * @type Boolean
116          */
117         enableGarbageCollector : true,
118
119         /**
120          * True to automatically purge event listeners after uncaching an element (defaults to false).
121          * Note: this only happens if enableGarbageCollector is true.
122          * @type Boolean
123          */
124         enableListenerCollection:false,
125
126         /**
127          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
128          * the IE insecure content warning (defaults to javascript:false).
129          * @type String
130          */
131         SSL_SECURE_URL : "javascript:false",
132
133         /**
134          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
135          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
136          * @type String
137          */
138         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
139
140         emptyFn : function(){},
141         
142         /**
143          * Copies all the properties of config to obj if they don't already exist.
144          * @param {Object} obj The receiver of the properties
145          * @param {Object} config The source of the properties
146          * @return {Object} returns obj
147          */
148         applyIf : function(o, c){
149             if(o && c){
150                 for(var p in c){
151                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
152                 }
153             }
154             return o;
155         },
156
157         /**
158          * Applies event listeners to elements by selectors when the document is ready.
159          * The event name is specified with an @ suffix.
160 <pre><code>
161 Roo.addBehaviors({
162    // add a listener for click on all anchors in element with id foo
163    '#foo a@click' : function(e, t){
164        // do something
165    },
166
167    // add the same listener to multiple selectors (separated by comma BEFORE the @)
168    '#foo a, #bar span.some-class@mouseover' : function(){
169        // do something
170    }
171 });
172 </code></pre>
173          * @param {Object} obj The list of behaviors to apply
174          */
175         addBehaviors : function(o){
176             if(!Roo.isReady){
177                 Roo.onReady(function(){
178                     Roo.addBehaviors(o);
179                 });
180                 return;
181             }
182             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
183             for(var b in o){
184                 var parts = b.split('@');
185                 if(parts[1]){ // for Object prototype breakers
186                     var s = parts[0];
187                     if(!cache[s]){
188                         cache[s] = Roo.select(s);
189                     }
190                     cache[s].on(parts[1], o[b]);
191                 }
192             }
193             cache = null;
194         },
195
196         /**
197          * Generates unique ids. If the element already has an id, it is unchanged
198          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
199          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
200          * @return {String} The generated Id.
201          */
202         id : function(el, prefix){
203             prefix = prefix || "roo-gen";
204             el = Roo.getDom(el);
205             var id = prefix + (++idSeed);
206             return el ? (el.id ? el.id : (el.id = id)) : id;
207         },
208          
209        
210         /**
211          * Extends one class with another class and optionally overrides members with the passed literal. This class
212          * also adds the function "override()" to the class that can be used to override
213          * members on an instance.
214          * @param {Object} subclass The class inheriting the functionality
215          * @param {Object} superclass The class being extended
216          * @param {Object} overrides (optional) A literal with members
217          * @method extend
218          */
219         extend : function(){
220             // inline overrides
221             var io = function(o){
222                 for(var m in o){
223                     this[m] = o[m];
224                 }
225             };
226             return function(sb, sp, overrides){
227                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
228                     overrides = sp;
229                     sp = sb;
230                     sb = function(){sp.apply(this, arguments);};
231                 }
232                 var F = function(){}, sbp, spp = sp.prototype;
233                 F.prototype = spp;
234                 sbp = sb.prototype = new F();
235                 sbp.constructor=sb;
236                 sb.superclass=spp;
237                 
238                 if(spp.constructor == Object.prototype.constructor){
239                     spp.constructor=sp;
240                    
241                 }
242                 
243                 sb.override = function(o){
244                     Roo.override(sb, o);
245                 };
246                 sbp.override = io;
247                 Roo.override(sb, overrides);
248                 return sb;
249             };
250         }(),
251
252         /**
253          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
254          * Usage:<pre><code>
255 Roo.override(MyClass, {
256     newMethod1: function(){
257         // etc.
258     },
259     newMethod2: function(foo){
260         // etc.
261     }
262 });
263  </code></pre>
264          * @param {Object} origclass The class to override
265          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
266          * containing one or more methods.
267          * @method override
268          */
269         override : function(origclass, overrides){
270             if(overrides){
271                 var p = origclass.prototype;
272                 for(var method in overrides){
273                     p[method] = overrides[method];
274                 }
275             }
276         },
277         /**
278          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
279          * <pre><code>
280 Roo.namespace('Company', 'Company.data');
281 Company.Widget = function() { ... }
282 Company.data.CustomStore = function(config) { ... }
283 </code></pre>
284          * @param {String} namespace1
285          * @param {String} namespace2
286          * @param {String} etc
287          * @method namespace
288          */
289         namespace : function(){
290             var a=arguments, o=null, i, j, d, rt;
291             for (i=0; i<a.length; ++i) {
292                 d=a[i].split(".");
293                 rt = d[0];
294                 /** eval:var:o */
295                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
296                 for (j=1; j<d.length; ++j) {
297                     o[d[j]]=o[d[j]] || {};
298                     o=o[d[j]];
299                 }
300             }
301         },
302         /**
303          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
304          * <pre><code>
305 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
306 Roo.factory(conf, Roo.data);
307 </code></pre>
308          * @param {String} classname
309          * @param {String} namespace (optional)
310          * @method factory
311          */
312          
313         factory : function(c, ns)
314         {
315             // no xtype, no ns or c.xns - or forced off by c.xns
316             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
317                 return c;
318             }
319             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
320             if (c.constructor == ns[c.xtype]) {// already created...
321                 return c;
322             }
323             if (ns[c.xtype]) {
324                 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
325                 var ret = new ns[c.xtype](c);
326                 ret.xns = false;
327                 return ret;
328             }
329             c.xns = false; // prevent recursion..
330             return c;
331         },
332          /**
333          * Logs to console if it can.
334          *
335          * @param {String|Object} string
336          * @method log
337          */
338         log : function(s)
339         {
340             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
341                 return; // alerT?
342             }
343             console.log(s);
344             
345         },
346         /**
347          * 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.
348          * @param {Object} o
349          * @return {String}
350          */
351         urlEncode : function(o){
352             if(!o){
353                 return "";
354             }
355             var buf = [];
356             for(var key in o){
357                 var ov = o[key], k = Roo.encodeURIComponent(key);
358                 var type = typeof ov;
359                 if(type == 'undefined'){
360                     buf.push(k, "=&");
361                 }else if(type != "function" && type != "object"){
362                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
363                 }else if(ov instanceof Array){
364                     if (ov.length) {
365                             for(var i = 0, len = ov.length; i < len; i++) {
366                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
367                             }
368                         } else {
369                             buf.push(k, "=&");
370                         }
371                 }
372             }
373             buf.pop();
374             return buf.join("");
375         },
376          /**
377          * Safe version of encodeURIComponent
378          * @param {String} data 
379          * @return {String} 
380          */
381         
382         encodeURIComponent : function (data)
383         {
384             try {
385                 return encodeURIComponent(data);
386             } catch(e) {} // should be an uri encode error.
387             
388             if (data == '' || data == null){
389                return '';
390             }
391             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
392             function nibble_to_hex(nibble){
393                 var chars = '0123456789ABCDEF';
394                 return chars.charAt(nibble);
395             }
396             data = data.toString();
397             var buffer = '';
398             for(var i=0; i<data.length; i++){
399                 var c = data.charCodeAt(i);
400                 var bs = new Array();
401                 if (c > 0x10000){
402                         // 4 bytes
403                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
404                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
405                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
406                     bs[3] = 0x80 | (c & 0x3F);
407                 }else if (c > 0x800){
408                          // 3 bytes
409                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
410                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
411                     bs[2] = 0x80 | (c & 0x3F);
412                 }else if (c > 0x80){
413                        // 2 bytes
414                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
415                     bs[1] = 0x80 | (c & 0x3F);
416                 }else{
417                         // 1 byte
418                     bs[0] = c;
419                 }
420                 for(var j=0; j<bs.length; j++){
421                     var b = bs[j];
422                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
423                             + nibble_to_hex(b &0x0F);
424                     buffer += '%'+hex;
425                }
426             }
427             return buffer;    
428              
429         },
430
431         /**
432          * 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]}.
433          * @param {String} string
434          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
435          * @return {Object} A literal with members
436          */
437         urlDecode : function(string, overwrite){
438             if(!string || !string.length){
439                 return {};
440             }
441             var obj = {};
442             var pairs = string.split('&');
443             var pair, name, value;
444             for(var i = 0, len = pairs.length; i < len; i++){
445                 pair = pairs[i].split('=');
446                 name = decodeURIComponent(pair[0]);
447                 value = decodeURIComponent(pair[1]);
448                 if(overwrite !== true){
449                     if(typeof obj[name] == "undefined"){
450                         obj[name] = value;
451                     }else if(typeof obj[name] == "string"){
452                         obj[name] = [obj[name]];
453                         obj[name].push(value);
454                     }else{
455                         obj[name].push(value);
456                     }
457                 }else{
458                     obj[name] = value;
459                 }
460             }
461             return obj;
462         },
463
464         /**
465          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
466          * passed array is not really an array, your function is called once with it.
467          * The supplied function is called with (Object item, Number index, Array allItems).
468          * @param {Array/NodeList/Mixed} array
469          * @param {Function} fn
470          * @param {Object} scope
471          */
472         each : function(array, fn, scope){
473             if(typeof array.length == "undefined" || typeof array == "string"){
474                 array = [array];
475             }
476             for(var i = 0, len = array.length; i < len; i++){
477                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
478             }
479         },
480
481         // deprecated
482         combine : function(){
483             var as = arguments, l = as.length, r = [];
484             for(var i = 0; i < l; i++){
485                 var a = as[i];
486                 if(a instanceof Array){
487                     r = r.concat(a);
488                 }else if(a.length !== undefined && !a.substr){
489                     r = r.concat(Array.prototype.slice.call(a, 0));
490                 }else{
491                     r.push(a);
492                 }
493             }
494             return r;
495         },
496
497         /**
498          * Escapes the passed string for use in a regular expression
499          * @param {String} str
500          * @return {String}
501          */
502         escapeRe : function(s) {
503             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
504         },
505
506         // internal
507         callback : function(cb, scope, args, delay){
508             if(typeof cb == "function"){
509                 if(delay){
510                     cb.defer(delay, scope, args || []);
511                 }else{
512                     cb.apply(scope, args || []);
513                 }
514             }
515         },
516
517         /**
518          * Return the dom node for the passed string (id), dom node, or Roo.Element
519          * @param {String/HTMLElement/Roo.Element} el
520          * @return HTMLElement
521          */
522         getDom : function(el){
523             if(!el){
524                 return null;
525             }
526             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
527         },
528
529         /**
530         * Shorthand for {@link Roo.ComponentMgr#get}
531         * @param {String} id
532         * @return Roo.Component
533         */
534         getCmp : function(id){
535             return Roo.ComponentMgr.get(id);
536         },
537          
538         num : function(v, defaultValue){
539             if(typeof v != 'number'){
540                 return defaultValue;
541             }
542             return v;
543         },
544
545         destroy : function(){
546             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
547                 var as = a[i];
548                 if(as){
549                     if(as.dom){
550                         as.removeAllListeners();
551                         as.remove();
552                         continue;
553                     }
554                     if(typeof as.purgeListeners == 'function'){
555                         as.purgeListeners();
556                     }
557                     if(typeof as.destroy == 'function'){
558                         as.destroy();
559                     }
560                 }
561             }
562         },
563
564         // inpired by a similar function in mootools library
565         /**
566          * Returns the type of object that is passed in. If the object passed in is null or undefined it
567          * return false otherwise it returns one of the following values:<ul>
568          * <li><b>string</b>: If the object passed is a string</li>
569          * <li><b>number</b>: If the object passed is a number</li>
570          * <li><b>boolean</b>: If the object passed is a boolean value</li>
571          * <li><b>function</b>: If the object passed is a function reference</li>
572          * <li><b>object</b>: If the object passed is an object</li>
573          * <li><b>array</b>: If the object passed is an array</li>
574          * <li><b>regexp</b>: If the object passed is a regular expression</li>
575          * <li><b>element</b>: If the object passed is a DOM Element</li>
576          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
577          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
578          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
579          * @param {Mixed} object
580          * @return {String}
581          */
582         type : function(o){
583             if(o === undefined || o === null){
584                 return false;
585             }
586             if(o.htmlElement){
587                 return 'element';
588             }
589             var t = typeof o;
590             if(t == 'object' && o.nodeName) {
591                 switch(o.nodeType) {
592                     case 1: return 'element';
593                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
594                 }
595             }
596             if(t == 'object' || t == 'function') {
597                 switch(o.constructor) {
598                     case Array: return 'array';
599                     case RegExp: return 'regexp';
600                 }
601                 if(typeof o.length == 'number' && typeof o.item == 'function') {
602                     return 'nodelist';
603                 }
604             }
605             return t;
606         },
607
608         /**
609          * Returns true if the passed value is null, undefined or an empty string (optional).
610          * @param {Mixed} value The value to test
611          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
612          * @return {Boolean}
613          */
614         isEmpty : function(v, allowBlank){
615             return v === null || v === undefined || (!allowBlank ? v === '' : false);
616         },
617         
618         /** @type Boolean */
619         isOpera : isOpera,
620         /** @type Boolean */
621         isSafari : isSafari,
622         /** @type Boolean */
623         isFirefox : isFirefox,
624         /** @type Boolean */
625         isIE : isIE,
626         /** @type Boolean */
627         isIE7 : isIE7,
628         /** @type Boolean */
629         isIE11 : isIE11,
630         /** @type Boolean */
631         isGecko : isGecko,
632         /** @type Boolean */
633         isBorderBox : isBorderBox,
634         /** @type Boolean */
635         isWindows : isWindows,
636         /** @type Boolean */
637         isLinux : isLinux,
638         /** @type Boolean */
639         isMac : isMac,
640         /** @type Boolean */
641         isIOS : isIOS,
642         /** @type Boolean */
643         isTouch : isTouch,
644
645         /**
646          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
647          * you may want to set this to true.
648          * @type Boolean
649          */
650         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
651         
652         
653                 
654         /**
655          * Selects a single element as a Roo Element
656          * This is about as close as you can get to jQuery's $('do crazy stuff')
657          * @param {String} selector The selector/xpath query
658          * @param {Node} root (optional) The start of the query (defaults to document).
659          * @return {Roo.Element}
660          */
661         selectNode : function(selector, root) 
662         {
663             var node = Roo.DomQuery.selectNode(selector,root);
664             return node ? Roo.get(node) : new Roo.Element(false);
665         }
666         
667     });
668
669
670 })();
671
672 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
673                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
674                 "Roo.app", "Roo.ux",
675                 "Roo.bootstrap",
676                 "Roo.bootstrap.dash");
677 /*
678  * Based on:
679  * Ext JS Library 1.1.1
680  * Copyright(c) 2006-2007, Ext JS, LLC.
681  *
682  * Originally Released Under LGPL - original licence link has changed is not relivant.
683  *
684  * Fork - LGPL
685  * <script type="text/javascript">
686  */
687
688 (function() {    
689     // wrappedn so fnCleanup is not in global scope...
690     if(Roo.isIE) {
691         function fnCleanUp() {
692             var p = Function.prototype;
693             delete p.createSequence;
694             delete p.defer;
695             delete p.createDelegate;
696             delete p.createCallback;
697             delete p.createInterceptor;
698
699             window.detachEvent("onunload", fnCleanUp);
700         }
701         window.attachEvent("onunload", fnCleanUp);
702     }
703 })();
704
705
706 /**
707  * @class Function
708  * These functions are available on every Function object (any JavaScript function).
709  */
710 Roo.apply(Function.prototype, {
711      /**
712      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
713      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
714      * Will create a function that is bound to those 2 args.
715      * @return {Function} The new function
716     */
717     createCallback : function(/*args...*/){
718         // make args available, in function below
719         var args = arguments;
720         var method = this;
721         return function() {
722             return method.apply(window, args);
723         };
724     },
725
726     /**
727      * Creates a delegate (callback) that sets the scope to obj.
728      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
729      * Will create a function that is automatically scoped to this.
730      * @param {Object} obj (optional) The object for which the scope is set
731      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
732      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
733      *                                             if a number the args are inserted at the specified position
734      * @return {Function} The new function
735      */
736     createDelegate : function(obj, args, appendArgs){
737         var method = this;
738         return function() {
739             var callArgs = args || arguments;
740             if(appendArgs === true){
741                 callArgs = Array.prototype.slice.call(arguments, 0);
742                 callArgs = callArgs.concat(args);
743             }else if(typeof appendArgs == "number"){
744                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
745                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
746                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
747             }
748             return method.apply(obj || window, callArgs);
749         };
750     },
751
752     /**
753      * Calls this function after the number of millseconds specified.
754      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
755      * @param {Object} obj (optional) The object for which the scope is set
756      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
757      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
758      *                                             if a number the args are inserted at the specified position
759      * @return {Number} The timeout id that can be used with clearTimeout
760      */
761     defer : function(millis, obj, args, appendArgs){
762         var fn = this.createDelegate(obj, args, appendArgs);
763         if(millis){
764             return setTimeout(fn, millis);
765         }
766         fn();
767         return 0;
768     },
769     /**
770      * Create a combined function call sequence of the original function + the passed function.
771      * The resulting function returns the results of the original function.
772      * The passed fcn is called with the parameters of the original function
773      * @param {Function} fcn The function to sequence
774      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
775      * @return {Function} The new function
776      */
777     createSequence : function(fcn, scope){
778         if(typeof fcn != "function"){
779             return this;
780         }
781         var method = this;
782         return function() {
783             var retval = method.apply(this || window, arguments);
784             fcn.apply(scope || this || window, arguments);
785             return retval;
786         };
787     },
788
789     /**
790      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
791      * The resulting function returns the results of the original function.
792      * The passed fcn is called with the parameters of the original function.
793      * @addon
794      * @param {Function} fcn The function to call before the original
795      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
796      * @return {Function} The new function
797      */
798     createInterceptor : function(fcn, scope){
799         if(typeof fcn != "function"){
800             return this;
801         }
802         var method = this;
803         return function() {
804             fcn.target = this;
805             fcn.method = method;
806             if(fcn.apply(scope || this || window, arguments) === false){
807                 return;
808             }
809             return method.apply(this || window, arguments);
810         };
811     }
812 });
813 /*
814  * Based on:
815  * Ext JS Library 1.1.1
816  * Copyright(c) 2006-2007, Ext JS, LLC.
817  *
818  * Originally Released Under LGPL - original licence link has changed is not relivant.
819  *
820  * Fork - LGPL
821  * <script type="text/javascript">
822  */
823
824 Roo.applyIf(String, {
825     
826     /** @scope String */
827     
828     /**
829      * Escapes the passed string for ' and \
830      * @param {String} string The string to escape
831      * @return {String} The escaped string
832      * @static
833      */
834     escape : function(string) {
835         return string.replace(/('|\\)/g, "\\$1");
836     },
837
838     /**
839      * Pads the left side of a string with a specified character.  This is especially useful
840      * for normalizing number and date strings.  Example usage:
841      * <pre><code>
842 var s = String.leftPad('123', 5, '0');
843 // s now contains the string: '00123'
844 </code></pre>
845      * @param {String} string The original string
846      * @param {Number} size The total length of the output string
847      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
848      * @return {String} The padded string
849      * @static
850      */
851     leftPad : function (val, size, ch) {
852         var result = new String(val);
853         if(ch === null || ch === undefined || ch === '') {
854             ch = " ";
855         }
856         while (result.length < size) {
857             result = ch + result;
858         }
859         return result;
860     },
861
862     /**
863      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
864      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
865      * <pre><code>
866 var cls = 'my-class', text = 'Some text';
867 var s = String.format('<div class="{0}">{1}</div>', cls, text);
868 // s now contains the string: '<div class="my-class">Some text</div>'
869 </code></pre>
870      * @param {String} string The tokenized string to be formatted
871      * @param {String} value1 The value to replace token {0}
872      * @param {String} value2 Etc...
873      * @return {String} The formatted string
874      * @static
875      */
876     format : function(format){
877         var args = Array.prototype.slice.call(arguments, 1);
878         return format.replace(/\{(\d+)\}/g, function(m, i){
879             return Roo.util.Format.htmlEncode(args[i]);
880         });
881     }
882 });
883
884 /**
885  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
886  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
887  * they are already different, the first value passed in is returned.  Note that this method returns the new value
888  * but does not change the current string.
889  * <pre><code>
890 // alternate sort directions
891 sort = sort.toggle('ASC', 'DESC');
892
893 // instead of conditional logic:
894 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
895 </code></pre>
896  * @param {String} value The value to compare to the current string
897  * @param {String} other The new value to use if the string already equals the first value passed in
898  * @return {String} The new value
899  */
900  
901 String.prototype.toggle = function(value, other){
902     return this == value ? other : value;
903 };/*
904  * Based on:
905  * Ext JS Library 1.1.1
906  * Copyright(c) 2006-2007, Ext JS, LLC.
907  *
908  * Originally Released Under LGPL - original licence link has changed is not relivant.
909  *
910  * Fork - LGPL
911  * <script type="text/javascript">
912  */
913
914  /**
915  * @class Number
916  */
917 Roo.applyIf(Number.prototype, {
918     /**
919      * Checks whether or not the current number is within a desired range.  If the number is already within the
920      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
921      * exceeded.  Note that this method returns the constrained value but does not change the current number.
922      * @param {Number} min The minimum number in the range
923      * @param {Number} max The maximum number in the range
924      * @return {Number} The constrained value if outside the range, otherwise the current value
925      */
926     constrain : function(min, max){
927         return Math.min(Math.max(this, min), max);
928     }
929 });/*
930  * Based on:
931  * Ext JS Library 1.1.1
932  * Copyright(c) 2006-2007, Ext JS, LLC.
933  *
934  * Originally Released Under LGPL - original licence link has changed is not relivant.
935  *
936  * Fork - LGPL
937  * <script type="text/javascript">
938  */
939  /**
940  * @class Array
941  */
942 Roo.applyIf(Array.prototype, {
943     /**
944      * 
945      * Checks whether or not the specified object exists in the array.
946      * @param {Object} o The object to check for
947      * @return {Number} The index of o in the array (or -1 if it is not found)
948      */
949     indexOf : function(o){
950        for (var i = 0, len = this.length; i < len; i++){
951               if(this[i] == o) { return i; }
952        }
953            return -1;
954     },
955
956     /**
957      * Removes the specified object from the array.  If the object is not found nothing happens.
958      * @param {Object} o The object to remove
959      */
960     remove : function(o){
961        var index = this.indexOf(o);
962        if(index != -1){
963            this.splice(index, 1);
964        }
965     },
966     /**
967      * Map (JS 1.6 compatibility)
968      * @param {Function} function  to call
969      */
970     map : function(fun )
971     {
972         var len = this.length >>> 0;
973         if (typeof fun != "function") {
974             throw new TypeError();
975         }
976         var res = new Array(len);
977         var thisp = arguments[1];
978         for (var i = 0; i < len; i++)
979         {
980             if (i in this) {
981                 res[i] = fun.call(thisp, this[i], i, this);
982             }
983         }
984
985         return res;
986     }
987     
988 });
989
990
991  
992 /*
993  * Based on:
994  * Ext JS Library 1.1.1
995  * Copyright(c) 2006-2007, Ext JS, LLC.
996  *
997  * Originally Released Under LGPL - original licence link has changed is not relivant.
998  *
999  * Fork - LGPL
1000  * <script type="text/javascript">
1001  */
1002
1003 /**
1004  * @class Date
1005  *
1006  * The date parsing and format syntax is a subset of
1007  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1008  * supported will provide results equivalent to their PHP versions.
1009  *
1010  * Following is the list of all currently supported formats:
1011  *<pre>
1012 Sample date:
1013 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1014
1015 Format  Output      Description
1016 ------  ----------  --------------------------------------------------------------
1017   d      10         Day of the month, 2 digits with leading zeros
1018   D      Wed        A textual representation of a day, three letters
1019   j      10         Day of the month without leading zeros
1020   l      Wednesday  A full textual representation of the day of the week
1021   S      th         English ordinal day of month suffix, 2 chars (use with j)
1022   w      3          Numeric representation of the day of the week
1023   z      9          The julian date, or day of the year (0-365)
1024   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1025   F      January    A full textual representation of the month
1026   m      01         Numeric representation of a month, with leading zeros
1027   M      Jan        Month name abbreviation, three letters
1028   n      1          Numeric representation of a month, without leading zeros
1029   t      31         Number of days in the given month
1030   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1031   Y      2007       A full numeric representation of a year, 4 digits
1032   y      07         A two digit representation of a year
1033   a      pm         Lowercase Ante meridiem and Post meridiem
1034   A      PM         Uppercase Ante meridiem and Post meridiem
1035   g      3          12-hour format of an hour without leading zeros
1036   G      15         24-hour format of an hour without leading zeros
1037   h      03         12-hour format of an hour with leading zeros
1038   H      15         24-hour format of an hour with leading zeros
1039   i      05         Minutes with leading zeros
1040   s      01         Seconds, with leading zeros
1041   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1042   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1043   T      CST        Timezone setting of the machine running the code
1044   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1045 </pre>
1046  *
1047  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1048  * <pre><code>
1049 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1050 document.write(dt.format('Y-m-d'));                         //2007-01-10
1051 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1052 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
1053  </code></pre>
1054  *
1055  * Here are some standard date/time patterns that you might find helpful.  They
1056  * are not part of the source of Date.js, but to use them you can simply copy this
1057  * block of code into any script that is included after Date.js and they will also become
1058  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1059  * <pre><code>
1060 Date.patterns = {
1061     ISO8601Long:"Y-m-d H:i:s",
1062     ISO8601Short:"Y-m-d",
1063     ShortDate: "n/j/Y",
1064     LongDate: "l, F d, Y",
1065     FullDateTime: "l, F d, Y g:i:s A",
1066     MonthDay: "F d",
1067     ShortTime: "g:i A",
1068     LongTime: "g:i:s A",
1069     SortableDateTime: "Y-m-d\\TH:i:s",
1070     UniversalSortableDateTime: "Y-m-d H:i:sO",
1071     YearMonth: "F, Y"
1072 };
1073 </code></pre>
1074  *
1075  * Example usage:
1076  * <pre><code>
1077 var dt = new Date();
1078 document.write(dt.format(Date.patterns.ShortDate));
1079  </code></pre>
1080  */
1081
1082 /*
1083  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1084  * They generate precompiled functions from date formats instead of parsing and
1085  * processing the pattern every time you format a date.  These functions are available
1086  * on every Date object (any javascript function).
1087  *
1088  * The original article and download are here:
1089  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1090  *
1091  */
1092  
1093  
1094  // was in core
1095 /**
1096  Returns the number of milliseconds between this date and date
1097  @param {Date} date (optional) Defaults to now
1098  @return {Number} The diff in milliseconds
1099  @member Date getElapsed
1100  */
1101 Date.prototype.getElapsed = function(date) {
1102         return Math.abs((date || new Date()).getTime()-this.getTime());
1103 };
1104 // was in date file..
1105
1106
1107 // private
1108 Date.parseFunctions = {count:0};
1109 // private
1110 Date.parseRegexes = [];
1111 // private
1112 Date.formatFunctions = {count:0};
1113
1114 // private
1115 Date.prototype.dateFormat = function(format) {
1116     if (Date.formatFunctions[format] == null) {
1117         Date.createNewFormat(format);
1118     }
1119     var func = Date.formatFunctions[format];
1120     return this[func]();
1121 };
1122
1123
1124 /**
1125  * Formats a date given the supplied format string
1126  * @param {String} format The format string
1127  * @return {String} The formatted date
1128  * @method
1129  */
1130 Date.prototype.format = Date.prototype.dateFormat;
1131
1132 // private
1133 Date.createNewFormat = function(format) {
1134     var funcName = "format" + Date.formatFunctions.count++;
1135     Date.formatFunctions[format] = funcName;
1136     var code = "Date.prototype." + funcName + " = function(){return ";
1137     var special = false;
1138     var ch = '';
1139     for (var i = 0; i < format.length; ++i) {
1140         ch = format.charAt(i);
1141         if (!special && ch == "\\") {
1142             special = true;
1143         }
1144         else if (special) {
1145             special = false;
1146             code += "'" + String.escape(ch) + "' + ";
1147         }
1148         else {
1149             code += Date.getFormatCode(ch);
1150         }
1151     }
1152     /** eval:var:zzzzzzzzzzzzz */
1153     eval(code.substring(0, code.length - 3) + ";}");
1154 };
1155
1156 // private
1157 Date.getFormatCode = function(character) {
1158     switch (character) {
1159     case "d":
1160         return "String.leftPad(this.getDate(), 2, '0') + ";
1161     case "D":
1162         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1163     case "j":
1164         return "this.getDate() + ";
1165     case "l":
1166         return "Date.dayNames[this.getDay()] + ";
1167     case "S":
1168         return "this.getSuffix() + ";
1169     case "w":
1170         return "this.getDay() + ";
1171     case "z":
1172         return "this.getDayOfYear() + ";
1173     case "W":
1174         return "this.getWeekOfYear() + ";
1175     case "F":
1176         return "Date.monthNames[this.getMonth()] + ";
1177     case "m":
1178         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1179     case "M":
1180         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1181     case "n":
1182         return "(this.getMonth() + 1) + ";
1183     case "t":
1184         return "this.getDaysInMonth() + ";
1185     case "L":
1186         return "(this.isLeapYear() ? 1 : 0) + ";
1187     case "Y":
1188         return "this.getFullYear() + ";
1189     case "y":
1190         return "('' + this.getFullYear()).substring(2, 4) + ";
1191     case "a":
1192         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1193     case "A":
1194         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1195     case "g":
1196         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1197     case "G":
1198         return "this.getHours() + ";
1199     case "h":
1200         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1201     case "H":
1202         return "String.leftPad(this.getHours(), 2, '0') + ";
1203     case "i":
1204         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1205     case "s":
1206         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1207     case "O":
1208         return "this.getGMTOffset() + ";
1209     case "P":
1210         return "this.getGMTColonOffset() + ";
1211     case "T":
1212         return "this.getTimezone() + ";
1213     case "Z":
1214         return "(this.getTimezoneOffset() * -60) + ";
1215     default:
1216         return "'" + String.escape(character) + "' + ";
1217     }
1218 };
1219
1220 /**
1221  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1222  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1223  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1224  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1225  * string or the parse operation will fail.
1226  * Example Usage:
1227 <pre><code>
1228 //dt = Fri May 25 2007 (current date)
1229 var dt = new Date();
1230
1231 //dt = Thu May 25 2006 (today's month/day in 2006)
1232 dt = Date.parseDate("2006", "Y");
1233
1234 //dt = Sun Jan 15 2006 (all date parts specified)
1235 dt = Date.parseDate("2006-1-15", "Y-m-d");
1236
1237 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1238 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1239 </code></pre>
1240  * @param {String} input The unparsed date as a string
1241  * @param {String} format The format the date is in
1242  * @return {Date} The parsed date
1243  * @static
1244  */
1245 Date.parseDate = function(input, format) {
1246     if (Date.parseFunctions[format] == null) {
1247         Date.createParser(format);
1248     }
1249     var func = Date.parseFunctions[format];
1250     return Date[func](input);
1251 };
1252 /**
1253  * @private
1254  */
1255
1256 Date.createParser = function(format) {
1257     var funcName = "parse" + Date.parseFunctions.count++;
1258     var regexNum = Date.parseRegexes.length;
1259     var currentGroup = 1;
1260     Date.parseFunctions[format] = funcName;
1261
1262     var code = "Date." + funcName + " = function(input){\n"
1263         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1264         + "var d = new Date();\n"
1265         + "y = d.getFullYear();\n"
1266         + "m = d.getMonth();\n"
1267         + "d = d.getDate();\n"
1268         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1269         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1270         + "if (results && results.length > 0) {";
1271     var regex = "";
1272
1273     var special = false;
1274     var ch = '';
1275     for (var i = 0; i < format.length; ++i) {
1276         ch = format.charAt(i);
1277         if (!special && ch == "\\") {
1278             special = true;
1279         }
1280         else if (special) {
1281             special = false;
1282             regex += String.escape(ch);
1283         }
1284         else {
1285             var obj = Date.formatCodeToRegex(ch, currentGroup);
1286             currentGroup += obj.g;
1287             regex += obj.s;
1288             if (obj.g && obj.c) {
1289                 code += obj.c;
1290             }
1291         }
1292     }
1293
1294     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1295         + "{v = new Date(y, m, d, h, i, s);}\n"
1296         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1297         + "{v = new Date(y, m, d, h, i);}\n"
1298         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1299         + "{v = new Date(y, m, d, h);}\n"
1300         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1301         + "{v = new Date(y, m, d);}\n"
1302         + "else if (y >= 0 && m >= 0)\n"
1303         + "{v = new Date(y, m);}\n"
1304         + "else if (y >= 0)\n"
1305         + "{v = new Date(y);}\n"
1306         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1307         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1308         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1309         + ";}";
1310
1311     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1312     /** eval:var:zzzzzzzzzzzzz */
1313     eval(code);
1314 };
1315
1316 // private
1317 Date.formatCodeToRegex = function(character, currentGroup) {
1318     switch (character) {
1319     case "D":
1320         return {g:0,
1321         c:null,
1322         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1323     case "j":
1324         return {g:1,
1325             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1326             s:"(\\d{1,2})"}; // day of month without leading zeroes
1327     case "d":
1328         return {g:1,
1329             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1330             s:"(\\d{2})"}; // day of month with leading zeroes
1331     case "l":
1332         return {g:0,
1333             c:null,
1334             s:"(?:" + Date.dayNames.join("|") + ")"};
1335     case "S":
1336         return {g:0,
1337             c:null,
1338             s:"(?:st|nd|rd|th)"};
1339     case "w":
1340         return {g:0,
1341             c:null,
1342             s:"\\d"};
1343     case "z":
1344         return {g:0,
1345             c:null,
1346             s:"(?:\\d{1,3})"};
1347     case "W":
1348         return {g:0,
1349             c:null,
1350             s:"(?:\\d{2})"};
1351     case "F":
1352         return {g:1,
1353             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1354             s:"(" + Date.monthNames.join("|") + ")"};
1355     case "M":
1356         return {g:1,
1357             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1358             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1359     case "n":
1360         return {g:1,
1361             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1362             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1363     case "m":
1364         return {g:1,
1365             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1366             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1367     case "t":
1368         return {g:0,
1369             c:null,
1370             s:"\\d{1,2}"};
1371     case "L":
1372         return {g:0,
1373             c:null,
1374             s:"(?:1|0)"};
1375     case "Y":
1376         return {g:1,
1377             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1378             s:"(\\d{4})"};
1379     case "y":
1380         return {g:1,
1381             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1382                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1383             s:"(\\d{1,2})"};
1384     case "a":
1385         return {g:1,
1386             c:"if (results[" + currentGroup + "] == 'am') {\n"
1387                 + "if (h == 12) { h = 0; }\n"
1388                 + "} else { if (h < 12) { h += 12; }}",
1389             s:"(am|pm)"};
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 "g":
1397     case "G":
1398         return {g:1,
1399             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1400             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1401     case "h":
1402     case "H":
1403         return {g:1,
1404             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1405             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1406     case "i":
1407         return {g:1,
1408             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1409             s:"(\\d{2})"};
1410     case "s":
1411         return {g:1,
1412             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1413             s:"(\\d{2})"};
1414     case "O":
1415         return {g:1,
1416             c:[
1417                 "o = results[", currentGroup, "];\n",
1418                 "var sn = o.substring(0,1);\n", // get + / - sign
1419                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1420                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1421                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1422                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1423             ].join(""),
1424             s:"([+\-]\\d{2,4})"};
1425     
1426     
1427     case "P":
1428         return {g:1,
1429                 c:[
1430                    "o = results[", currentGroup, "];\n",
1431                    "var sn = o.substring(0,1);\n",
1432                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1433                    "var mn = o.substring(4,6) % 60;\n",
1434                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1435                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1436             ].join(""),
1437             s:"([+\-]\\d{4})"};
1438     case "T":
1439         return {g:0,
1440             c:null,
1441             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1442     case "Z":
1443         return {g:1,
1444             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1445                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1446             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1447     default:
1448         return {g:0,
1449             c:null,
1450             s:String.escape(character)};
1451     }
1452 };
1453
1454 /**
1455  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1456  * @return {String} The abbreviated timezone name (e.g. 'CST')
1457  */
1458 Date.prototype.getTimezone = function() {
1459     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1460 };
1461
1462 /**
1463  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1464  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1465  */
1466 Date.prototype.getGMTOffset = function() {
1467     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1468         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1470 };
1471
1472 /**
1473  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1474  * @return {String} 2-characters representing hours and 2-characters representing minutes
1475  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1476  */
1477 Date.prototype.getGMTColonOffset = function() {
1478         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1479                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1480                 + ":"
1481                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1482 }
1483
1484 /**
1485  * Get the numeric day number of the year, adjusted for leap year.
1486  * @return {Number} 0 through 364 (365 in leap years)
1487  */
1488 Date.prototype.getDayOfYear = function() {
1489     var num = 0;
1490     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1491     for (var i = 0; i < this.getMonth(); ++i) {
1492         num += Date.daysInMonth[i];
1493     }
1494     return num + this.getDate() - 1;
1495 };
1496
1497 /**
1498  * Get the string representation of the numeric week number of the year
1499  * (equivalent to the format specifier 'W').
1500  * @return {String} '00' through '52'
1501  */
1502 Date.prototype.getWeekOfYear = function() {
1503     // Skip to Thursday of this week
1504     var now = this.getDayOfYear() + (4 - this.getDay());
1505     // Find the first Thursday of the year
1506     var jan1 = new Date(this.getFullYear(), 0, 1);
1507     var then = (7 - jan1.getDay() + 4);
1508     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1509 };
1510
1511 /**
1512  * Whether or not the current date is in a leap year.
1513  * @return {Boolean} True if the current date is in a leap year, else false
1514  */
1515 Date.prototype.isLeapYear = function() {
1516     var year = this.getFullYear();
1517     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1518 };
1519
1520 /**
1521  * Get the first day of the current month, adjusted for leap year.  The returned value
1522  * is the numeric day index within the week (0-6) which can be used in conjunction with
1523  * the {@link #monthNames} array to retrieve the textual day name.
1524  * Example:
1525  *<pre><code>
1526 var dt = new Date('1/10/2007');
1527 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1528 </code></pre>
1529  * @return {Number} The day number (0-6)
1530  */
1531 Date.prototype.getFirstDayOfMonth = function() {
1532     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1533     return (day < 0) ? (day + 7) : day;
1534 };
1535
1536 /**
1537  * Get the last day of the current month, adjusted for leap year.  The returned value
1538  * is the numeric day index within the week (0-6) which can be used in conjunction with
1539  * the {@link #monthNames} array to retrieve the textual day name.
1540  * Example:
1541  *<pre><code>
1542 var dt = new Date('1/10/2007');
1543 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1544 </code></pre>
1545  * @return {Number} The day number (0-6)
1546  */
1547 Date.prototype.getLastDayOfMonth = function() {
1548     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1549     return (day < 0) ? (day + 7) : day;
1550 };
1551
1552
1553 /**
1554  * Get the first date of this date's month
1555  * @return {Date}
1556  */
1557 Date.prototype.getFirstDateOfMonth = function() {
1558     return new Date(this.getFullYear(), this.getMonth(), 1);
1559 };
1560
1561 /**
1562  * Get the last date of this date's month
1563  * @return {Date}
1564  */
1565 Date.prototype.getLastDateOfMonth = function() {
1566     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1567 };
1568 /**
1569  * Get the number of days in the current month, adjusted for leap year.
1570  * @return {Number} The number of days in the month
1571  */
1572 Date.prototype.getDaysInMonth = function() {
1573     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1574     return Date.daysInMonth[this.getMonth()];
1575 };
1576
1577 /**
1578  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1579  * @return {String} 'st, 'nd', 'rd' or 'th'
1580  */
1581 Date.prototype.getSuffix = function() {
1582     switch (this.getDate()) {
1583         case 1:
1584         case 21:
1585         case 31:
1586             return "st";
1587         case 2:
1588         case 22:
1589             return "nd";
1590         case 3:
1591         case 23:
1592             return "rd";
1593         default:
1594             return "th";
1595     }
1596 };
1597
1598 // private
1599 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1600
1601 /**
1602  * An array of textual month names.
1603  * Override these values for international dates, for example...
1604  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1605  * @type Array
1606  * @static
1607  */
1608 Date.monthNames =
1609    ["January",
1610     "February",
1611     "March",
1612     "April",
1613     "May",
1614     "June",
1615     "July",
1616     "August",
1617     "September",
1618     "October",
1619     "November",
1620     "December"];
1621
1622 /**
1623  * An array of textual day names.
1624  * Override these values for international dates, for example...
1625  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1626  * @type Array
1627  * @static
1628  */
1629 Date.dayNames =
1630    ["Sunday",
1631     "Monday",
1632     "Tuesday",
1633     "Wednesday",
1634     "Thursday",
1635     "Friday",
1636     "Saturday"];
1637
1638 // private
1639 Date.y2kYear = 50;
1640 // private
1641 Date.monthNumbers = {
1642     Jan:0,
1643     Feb:1,
1644     Mar:2,
1645     Apr:3,
1646     May:4,
1647     Jun:5,
1648     Jul:6,
1649     Aug:7,
1650     Sep:8,
1651     Oct:9,
1652     Nov:10,
1653     Dec:11};
1654
1655 /**
1656  * Creates and returns a new Date instance with the exact same date value as the called instance.
1657  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1658  * variable will also be changed.  When the intention is to create a new variable that will not
1659  * modify the original instance, you should create a clone.
1660  *
1661  * Example of correctly cloning a date:
1662  * <pre><code>
1663 //wrong way:
1664 var orig = new Date('10/1/2006');
1665 var copy = orig;
1666 copy.setDate(5);
1667 document.write(orig);  //returns 'Thu Oct 05 2006'!
1668
1669 //correct way:
1670 var orig = new Date('10/1/2006');
1671 var copy = orig.clone();
1672 copy.setDate(5);
1673 document.write(orig);  //returns 'Thu Oct 01 2006'
1674 </code></pre>
1675  * @return {Date} The new Date instance
1676  */
1677 Date.prototype.clone = function() {
1678         return new Date(this.getTime());
1679 };
1680
1681 /**
1682  * Clears any time information from this date
1683  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1684  @return {Date} this or the clone
1685  */
1686 Date.prototype.clearTime = function(clone){
1687     if(clone){
1688         return this.clone().clearTime();
1689     }
1690     this.setHours(0);
1691     this.setMinutes(0);
1692     this.setSeconds(0);
1693     this.setMilliseconds(0);
1694     return this;
1695 };
1696
1697 // private
1698 // safari setMonth is broken -- check that this is only donw once...
1699 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1700     Date.brokenSetMonth = Date.prototype.setMonth;
1701         Date.prototype.setMonth = function(num){
1702                 if(num <= -1){
1703                         var n = Math.ceil(-num);
1704                         var back_year = Math.ceil(n/12);
1705                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1706                         this.setFullYear(this.getFullYear() - back_year);
1707                         return Date.brokenSetMonth.call(this, month);
1708                 } else {
1709                         return Date.brokenSetMonth.apply(this, arguments);
1710                 }
1711         };
1712 }
1713
1714 /** Date interval constant 
1715 * @static 
1716 * @type String */
1717 Date.MILLI = "ms";
1718 /** Date interval constant 
1719 * @static 
1720 * @type String */
1721 Date.SECOND = "s";
1722 /** Date interval constant 
1723 * @static 
1724 * @type String */
1725 Date.MINUTE = "mi";
1726 /** Date interval constant 
1727 * @static 
1728 * @type String */
1729 Date.HOUR = "h";
1730 /** Date interval constant 
1731 * @static 
1732 * @type String */
1733 Date.DAY = "d";
1734 /** Date interval constant 
1735 * @static 
1736 * @type String */
1737 Date.MONTH = "mo";
1738 /** Date interval constant 
1739 * @static 
1740 * @type String */
1741 Date.YEAR = "y";
1742
1743 /**
1744  * Provides a convenient method of performing basic date arithmetic.  This method
1745  * does not modify the Date instance being called - it creates and returns
1746  * a new Date instance containing the resulting date value.
1747  *
1748  * Examples:
1749  * <pre><code>
1750 //Basic usage:
1751 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1752 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1753
1754 //Negative values will subtract correctly:
1755 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1756 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1757
1758 //You can even chain several calls together in one line!
1759 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1760 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1761  </code></pre>
1762  *
1763  * @param {String} interval   A valid date interval enum value
1764  * @param {Number} value      The amount to add to the current date
1765  * @return {Date} The new Date instance
1766  */
1767 Date.prototype.add = function(interval, value){
1768   var d = this.clone();
1769   if (!interval || value === 0) { return d; }
1770   switch(interval.toLowerCase()){
1771     case Date.MILLI:
1772       d.setMilliseconds(this.getMilliseconds() + value);
1773       break;
1774     case Date.SECOND:
1775       d.setSeconds(this.getSeconds() + value);
1776       break;
1777     case Date.MINUTE:
1778       d.setMinutes(this.getMinutes() + value);
1779       break;
1780     case Date.HOUR:
1781       d.setHours(this.getHours() + value);
1782       break;
1783     case Date.DAY:
1784       d.setDate(this.getDate() + value);
1785       break;
1786     case Date.MONTH:
1787       var day = this.getDate();
1788       if(day > 28){
1789           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1790       }
1791       d.setDate(day);
1792       d.setMonth(this.getMonth() + value);
1793       break;
1794     case Date.YEAR:
1795       d.setFullYear(this.getFullYear() + value);
1796       break;
1797   }
1798   return d;
1799 };
1800 /*
1801  * Based on:
1802  * Ext JS Library 1.1.1
1803  * Copyright(c) 2006-2007, Ext JS, LLC.
1804  *
1805  * Originally Released Under LGPL - original licence link has changed is not relivant.
1806  *
1807  * Fork - LGPL
1808  * <script type="text/javascript">
1809  */
1810
1811 /**
1812  * @class Roo.lib.Dom
1813  * @static
1814  * 
1815  * Dom utils (from YIU afaik)
1816  * 
1817  **/
1818 Roo.lib.Dom = {
1819     /**
1820      * Get the view width
1821      * @param {Boolean} full True will get the full document, otherwise it's the view width
1822      * @return {Number} The width
1823      */
1824      
1825     getViewWidth : function(full) {
1826         return full ? this.getDocumentWidth() : this.getViewportWidth();
1827     },
1828     /**
1829      * Get the view height
1830      * @param {Boolean} full True will get the full document, otherwise it's the view height
1831      * @return {Number} The height
1832      */
1833     getViewHeight : function(full) {
1834         return full ? this.getDocumentHeight() : this.getViewportHeight();
1835     },
1836
1837     getDocumentHeight: function() {
1838         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1839         return Math.max(scrollHeight, this.getViewportHeight());
1840     },
1841
1842     getDocumentWidth: function() {
1843         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1844         return Math.max(scrollWidth, this.getViewportWidth());
1845     },
1846
1847     getViewportHeight: function() {
1848         var height = self.innerHeight;
1849         var mode = document.compatMode;
1850
1851         if ((mode || Roo.isIE) && !Roo.isOpera) {
1852             height = (mode == "CSS1Compat") ?
1853                      document.documentElement.clientHeight :
1854                      document.body.clientHeight;
1855         }
1856
1857         return height;
1858     },
1859
1860     getViewportWidth: function() {
1861         var width = self.innerWidth;
1862         var mode = document.compatMode;
1863
1864         if (mode || Roo.isIE) {
1865             width = (mode == "CSS1Compat") ?
1866                     document.documentElement.clientWidth :
1867                     document.body.clientWidth;
1868         }
1869         return width;
1870     },
1871
1872     isAncestor : function(p, c) {
1873         p = Roo.getDom(p);
1874         c = Roo.getDom(c);
1875         if (!p || !c) {
1876             return false;
1877         }
1878
1879         if (p.contains && !Roo.isSafari) {
1880             return p.contains(c);
1881         } else if (p.compareDocumentPosition) {
1882             return !!(p.compareDocumentPosition(c) & 16);
1883         } else {
1884             var parent = c.parentNode;
1885             while (parent) {
1886                 if (parent == p) {
1887                     return true;
1888                 }
1889                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1890                     return false;
1891                 }
1892                 parent = parent.parentNode;
1893             }
1894             return false;
1895         }
1896     },
1897
1898     getRegion : function(el) {
1899         return Roo.lib.Region.getRegion(el);
1900     },
1901
1902     getY : function(el) {
1903         return this.getXY(el)[1];
1904     },
1905
1906     getX : function(el) {
1907         return this.getXY(el)[0];
1908     },
1909
1910     getXY : function(el) {
1911         var p, pe, b, scroll, bd = document.body;
1912         el = Roo.getDom(el);
1913         var fly = Roo.lib.AnimBase.fly;
1914         if (el.getBoundingClientRect) {
1915             b = el.getBoundingClientRect();
1916             scroll = fly(document).getScroll();
1917             return [b.left + scroll.left, b.top + scroll.top];
1918         }
1919         var x = 0, y = 0;
1920
1921         p = el;
1922
1923         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1924
1925         while (p) {
1926
1927             x += p.offsetLeft;
1928             y += p.offsetTop;
1929
1930             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1931                 hasAbsolute = true;
1932             }
1933
1934             if (Roo.isGecko) {
1935                 pe = fly(p);
1936
1937                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1938                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1939
1940
1941                 x += bl;
1942                 y += bt;
1943
1944
1945                 if (p != el && pe.getStyle('overflow') != 'visible') {
1946                     x += bl;
1947                     y += bt;
1948                 }
1949             }
1950             p = p.offsetParent;
1951         }
1952
1953         if (Roo.isSafari && hasAbsolute) {
1954             x -= bd.offsetLeft;
1955             y -= bd.offsetTop;
1956         }
1957
1958         if (Roo.isGecko && !hasAbsolute) {
1959             var dbd = fly(bd);
1960             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1961             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1962         }
1963
1964         p = el.parentNode;
1965         while (p && p != bd) {
1966             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1967                 x -= p.scrollLeft;
1968                 y -= p.scrollTop;
1969             }
1970             p = p.parentNode;
1971         }
1972         return [x, y];
1973     },
1974  
1975   
1976
1977
1978     setXY : function(el, xy) {
1979         el = Roo.fly(el, '_setXY');
1980         el.position();
1981         var pts = el.translatePoints(xy);
1982         if (xy[0] !== false) {
1983             el.dom.style.left = pts.left + "px";
1984         }
1985         if (xy[1] !== false) {
1986             el.dom.style.top = pts.top + "px";
1987         }
1988     },
1989
1990     setX : function(el, x) {
1991         this.setXY(el, [x, false]);
1992     },
1993
1994     setY : function(el, y) {
1995         this.setXY(el, [false, y]);
1996     }
1997 };
1998 /*
1999  * Portions of this file are based on pieces of Yahoo User Interface Library
2000  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2001  * YUI licensed under the BSD License:
2002  * http://developer.yahoo.net/yui/license.txt
2003  * <script type="text/javascript">
2004  *
2005  */
2006
2007 Roo.lib.Event = function() {
2008     var loadComplete = false;
2009     var listeners = [];
2010     var unloadListeners = [];
2011     var retryCount = 0;
2012     var onAvailStack = [];
2013     var counter = 0;
2014     var lastError = null;
2015
2016     return {
2017         POLL_RETRYS: 200,
2018         POLL_INTERVAL: 20,
2019         EL: 0,
2020         TYPE: 1,
2021         FN: 2,
2022         WFN: 3,
2023         OBJ: 3,
2024         ADJ_SCOPE: 4,
2025         _interval: null,
2026
2027         startInterval: function() {
2028             if (!this._interval) {
2029                 var self = this;
2030                 var callback = function() {
2031                     self._tryPreloadAttach();
2032                 };
2033                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2034
2035             }
2036         },
2037
2038         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2039             onAvailStack.push({ id:         p_id,
2040                 fn:         p_fn,
2041                 obj:        p_obj,
2042                 override:   p_override,
2043                 checkReady: false    });
2044
2045             retryCount = this.POLL_RETRYS;
2046             this.startInterval();
2047         },
2048
2049
2050         addListener: function(el, eventName, fn) {
2051             el = Roo.getDom(el);
2052             if (!el || !fn) {
2053                 return false;
2054             }
2055
2056             if ("unload" == eventName) {
2057                 unloadListeners[unloadListeners.length] =
2058                 [el, eventName, fn];
2059                 return true;
2060             }
2061
2062             var wrappedFn = function(e) {
2063                 return fn(Roo.lib.Event.getEvent(e));
2064             };
2065
2066             var li = [el, eventName, fn, wrappedFn];
2067
2068             var index = listeners.length;
2069             listeners[index] = li;
2070
2071             this.doAdd(el, eventName, wrappedFn, false);
2072             return true;
2073
2074         },
2075
2076
2077         removeListener: function(el, eventName, fn) {
2078             var i, len;
2079
2080             el = Roo.getDom(el);
2081
2082             if(!fn) {
2083                 return this.purgeElement(el, false, eventName);
2084             }
2085
2086
2087             if ("unload" == eventName) {
2088
2089                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2090                     var li = unloadListeners[i];
2091                     if (li &&
2092                         li[0] == el &&
2093                         li[1] == eventName &&
2094                         li[2] == fn) {
2095                         unloadListeners.splice(i, 1);
2096                         return true;
2097                     }
2098                 }
2099
2100                 return false;
2101             }
2102
2103             var cacheItem = null;
2104
2105
2106             var index = arguments[3];
2107
2108             if ("undefined" == typeof index) {
2109                 index = this._getCacheIndex(el, eventName, fn);
2110             }
2111
2112             if (index >= 0) {
2113                 cacheItem = listeners[index];
2114             }
2115
2116             if (!el || !cacheItem) {
2117                 return false;
2118             }
2119
2120             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2121
2122             delete listeners[index][this.WFN];
2123             delete listeners[index][this.FN];
2124             listeners.splice(index, 1);
2125
2126             return true;
2127
2128         },
2129
2130
2131         getTarget: function(ev, resolveTextNode) {
2132             ev = ev.browserEvent || ev;
2133             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2134             var t = ev.target || ev.srcElement;
2135             return this.resolveTextNode(t);
2136         },
2137
2138
2139         resolveTextNode: function(node) {
2140             if (Roo.isSafari && node && 3 == node.nodeType) {
2141                 return node.parentNode;
2142             } else {
2143                 return node;
2144             }
2145         },
2146
2147
2148         getPageX: function(ev) {
2149             ev = ev.browserEvent || ev;
2150             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2151             var x = ev.pageX;
2152             if (!x && 0 !== x) {
2153                 x = ev.clientX || 0;
2154
2155                 if (Roo.isIE) {
2156                     x += this.getScroll()[1];
2157                 }
2158             }
2159
2160             return x;
2161         },
2162
2163
2164         getPageY: function(ev) {
2165             ev = ev.browserEvent || ev;
2166             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2167             var y = ev.pageY;
2168             if (!y && 0 !== y) {
2169                 y = ev.clientY || 0;
2170
2171                 if (Roo.isIE) {
2172                     y += this.getScroll()[0];
2173                 }
2174             }
2175
2176
2177             return y;
2178         },
2179
2180
2181         getXY: function(ev) {
2182             ev = ev.browserEvent || ev;
2183             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2184             return [this.getPageX(ev), this.getPageY(ev)];
2185         },
2186
2187
2188         getRelatedTarget: function(ev) {
2189             ev = ev.browserEvent || ev;
2190             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2191             var t = ev.relatedTarget;
2192             if (!t) {
2193                 if (ev.type == "mouseout") {
2194                     t = ev.toElement;
2195                 } else if (ev.type == "mouseover") {
2196                     t = ev.fromElement;
2197                 }
2198             }
2199
2200             return this.resolveTextNode(t);
2201         },
2202
2203
2204         getTime: function(ev) {
2205             ev = ev.browserEvent || ev;
2206             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2207             if (!ev.time) {
2208                 var t = new Date().getTime();
2209                 try {
2210                     ev.time = t;
2211                 } catch(ex) {
2212                     this.lastError = ex;
2213                     return t;
2214                 }
2215             }
2216
2217             return ev.time;
2218         },
2219
2220
2221         stopEvent: function(ev) {
2222             this.stopPropagation(ev);
2223             this.preventDefault(ev);
2224         },
2225
2226
2227         stopPropagation: function(ev) {
2228             ev = ev.browserEvent || ev;
2229             if (ev.stopPropagation) {
2230                 ev.stopPropagation();
2231             } else {
2232                 ev.cancelBubble = true;
2233             }
2234         },
2235
2236
2237         preventDefault: function(ev) {
2238             ev = ev.browserEvent || ev;
2239             if(ev.preventDefault) {
2240                 ev.preventDefault();
2241             } else {
2242                 ev.returnValue = false;
2243             }
2244         },
2245
2246
2247         getEvent: function(e) {
2248             var ev = e || window.event;
2249             if (!ev) {
2250                 var c = this.getEvent.caller;
2251                 while (c) {
2252                     ev = c.arguments[0];
2253                     if (ev && Event == ev.constructor) {
2254                         break;
2255                     }
2256                     c = c.caller;
2257                 }
2258             }
2259             return ev;
2260         },
2261
2262
2263         getCharCode: function(ev) {
2264             ev = ev.browserEvent || ev;
2265             return ev.charCode || ev.keyCode || 0;
2266         },
2267
2268
2269         _getCacheIndex: function(el, eventName, fn) {
2270             for (var i = 0,len = listeners.length; i < len; ++i) {
2271                 var li = listeners[i];
2272                 if (li &&
2273                     li[this.FN] == fn &&
2274                     li[this.EL] == el &&
2275                     li[this.TYPE] == eventName) {
2276                     return i;
2277                 }
2278             }
2279
2280             return -1;
2281         },
2282
2283
2284         elCache: {},
2285
2286
2287         getEl: function(id) {
2288             return document.getElementById(id);
2289         },
2290
2291
2292         clearCache: function() {
2293         },
2294
2295
2296         _load: function(e) {
2297             loadComplete = true;
2298             var EU = Roo.lib.Event;
2299
2300
2301             if (Roo.isIE) {
2302                 EU.doRemove(window, "load", EU._load);
2303             }
2304         },
2305
2306
2307         _tryPreloadAttach: function() {
2308
2309             if (this.locked) {
2310                 return false;
2311             }
2312
2313             this.locked = true;
2314
2315
2316             var tryAgain = !loadComplete;
2317             if (!tryAgain) {
2318                 tryAgain = (retryCount > 0);
2319             }
2320
2321
2322             var notAvail = [];
2323             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2324                 var item = onAvailStack[i];
2325                 if (item) {
2326                     var el = this.getEl(item.id);
2327
2328                     if (el) {
2329                         if (!item.checkReady ||
2330                             loadComplete ||
2331                             el.nextSibling ||
2332                             (document && document.body)) {
2333
2334                             var scope = el;
2335                             if (item.override) {
2336                                 if (item.override === true) {
2337                                     scope = item.obj;
2338                                 } else {
2339                                     scope = item.override;
2340                                 }
2341                             }
2342                             item.fn.call(scope, item.obj);
2343                             onAvailStack[i] = null;
2344                         }
2345                     } else {
2346                         notAvail.push(item);
2347                     }
2348                 }
2349             }
2350
2351             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2352
2353             if (tryAgain) {
2354
2355                 this.startInterval();
2356             } else {
2357                 clearInterval(this._interval);
2358                 this._interval = null;
2359             }
2360
2361             this.locked = false;
2362
2363             return true;
2364
2365         },
2366
2367
2368         purgeElement: function(el, recurse, eventName) {
2369             var elListeners = this.getListeners(el, eventName);
2370             if (elListeners) {
2371                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2372                     var l = elListeners[i];
2373                     this.removeListener(el, l.type, l.fn);
2374                 }
2375             }
2376
2377             if (recurse && el && el.childNodes) {
2378                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2379                     this.purgeElement(el.childNodes[i], recurse, eventName);
2380                 }
2381             }
2382         },
2383
2384
2385         getListeners: function(el, eventName) {
2386             var results = [], searchLists;
2387             if (!eventName) {
2388                 searchLists = [listeners, unloadListeners];
2389             } else if (eventName == "unload") {
2390                 searchLists = [unloadListeners];
2391             } else {
2392                 searchLists = [listeners];
2393             }
2394
2395             for (var j = 0; j < searchLists.length; ++j) {
2396                 var searchList = searchLists[j];
2397                 if (searchList && searchList.length > 0) {
2398                     for (var i = 0,len = searchList.length; i < len; ++i) {
2399                         var l = searchList[i];
2400                         if (l && l[this.EL] === el &&
2401                             (!eventName || eventName === l[this.TYPE])) {
2402                             results.push({
2403                                 type:   l[this.TYPE],
2404                                 fn:     l[this.FN],
2405                                 obj:    l[this.OBJ],
2406                                 adjust: l[this.ADJ_SCOPE],
2407                                 index:  i
2408                             });
2409                         }
2410                     }
2411                 }
2412             }
2413
2414             return (results.length) ? results : null;
2415         },
2416
2417
2418         _unload: function(e) {
2419
2420             var EU = Roo.lib.Event, i, j, l, len, index;
2421
2422             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2423                 l = unloadListeners[i];
2424                 if (l) {
2425                     var scope = window;
2426                     if (l[EU.ADJ_SCOPE]) {
2427                         if (l[EU.ADJ_SCOPE] === true) {
2428                             scope = l[EU.OBJ];
2429                         } else {
2430                             scope = l[EU.ADJ_SCOPE];
2431                         }
2432                     }
2433                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2434                     unloadListeners[i] = null;
2435                     l = null;
2436                     scope = null;
2437                 }
2438             }
2439
2440             unloadListeners = null;
2441
2442             if (listeners && listeners.length > 0) {
2443                 j = listeners.length;
2444                 while (j) {
2445                     index = j - 1;
2446                     l = listeners[index];
2447                     if (l) {
2448                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2449                                 l[EU.FN], index);
2450                     }
2451                     j = j - 1;
2452                 }
2453                 l = null;
2454
2455                 EU.clearCache();
2456             }
2457
2458             EU.doRemove(window, "unload", EU._unload);
2459
2460         },
2461
2462
2463         getScroll: function() {
2464             var dd = document.documentElement, db = document.body;
2465             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2466                 return [dd.scrollTop, dd.scrollLeft];
2467             } else if (db) {
2468                 return [db.scrollTop, db.scrollLeft];
2469             } else {
2470                 return [0, 0];
2471             }
2472         },
2473
2474
2475         doAdd: function () {
2476             if (window.addEventListener) {
2477                 return function(el, eventName, fn, capture) {
2478                     el.addEventListener(eventName, fn, (capture));
2479                 };
2480             } else if (window.attachEvent) {
2481                 return function(el, eventName, fn, capture) {
2482                     el.attachEvent("on" + eventName, fn);
2483                 };
2484             } else {
2485                 return function() {
2486                 };
2487             }
2488         }(),
2489
2490
2491         doRemove: function() {
2492             if (window.removeEventListener) {
2493                 return function (el, eventName, fn, capture) {
2494                     el.removeEventListener(eventName, fn, (capture));
2495                 };
2496             } else if (window.detachEvent) {
2497                 return function (el, eventName, fn) {
2498                     el.detachEvent("on" + eventName, fn);
2499                 };
2500             } else {
2501                 return function() {
2502                 };
2503             }
2504         }()
2505     };
2506     
2507 }();
2508 (function() {     
2509    
2510     var E = Roo.lib.Event;
2511     E.on = E.addListener;
2512     E.un = E.removeListener;
2513
2514     if (document && document.body) {
2515         E._load();
2516     } else {
2517         E.doAdd(window, "load", E._load);
2518     }
2519     E.doAdd(window, "unload", E._unload);
2520     E._tryPreloadAttach();
2521 })();
2522
2523 /*
2524  * Portions of this file are based on pieces of Yahoo User Interface Library
2525  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2526  * YUI licensed under the BSD License:
2527  * http://developer.yahoo.net/yui/license.txt
2528  * <script type="text/javascript">
2529  *
2530  */
2531
2532 (function() {
2533     /**
2534      * @class Roo.lib.Ajax
2535      *
2536      */
2537     Roo.lib.Ajax = {
2538         /**
2539          * @static 
2540          */
2541         request : function(method, uri, cb, data, options) {
2542             if(options){
2543                 var hs = options.headers;
2544                 if(hs){
2545                     for(var h in hs){
2546                         if(hs.hasOwnProperty(h)){
2547                             this.initHeader(h, hs[h], false);
2548                         }
2549                     }
2550                 }
2551                 if(options.xmlData){
2552                     this.initHeader('Content-Type', 'text/xml', false);
2553                     method = 'POST';
2554                     data = options.xmlData;
2555                 }
2556             }
2557
2558             return this.asyncRequest(method, uri, cb, data);
2559         },
2560
2561         serializeForm : function(form) {
2562             if(typeof form == 'string') {
2563                 form = (document.getElementById(form) || document.forms[form]);
2564             }
2565
2566             var el, name, val, disabled, data = '', hasSubmit = false;
2567             for (var i = 0; i < form.elements.length; i++) {
2568                 el = form.elements[i];
2569                 disabled = form.elements[i].disabled;
2570                 name = form.elements[i].name;
2571                 val = form.elements[i].value;
2572
2573                 if (!disabled && name){
2574                     switch (el.type)
2575                             {
2576                         case 'select-one':
2577                         case 'select-multiple':
2578                             for (var j = 0; j < el.options.length; j++) {
2579                                 if (el.options[j].selected) {
2580                                     if (Roo.isIE) {
2581                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2582                                     }
2583                                     else {
2584                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2585                                     }
2586                                 }
2587                             }
2588                             break;
2589                         case 'radio':
2590                         case 'checkbox':
2591                             if (el.checked) {
2592                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2593                             }
2594                             break;
2595                         case 'file':
2596
2597                         case undefined:
2598
2599                         case 'reset':
2600
2601                         case 'button':
2602
2603                             break;
2604                         case 'submit':
2605                             if(hasSubmit == false) {
2606                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2607                                 hasSubmit = true;
2608                             }
2609                             break;
2610                         default:
2611                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2612                             break;
2613                     }
2614                 }
2615             }
2616             data = data.substr(0, data.length - 1);
2617             return data;
2618         },
2619
2620         headers:{},
2621
2622         hasHeaders:false,
2623
2624         useDefaultHeader:true,
2625
2626         defaultPostHeader:'application/x-www-form-urlencoded',
2627
2628         useDefaultXhrHeader:true,
2629
2630         defaultXhrHeader:'XMLHttpRequest',
2631
2632         hasDefaultHeaders:true,
2633
2634         defaultHeaders:{},
2635
2636         poll:{},
2637
2638         timeout:{},
2639
2640         pollInterval:50,
2641
2642         transactionId:0,
2643
2644         setProgId:function(id)
2645         {
2646             this.activeX.unshift(id);
2647         },
2648
2649         setDefaultPostHeader:function(b)
2650         {
2651             this.useDefaultHeader = b;
2652         },
2653
2654         setDefaultXhrHeader:function(b)
2655         {
2656             this.useDefaultXhrHeader = b;
2657         },
2658
2659         setPollingInterval:function(i)
2660         {
2661             if (typeof i == 'number' && isFinite(i)) {
2662                 this.pollInterval = i;
2663             }
2664         },
2665
2666         createXhrObject:function(transactionId)
2667         {
2668             var obj,http;
2669             try
2670             {
2671
2672                 http = new XMLHttpRequest();
2673
2674                 obj = { conn:http, tId:transactionId };
2675             }
2676             catch(e)
2677             {
2678                 for (var i = 0; i < this.activeX.length; ++i) {
2679                     try
2680                     {
2681
2682                         http = new ActiveXObject(this.activeX[i]);
2683
2684                         obj = { conn:http, tId:transactionId };
2685                         break;
2686                     }
2687                     catch(e) {
2688                     }
2689                 }
2690             }
2691             finally
2692             {
2693                 return obj;
2694             }
2695         },
2696
2697         getConnectionObject:function()
2698         {
2699             var o;
2700             var tId = this.transactionId;
2701
2702             try
2703             {
2704                 o = this.createXhrObject(tId);
2705                 if (o) {
2706                     this.transactionId++;
2707                 }
2708             }
2709             catch(e) {
2710             }
2711             finally
2712             {
2713                 return o;
2714             }
2715         },
2716
2717         asyncRequest:function(method, uri, callback, postData)
2718         {
2719             var o = this.getConnectionObject();
2720
2721             if (!o) {
2722                 return null;
2723             }
2724             else {
2725                 o.conn.open(method, uri, true);
2726
2727                 if (this.useDefaultXhrHeader) {
2728                     if (!this.defaultHeaders['X-Requested-With']) {
2729                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2730                     }
2731                 }
2732
2733                 if(postData && this.useDefaultHeader){
2734                     this.initHeader('Content-Type', this.defaultPostHeader);
2735                 }
2736
2737                  if (this.hasDefaultHeaders || this.hasHeaders) {
2738                     this.setHeader(o);
2739                 }
2740
2741                 this.handleReadyState(o, callback);
2742                 o.conn.send(postData || null);
2743
2744                 return o;
2745             }
2746         },
2747
2748         handleReadyState:function(o, callback)
2749         {
2750             var oConn = this;
2751
2752             if (callback && callback.timeout) {
2753                 
2754                 this.timeout[o.tId] = window.setTimeout(function() {
2755                     oConn.abort(o, callback, true);
2756                 }, callback.timeout);
2757             }
2758
2759             this.poll[o.tId] = window.setInterval(
2760                     function() {
2761                         if (o.conn && o.conn.readyState == 4) {
2762                             window.clearInterval(oConn.poll[o.tId]);
2763                             delete oConn.poll[o.tId];
2764
2765                             if(callback && callback.timeout) {
2766                                 window.clearTimeout(oConn.timeout[o.tId]);
2767                                 delete oConn.timeout[o.tId];
2768                             }
2769
2770                             oConn.handleTransactionResponse(o, callback);
2771                         }
2772                     }
2773                     , this.pollInterval);
2774         },
2775
2776         handleTransactionResponse:function(o, callback, isAbort)
2777         {
2778
2779             if (!callback) {
2780                 this.releaseObject(o);
2781                 return;
2782             }
2783
2784             var httpStatus, responseObject;
2785
2786             try
2787             {
2788                 if (o.conn.status !== undefined && o.conn.status != 0) {
2789                     httpStatus = o.conn.status;
2790                 }
2791                 else {
2792                     httpStatus = 13030;
2793                 }
2794             }
2795             catch(e) {
2796
2797
2798                 httpStatus = 13030;
2799             }
2800
2801             if (httpStatus >= 200 && httpStatus < 300) {
2802                 responseObject = this.createResponseObject(o, callback.argument);
2803                 if (callback.success) {
2804                     if (!callback.scope) {
2805                         callback.success(responseObject);
2806                     }
2807                     else {
2808
2809
2810                         callback.success.apply(callback.scope, [responseObject]);
2811                     }
2812                 }
2813             }
2814             else {
2815                 switch (httpStatus) {
2816
2817                     case 12002:
2818                     case 12029:
2819                     case 12030:
2820                     case 12031:
2821                     case 12152:
2822                     case 13030:
2823                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2824                         if (callback.failure) {
2825                             if (!callback.scope) {
2826                                 callback.failure(responseObject);
2827                             }
2828                             else {
2829                                 callback.failure.apply(callback.scope, [responseObject]);
2830                             }
2831                         }
2832                         break;
2833                     default:
2834                         responseObject = this.createResponseObject(o, callback.argument);
2835                         if (callback.failure) {
2836                             if (!callback.scope) {
2837                                 callback.failure(responseObject);
2838                             }
2839                             else {
2840                                 callback.failure.apply(callback.scope, [responseObject]);
2841                             }
2842                         }
2843                 }
2844             }
2845
2846             this.releaseObject(o);
2847             responseObject = null;
2848         },
2849
2850         createResponseObject:function(o, callbackArg)
2851         {
2852             var obj = {};
2853             var headerObj = {};
2854
2855             try
2856             {
2857                 var headerStr = o.conn.getAllResponseHeaders();
2858                 var header = headerStr.split('\n');
2859                 for (var i = 0; i < header.length; i++) {
2860                     var delimitPos = header[i].indexOf(':');
2861                     if (delimitPos != -1) {
2862                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2863                     }
2864                 }
2865             }
2866             catch(e) {
2867             }
2868
2869             obj.tId = o.tId;
2870             obj.status = o.conn.status;
2871             obj.statusText = o.conn.statusText;
2872             obj.getResponseHeader = headerObj;
2873             obj.getAllResponseHeaders = headerStr;
2874             obj.responseText = o.conn.responseText;
2875             obj.responseXML = o.conn.responseXML;
2876
2877             if (typeof callbackArg !== undefined) {
2878                 obj.argument = callbackArg;
2879             }
2880
2881             return obj;
2882         },
2883
2884         createExceptionObject:function(tId, callbackArg, isAbort)
2885         {
2886             var COMM_CODE = 0;
2887             var COMM_ERROR = 'communication failure';
2888             var ABORT_CODE = -1;
2889             var ABORT_ERROR = 'transaction aborted';
2890
2891             var obj = {};
2892
2893             obj.tId = tId;
2894             if (isAbort) {
2895                 obj.status = ABORT_CODE;
2896                 obj.statusText = ABORT_ERROR;
2897             }
2898             else {
2899                 obj.status = COMM_CODE;
2900                 obj.statusText = COMM_ERROR;
2901             }
2902
2903             if (callbackArg) {
2904                 obj.argument = callbackArg;
2905             }
2906
2907             return obj;
2908         },
2909
2910         initHeader:function(label, value, isDefault)
2911         {
2912             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2913
2914             if (headerObj[label] === undefined) {
2915                 headerObj[label] = value;
2916             }
2917             else {
2918
2919
2920                 headerObj[label] = value + "," + headerObj[label];
2921             }
2922
2923             if (isDefault) {
2924                 this.hasDefaultHeaders = true;
2925             }
2926             else {
2927                 this.hasHeaders = true;
2928             }
2929         },
2930
2931
2932         setHeader:function(o)
2933         {
2934             if (this.hasDefaultHeaders) {
2935                 for (var prop in this.defaultHeaders) {
2936                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2937                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2938                     }
2939                 }
2940             }
2941
2942             if (this.hasHeaders) {
2943                 for (var prop in this.headers) {
2944                     if (this.headers.hasOwnProperty(prop)) {
2945                         o.conn.setRequestHeader(prop, this.headers[prop]);
2946                     }
2947                 }
2948                 this.headers = {};
2949                 this.hasHeaders = false;
2950             }
2951         },
2952
2953         resetDefaultHeaders:function() {
2954             delete this.defaultHeaders;
2955             this.defaultHeaders = {};
2956             this.hasDefaultHeaders = false;
2957         },
2958
2959         abort:function(o, callback, isTimeout)
2960         {
2961             if(this.isCallInProgress(o)) {
2962                 o.conn.abort();
2963                 window.clearInterval(this.poll[o.tId]);
2964                 delete this.poll[o.tId];
2965                 if (isTimeout) {
2966                     delete this.timeout[o.tId];
2967                 }
2968
2969                 this.handleTransactionResponse(o, callback, true);
2970
2971                 return true;
2972             }
2973             else {
2974                 return false;
2975             }
2976         },
2977
2978
2979         isCallInProgress:function(o)
2980         {
2981             if (o && o.conn) {
2982                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2983             }
2984             else {
2985
2986                 return false;
2987             }
2988         },
2989
2990
2991         releaseObject:function(o)
2992         {
2993
2994             o.conn = null;
2995
2996             o = null;
2997         },
2998
2999         activeX:[
3000         'MSXML2.XMLHTTP.3.0',
3001         'MSXML2.XMLHTTP',
3002         'Microsoft.XMLHTTP'
3003         ]
3004
3005
3006     };
3007 })();/*
3008  * Portions of this file are based on pieces of Yahoo User Interface Library
3009  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3010  * YUI licensed under the BSD License:
3011  * http://developer.yahoo.net/yui/license.txt
3012  * <script type="text/javascript">
3013  *
3014  */
3015
3016 Roo.lib.Region = function(t, r, b, l) {
3017     this.top = t;
3018     this[1] = t;
3019     this.right = r;
3020     this.bottom = b;
3021     this.left = l;
3022     this[0] = l;
3023 };
3024
3025
3026 Roo.lib.Region.prototype = {
3027     contains : function(region) {
3028         return ( region.left >= this.left &&
3029                  region.right <= this.right &&
3030                  region.top >= this.top &&
3031                  region.bottom <= this.bottom    );
3032
3033     },
3034
3035     getArea : function() {
3036         return ( (this.bottom - this.top) * (this.right - this.left) );
3037     },
3038
3039     intersect : function(region) {
3040         var t = Math.max(this.top, region.top);
3041         var r = Math.min(this.right, region.right);
3042         var b = Math.min(this.bottom, region.bottom);
3043         var l = Math.max(this.left, region.left);
3044
3045         if (b >= t && r >= l) {
3046             return new Roo.lib.Region(t, r, b, l);
3047         } else {
3048             return null;
3049         }
3050     },
3051     union : function(region) {
3052         var t = Math.min(this.top, region.top);
3053         var r = Math.max(this.right, region.right);
3054         var b = Math.max(this.bottom, region.bottom);
3055         var l = Math.min(this.left, region.left);
3056
3057         return new Roo.lib.Region(t, r, b, l);
3058     },
3059
3060     adjust : function(t, l, b, r) {
3061         this.top += t;
3062         this.left += l;
3063         this.right += r;
3064         this.bottom += b;
3065         return this;
3066     }
3067 };
3068
3069 Roo.lib.Region.getRegion = function(el) {
3070     var p = Roo.lib.Dom.getXY(el);
3071
3072     var t = p[1];
3073     var r = p[0] + el.offsetWidth;
3074     var b = p[1] + el.offsetHeight;
3075     var l = p[0];
3076
3077     return new Roo.lib.Region(t, r, b, l);
3078 };
3079 /*
3080  * Portions of this file are based on pieces of Yahoo User Interface Library
3081  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3082  * YUI licensed under the BSD License:
3083  * http://developer.yahoo.net/yui/license.txt
3084  * <script type="text/javascript">
3085  *
3086  */
3087 //@@dep Roo.lib.Region
3088
3089
3090 Roo.lib.Point = function(x, y) {
3091     if (x instanceof Array) {
3092         y = x[1];
3093         x = x[0];
3094     }
3095     this.x = this.right = this.left = this[0] = x;
3096     this.y = this.top = this.bottom = this[1] = y;
3097 };
3098
3099 Roo.lib.Point.prototype = new Roo.lib.Region();
3100 /*
3101  * Portions of this file are based on pieces of Yahoo User Interface Library
3102  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3103  * YUI licensed under the BSD License:
3104  * http://developer.yahoo.net/yui/license.txt
3105  * <script type="text/javascript">
3106  *
3107  */
3108  
3109 (function() {   
3110
3111     Roo.lib.Anim = {
3112         scroll : function(el, args, duration, easing, cb, scope) {
3113             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3114         },
3115
3116         motion : function(el, args, duration, easing, cb, scope) {
3117             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3118         },
3119
3120         color : function(el, args, duration, easing, cb, scope) {
3121             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3122         },
3123
3124         run : function(el, args, duration, easing, cb, scope, type) {
3125             type = type || Roo.lib.AnimBase;
3126             if (typeof easing == "string") {
3127                 easing = Roo.lib.Easing[easing];
3128             }
3129             var anim = new type(el, args, duration, easing);
3130             anim.animateX(function() {
3131                 Roo.callback(cb, scope);
3132             });
3133             return anim;
3134         }
3135     };
3136 })();/*
3137  * Portions of this file are based on pieces of Yahoo User Interface Library
3138  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3139  * YUI licensed under the BSD License:
3140  * http://developer.yahoo.net/yui/license.txt
3141  * <script type="text/javascript">
3142  *
3143  */
3144
3145 (function() {    
3146     var libFlyweight;
3147     
3148     function fly(el) {
3149         if (!libFlyweight) {
3150             libFlyweight = new Roo.Element.Flyweight();
3151         }
3152         libFlyweight.dom = el;
3153         return libFlyweight;
3154     }
3155
3156     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3157     
3158    
3159     
3160     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3161         if (el) {
3162             this.init(el, attributes, duration, method);
3163         }
3164     };
3165
3166     Roo.lib.AnimBase.fly = fly;
3167     
3168     
3169     
3170     Roo.lib.AnimBase.prototype = {
3171
3172         toString: function() {
3173             var el = this.getEl();
3174             var id = el.id || el.tagName;
3175             return ("Anim " + id);
3176         },
3177
3178         patterns: {
3179             noNegatives:        /width|height|opacity|padding/i,
3180             offsetAttribute:  /^((width|height)|(top|left))$/,
3181             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3182             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3183         },
3184
3185
3186         doMethod: function(attr, start, end) {
3187             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3188         },
3189
3190
3191         setAttribute: function(attr, val, unit) {
3192             if (this.patterns.noNegatives.test(attr)) {
3193                 val = (val > 0) ? val : 0;
3194             }
3195
3196             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3197         },
3198
3199
3200         getAttribute: function(attr) {
3201             var el = this.getEl();
3202             var val = fly(el).getStyle(attr);
3203
3204             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3205                 return parseFloat(val);
3206             }
3207
3208             var a = this.patterns.offsetAttribute.exec(attr) || [];
3209             var pos = !!( a[3] );
3210             var box = !!( a[2] );
3211
3212
3213             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3214                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3215             } else {
3216                 val = 0;
3217             }
3218
3219             return val;
3220         },
3221
3222
3223         getDefaultUnit: function(attr) {
3224             if (this.patterns.defaultUnit.test(attr)) {
3225                 return 'px';
3226             }
3227
3228             return '';
3229         },
3230
3231         animateX : function(callback, scope) {
3232             var f = function() {
3233                 this.onComplete.removeListener(f);
3234                 if (typeof callback == "function") {
3235                     callback.call(scope || this, this);
3236                 }
3237             };
3238             this.onComplete.addListener(f, this);
3239             this.animate();
3240         },
3241
3242
3243         setRuntimeAttribute: function(attr) {
3244             var start;
3245             var end;
3246             var attributes = this.attributes;
3247
3248             this.runtimeAttributes[attr] = {};
3249
3250             var isset = function(prop) {
3251                 return (typeof prop !== 'undefined');
3252             };
3253
3254             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3255                 return false;
3256             }
3257
3258             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3259
3260
3261             if (isset(attributes[attr]['to'])) {
3262                 end = attributes[attr]['to'];
3263             } else if (isset(attributes[attr]['by'])) {
3264                 if (start.constructor == Array) {
3265                     end = [];
3266                     for (var i = 0, len = start.length; i < len; ++i) {
3267                         end[i] = start[i] + attributes[attr]['by'][i];
3268                     }
3269                 } else {
3270                     end = start + attributes[attr]['by'];
3271                 }
3272             }
3273
3274             this.runtimeAttributes[attr].start = start;
3275             this.runtimeAttributes[attr].end = end;
3276
3277
3278             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3279         },
3280
3281
3282         init: function(el, attributes, duration, method) {
3283
3284             var isAnimated = false;
3285
3286
3287             var startTime = null;
3288
3289
3290             var actualFrames = 0;
3291
3292
3293             el = Roo.getDom(el);
3294
3295
3296             this.attributes = attributes || {};
3297
3298
3299             this.duration = duration || 1;
3300
3301
3302             this.method = method || Roo.lib.Easing.easeNone;
3303
3304
3305             this.useSeconds = true;
3306
3307
3308             this.currentFrame = 0;
3309
3310
3311             this.totalFrames = Roo.lib.AnimMgr.fps;
3312
3313
3314             this.getEl = function() {
3315                 return el;
3316             };
3317
3318
3319             this.isAnimated = function() {
3320                 return isAnimated;
3321             };
3322
3323
3324             this.getStartTime = function() {
3325                 return startTime;
3326             };
3327
3328             this.runtimeAttributes = {};
3329
3330
3331             this.animate = function() {
3332                 if (this.isAnimated()) {
3333                     return false;
3334                 }
3335
3336                 this.currentFrame = 0;
3337
3338                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3339
3340                 Roo.lib.AnimMgr.registerElement(this);
3341             };
3342
3343
3344             this.stop = function(finish) {
3345                 if (finish) {
3346                     this.currentFrame = this.totalFrames;
3347                     this._onTween.fire();
3348                 }
3349                 Roo.lib.AnimMgr.stop(this);
3350             };
3351
3352             var onStart = function() {
3353                 this.onStart.fire();
3354
3355                 this.runtimeAttributes = {};
3356                 for (var attr in this.attributes) {
3357                     this.setRuntimeAttribute(attr);
3358                 }
3359
3360                 isAnimated = true;
3361                 actualFrames = 0;
3362                 startTime = new Date();
3363             };
3364
3365
3366             var onTween = function() {
3367                 var data = {
3368                     duration: new Date() - this.getStartTime(),
3369                     currentFrame: this.currentFrame
3370                 };
3371
3372                 data.toString = function() {
3373                     return (
3374                             'duration: ' + data.duration +
3375                             ', currentFrame: ' + data.currentFrame
3376                             );
3377                 };
3378
3379                 this.onTween.fire(data);
3380
3381                 var runtimeAttributes = this.runtimeAttributes;
3382
3383                 for (var attr in runtimeAttributes) {
3384                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3385                 }
3386
3387                 actualFrames += 1;
3388             };
3389
3390             var onComplete = function() {
3391                 var actual_duration = (new Date() - startTime) / 1000 ;
3392
3393                 var data = {
3394                     duration: actual_duration,
3395                     frames: actualFrames,
3396                     fps: actualFrames / actual_duration
3397                 };
3398
3399                 data.toString = function() {
3400                     return (
3401                             'duration: ' + data.duration +
3402                             ', frames: ' + data.frames +
3403                             ', fps: ' + data.fps
3404                             );
3405                 };
3406
3407                 isAnimated = false;
3408                 actualFrames = 0;
3409                 this.onComplete.fire(data);
3410             };
3411
3412
3413             this._onStart = new Roo.util.Event(this);
3414             this.onStart = new Roo.util.Event(this);
3415             this.onTween = new Roo.util.Event(this);
3416             this._onTween = new Roo.util.Event(this);
3417             this.onComplete = new Roo.util.Event(this);
3418             this._onComplete = new Roo.util.Event(this);
3419             this._onStart.addListener(onStart);
3420             this._onTween.addListener(onTween);
3421             this._onComplete.addListener(onComplete);
3422         }
3423     };
3424 })();
3425 /*
3426  * Portions of this file are based on pieces of Yahoo User Interface Library
3427  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3428  * YUI licensed under the BSD License:
3429  * http://developer.yahoo.net/yui/license.txt
3430  * <script type="text/javascript">
3431  *
3432  */
3433
3434 Roo.lib.AnimMgr = new function() {
3435
3436     var thread = null;
3437
3438
3439     var queue = [];
3440
3441
3442     var tweenCount = 0;
3443
3444
3445     this.fps = 1000;
3446
3447
3448     this.delay = 1;
3449
3450
3451     this.registerElement = function(tween) {
3452         queue[queue.length] = tween;
3453         tweenCount += 1;
3454         tween._onStart.fire();
3455         this.start();
3456     };
3457
3458
3459     this.unRegister = function(tween, index) {
3460         tween._onComplete.fire();
3461         index = index || getIndex(tween);
3462         if (index != -1) {
3463             queue.splice(index, 1);
3464         }
3465
3466         tweenCount -= 1;
3467         if (tweenCount <= 0) {
3468             this.stop();
3469         }
3470     };
3471
3472
3473     this.start = function() {
3474         if (thread === null) {
3475             thread = setInterval(this.run, this.delay);
3476         }
3477     };
3478
3479
3480     this.stop = function(tween) {
3481         if (!tween) {
3482             clearInterval(thread);
3483
3484             for (var i = 0, len = queue.length; i < len; ++i) {
3485                 if (queue[0].isAnimated()) {
3486                     this.unRegister(queue[0], 0);
3487                 }
3488             }
3489
3490             queue = [];
3491             thread = null;
3492             tweenCount = 0;
3493         }
3494         else {
3495             this.unRegister(tween);
3496         }
3497     };
3498
3499
3500     this.run = function() {
3501         for (var i = 0, len = queue.length; i < len; ++i) {
3502             var tween = queue[i];
3503             if (!tween || !tween.isAnimated()) {
3504                 continue;
3505             }
3506
3507             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3508             {
3509                 tween.currentFrame += 1;
3510
3511                 if (tween.useSeconds) {
3512                     correctFrame(tween);
3513                 }
3514                 tween._onTween.fire();
3515             }
3516             else {
3517                 Roo.lib.AnimMgr.stop(tween, i);
3518             }
3519         }
3520     };
3521
3522     var getIndex = function(anim) {
3523         for (var i = 0, len = queue.length; i < len; ++i) {
3524             if (queue[i] == anim) {
3525                 return i;
3526             }
3527         }
3528         return -1;
3529     };
3530
3531
3532     var correctFrame = function(tween) {
3533         var frames = tween.totalFrames;
3534         var frame = tween.currentFrame;
3535         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3536         var elapsed = (new Date() - tween.getStartTime());
3537         var tweak = 0;
3538
3539         if (elapsed < tween.duration * 1000) {
3540             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3541         } else {
3542             tweak = frames - (frame + 1);
3543         }
3544         if (tweak > 0 && isFinite(tweak)) {
3545             if (tween.currentFrame + tweak >= frames) {
3546                 tweak = frames - (frame + 1);
3547             }
3548
3549             tween.currentFrame += tweak;
3550         }
3551     };
3552 };
3553
3554     /*
3555  * Portions of this file are based on pieces of Yahoo User Interface Library
3556  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557  * YUI licensed under the BSD License:
3558  * http://developer.yahoo.net/yui/license.txt
3559  * <script type="text/javascript">
3560  *
3561  */
3562 Roo.lib.Bezier = new function() {
3563
3564         this.getPosition = function(points, t) {
3565             var n = points.length;
3566             var tmp = [];
3567
3568             for (var i = 0; i < n; ++i) {
3569                 tmp[i] = [points[i][0], points[i][1]];
3570             }
3571
3572             for (var j = 1; j < n; ++j) {
3573                 for (i = 0; i < n - j; ++i) {
3574                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3575                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3576                 }
3577             }
3578
3579             return [ tmp[0][0], tmp[0][1] ];
3580
3581         };
3582     };/*
3583  * Portions of this file are based on pieces of Yahoo User Interface Library
3584  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3585  * YUI licensed under the BSD License:
3586  * http://developer.yahoo.net/yui/license.txt
3587  * <script type="text/javascript">
3588  *
3589  */
3590 (function() {
3591
3592     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3593         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3594     };
3595
3596     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3597
3598     var fly = Roo.lib.AnimBase.fly;
3599     var Y = Roo.lib;
3600     var superclass = Y.ColorAnim.superclass;
3601     var proto = Y.ColorAnim.prototype;
3602
3603     proto.toString = function() {
3604         var el = this.getEl();
3605         var id = el.id || el.tagName;
3606         return ("ColorAnim " + id);
3607     };
3608
3609     proto.patterns.color = /color$/i;
3610     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3611     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3612     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3613     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3614
3615
3616     proto.parseColor = function(s) {
3617         if (s.length == 3) {
3618             return s;
3619         }
3620
3621         var c = this.patterns.hex.exec(s);
3622         if (c && c.length == 4) {
3623             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3624         }
3625
3626         c = this.patterns.rgb.exec(s);
3627         if (c && c.length == 4) {
3628             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3629         }
3630
3631         c = this.patterns.hex3.exec(s);
3632         if (c && c.length == 4) {
3633             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3634         }
3635
3636         return null;
3637     };
3638     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3639     proto.getAttribute = function(attr) {
3640         var el = this.getEl();
3641         if (this.patterns.color.test(attr)) {
3642             var val = fly(el).getStyle(attr);
3643
3644             if (this.patterns.transparent.test(val)) {
3645                 var parent = el.parentNode;
3646                 val = fly(parent).getStyle(attr);
3647
3648                 while (parent && this.patterns.transparent.test(val)) {
3649                     parent = parent.parentNode;
3650                     val = fly(parent).getStyle(attr);
3651                     if (parent.tagName.toUpperCase() == 'HTML') {
3652                         val = '#fff';
3653                     }
3654                 }
3655             }
3656         } else {
3657             val = superclass.getAttribute.call(this, attr);
3658         }
3659
3660         return val;
3661     };
3662     proto.getAttribute = function(attr) {
3663         var el = this.getEl();
3664         if (this.patterns.color.test(attr)) {
3665             var val = fly(el).getStyle(attr);
3666
3667             if (this.patterns.transparent.test(val)) {
3668                 var parent = el.parentNode;
3669                 val = fly(parent).getStyle(attr);
3670
3671                 while (parent && this.patterns.transparent.test(val)) {
3672                     parent = parent.parentNode;
3673                     val = fly(parent).getStyle(attr);
3674                     if (parent.tagName.toUpperCase() == 'HTML') {
3675                         val = '#fff';
3676                     }
3677                 }
3678             }
3679         } else {
3680             val = superclass.getAttribute.call(this, attr);
3681         }
3682
3683         return val;
3684     };
3685
3686     proto.doMethod = function(attr, start, end) {
3687         var val;
3688
3689         if (this.patterns.color.test(attr)) {
3690             val = [];
3691             for (var i = 0, len = start.length; i < len; ++i) {
3692                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3693             }
3694
3695             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3696         }
3697         else {
3698             val = superclass.doMethod.call(this, attr, start, end);
3699         }
3700
3701         return val;
3702     };
3703
3704     proto.setRuntimeAttribute = function(attr) {
3705         superclass.setRuntimeAttribute.call(this, attr);
3706
3707         if (this.patterns.color.test(attr)) {
3708             var attributes = this.attributes;
3709             var start = this.parseColor(this.runtimeAttributes[attr].start);
3710             var end = this.parseColor(this.runtimeAttributes[attr].end);
3711
3712             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3713                 end = this.parseColor(attributes[attr].by);
3714
3715                 for (var i = 0, len = start.length; i < len; ++i) {
3716                     end[i] = start[i] + end[i];
3717                 }
3718             }
3719
3720             this.runtimeAttributes[attr].start = start;
3721             this.runtimeAttributes[attr].end = end;
3722         }
3723     };
3724 })();
3725
3726 /*
3727  * Portions of this file are based on pieces of Yahoo User Interface Library
3728  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3729  * YUI licensed under the BSD License:
3730  * http://developer.yahoo.net/yui/license.txt
3731  * <script type="text/javascript">
3732  *
3733  */
3734 Roo.lib.Easing = {
3735
3736
3737     easeNone: function (t, b, c, d) {
3738         return c * t / d + b;
3739     },
3740
3741
3742     easeIn: function (t, b, c, d) {
3743         return c * (t /= d) * t + b;
3744     },
3745
3746
3747     easeOut: function (t, b, c, d) {
3748         return -c * (t /= d) * (t - 2) + b;
3749     },
3750
3751
3752     easeBoth: function (t, b, c, d) {
3753         if ((t /= d / 2) < 1) {
3754             return c / 2 * t * t + b;
3755         }
3756
3757         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3758     },
3759
3760
3761     easeInStrong: function (t, b, c, d) {
3762         return c * (t /= d) * t * t * t + b;
3763     },
3764
3765
3766     easeOutStrong: function (t, b, c, d) {
3767         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3768     },
3769
3770
3771     easeBothStrong: function (t, b, c, d) {
3772         if ((t /= d / 2) < 1) {
3773             return c / 2 * t * t * t * t + b;
3774         }
3775
3776         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3777     },
3778
3779
3780
3781     elasticIn: function (t, b, c, d, a, p) {
3782         if (t == 0) {
3783             return b;
3784         }
3785         if ((t /= d) == 1) {
3786             return b + c;
3787         }
3788         if (!p) {
3789             p = d * .3;
3790         }
3791
3792         if (!a || a < Math.abs(c)) {
3793             a = c;
3794             var s = p / 4;
3795         }
3796         else {
3797             var s = p / (2 * Math.PI) * Math.asin(c / a);
3798         }
3799
3800         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3801     },
3802
3803
3804     elasticOut: function (t, b, c, d, a, p) {
3805         if (t == 0) {
3806             return b;
3807         }
3808         if ((t /= d) == 1) {
3809             return b + c;
3810         }
3811         if (!p) {
3812             p = d * .3;
3813         }
3814
3815         if (!a || a < Math.abs(c)) {
3816             a = c;
3817             var s = p / 4;
3818         }
3819         else {
3820             var s = p / (2 * Math.PI) * Math.asin(c / a);
3821         }
3822
3823         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3824     },
3825
3826
3827     elasticBoth: function (t, b, c, d, a, p) {
3828         if (t == 0) {
3829             return b;
3830         }
3831
3832         if ((t /= d / 2) == 2) {
3833             return b + c;
3834         }
3835
3836         if (!p) {
3837             p = d * (.3 * 1.5);
3838         }
3839
3840         if (!a || a < Math.abs(c)) {
3841             a = c;
3842             var s = p / 4;
3843         }
3844         else {
3845             var s = p / (2 * Math.PI) * Math.asin(c / a);
3846         }
3847
3848         if (t < 1) {
3849             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3850                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3851         }
3852         return a * Math.pow(2, -10 * (t -= 1)) *
3853                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3854     },
3855
3856
3857
3858     backIn: function (t, b, c, d, s) {
3859         if (typeof s == 'undefined') {
3860             s = 1.70158;
3861         }
3862         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3863     },
3864
3865
3866     backOut: function (t, b, c, d, s) {
3867         if (typeof s == 'undefined') {
3868             s = 1.70158;
3869         }
3870         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3871     },
3872
3873
3874     backBoth: function (t, b, c, d, s) {
3875         if (typeof s == 'undefined') {
3876             s = 1.70158;
3877         }
3878
3879         if ((t /= d / 2 ) < 1) {
3880             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3881         }
3882         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3883     },
3884
3885
3886     bounceIn: function (t, b, c, d) {
3887         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3888     },
3889
3890
3891     bounceOut: function (t, b, c, d) {
3892         if ((t /= d) < (1 / 2.75)) {
3893             return c * (7.5625 * t * t) + b;
3894         } else if (t < (2 / 2.75)) {
3895             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3896         } else if (t < (2.5 / 2.75)) {
3897             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3898         }
3899         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3900     },
3901
3902
3903     bounceBoth: function (t, b, c, d) {
3904         if (t < d / 2) {
3905             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3906         }
3907         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3908     }
3909 };/*
3910  * Portions of this file are based on pieces of Yahoo User Interface Library
3911  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3912  * YUI licensed under the BSD License:
3913  * http://developer.yahoo.net/yui/license.txt
3914  * <script type="text/javascript">
3915  *
3916  */
3917     (function() {
3918         Roo.lib.Motion = function(el, attributes, duration, method) {
3919             if (el) {
3920                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3921             }
3922         };
3923
3924         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3925
3926
3927         var Y = Roo.lib;
3928         var superclass = Y.Motion.superclass;
3929         var proto = Y.Motion.prototype;
3930
3931         proto.toString = function() {
3932             var el = this.getEl();
3933             var id = el.id || el.tagName;
3934             return ("Motion " + id);
3935         };
3936
3937         proto.patterns.points = /^points$/i;
3938
3939         proto.setAttribute = function(attr, val, unit) {
3940             if (this.patterns.points.test(attr)) {
3941                 unit = unit || 'px';
3942                 superclass.setAttribute.call(this, 'left', val[0], unit);
3943                 superclass.setAttribute.call(this, 'top', val[1], unit);
3944             } else {
3945                 superclass.setAttribute.call(this, attr, val, unit);
3946             }
3947         };
3948
3949         proto.getAttribute = function(attr) {
3950             if (this.patterns.points.test(attr)) {
3951                 var val = [
3952                         superclass.getAttribute.call(this, 'left'),
3953                         superclass.getAttribute.call(this, 'top')
3954                         ];
3955             } else {
3956                 val = superclass.getAttribute.call(this, attr);
3957             }
3958
3959             return val;
3960         };
3961
3962         proto.doMethod = function(attr, start, end) {
3963             var val = null;
3964
3965             if (this.patterns.points.test(attr)) {
3966                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3967                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3968             } else {
3969                 val = superclass.doMethod.call(this, attr, start, end);
3970             }
3971             return val;
3972         };
3973
3974         proto.setRuntimeAttribute = function(attr) {
3975             if (this.patterns.points.test(attr)) {
3976                 var el = this.getEl();
3977                 var attributes = this.attributes;
3978                 var start;
3979                 var control = attributes['points']['control'] || [];
3980                 var end;
3981                 var i, len;
3982
3983                 if (control.length > 0 && !(control[0] instanceof Array)) {
3984                     control = [control];
3985                 } else {
3986                     var tmp = [];
3987                     for (i = 0,len = control.length; i < len; ++i) {
3988                         tmp[i] = control[i];
3989                     }
3990                     control = tmp;
3991                 }
3992
3993                 Roo.fly(el).position();
3994
3995                 if (isset(attributes['points']['from'])) {
3996                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3997                 }
3998                 else {
3999                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4000                 }
4001
4002                 start = this.getAttribute('points');
4003
4004
4005                 if (isset(attributes['points']['to'])) {
4006                     end = translateValues.call(this, attributes['points']['to'], start);
4007
4008                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009                     for (i = 0,len = control.length; i < len; ++i) {
4010                         control[i] = translateValues.call(this, control[i], start);
4011                     }
4012
4013
4014                 } else if (isset(attributes['points']['by'])) {
4015                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4016
4017                     for (i = 0,len = control.length; i < len; ++i) {
4018                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4019                     }
4020                 }
4021
4022                 this.runtimeAttributes[attr] = [start];
4023
4024                 if (control.length > 0) {
4025                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4026                 }
4027
4028                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4029             }
4030             else {
4031                 superclass.setRuntimeAttribute.call(this, attr);
4032             }
4033         };
4034
4035         var translateValues = function(val, start) {
4036             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4037             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4038
4039             return val;
4040         };
4041
4042         var isset = function(prop) {
4043             return (typeof prop !== 'undefined');
4044         };
4045     })();
4046 /*
4047  * Portions of this file are based on pieces of Yahoo User Interface Library
4048  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4049  * YUI licensed under the BSD License:
4050  * http://developer.yahoo.net/yui/license.txt
4051  * <script type="text/javascript">
4052  *
4053  */
4054     (function() {
4055         Roo.lib.Scroll = function(el, attributes, duration, method) {
4056             if (el) {
4057                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4058             }
4059         };
4060
4061         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4062
4063
4064         var Y = Roo.lib;
4065         var superclass = Y.Scroll.superclass;
4066         var proto = Y.Scroll.prototype;
4067
4068         proto.toString = function() {
4069             var el = this.getEl();
4070             var id = el.id || el.tagName;
4071             return ("Scroll " + id);
4072         };
4073
4074         proto.doMethod = function(attr, start, end) {
4075             var val = null;
4076
4077             if (attr == 'scroll') {
4078                 val = [
4079                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4080                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4081                         ];
4082
4083             } else {
4084                 val = superclass.doMethod.call(this, attr, start, end);
4085             }
4086             return val;
4087         };
4088
4089         proto.getAttribute = function(attr) {
4090             var val = null;
4091             var el = this.getEl();
4092
4093             if (attr == 'scroll') {
4094                 val = [ el.scrollLeft, el.scrollTop ];
4095             } else {
4096                 val = superclass.getAttribute.call(this, attr);
4097             }
4098
4099             return val;
4100         };
4101
4102         proto.setAttribute = function(attr, val, unit) {
4103             var el = this.getEl();
4104
4105             if (attr == 'scroll') {
4106                 el.scrollLeft = val[0];
4107                 el.scrollTop = val[1];
4108             } else {
4109                 superclass.setAttribute.call(this, attr, val, unit);
4110             }
4111         };
4112     })();
4113 /*
4114  * Based on:
4115  * Ext JS Library 1.1.1
4116  * Copyright(c) 2006-2007, Ext JS, LLC.
4117  *
4118  * Originally Released Under LGPL - original licence link has changed is not relivant.
4119  *
4120  * Fork - LGPL
4121  * <script type="text/javascript">
4122  */
4123
4124
4125 // nasty IE9 hack - what a pile of crap that is..
4126
4127  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4128     Range.prototype.createContextualFragment = function (html) {
4129         var doc = window.document;
4130         var container = doc.createElement("div");
4131         container.innerHTML = html;
4132         var frag = doc.createDocumentFragment(), n;
4133         while ((n = container.firstChild)) {
4134             frag.appendChild(n);
4135         }
4136         return frag;
4137     };
4138 }
4139
4140 /**
4141  * @class Roo.DomHelper
4142  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4143  * 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>.
4144  * @singleton
4145  */
4146 Roo.DomHelper = function(){
4147     var tempTableEl = null;
4148     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4149     var tableRe = /^table|tbody|tr|td$/i;
4150     var xmlns = {};
4151     // build as innerHTML where available
4152     /** @ignore */
4153     var createHtml = function(o){
4154         if(typeof o == 'string'){
4155             return o;
4156         }
4157         var b = "";
4158         if(!o.tag){
4159             o.tag = "div";
4160         }
4161         b += "<" + o.tag;
4162         for(var attr in o){
4163             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4164             if(attr == "style"){
4165                 var s = o["style"];
4166                 if(typeof s == "function"){
4167                     s = s.call();
4168                 }
4169                 if(typeof s == "string"){
4170                     b += ' style="' + s + '"';
4171                 }else if(typeof s == "object"){
4172                     b += ' style="';
4173                     for(var key in s){
4174                         if(typeof s[key] != "function"){
4175                             b += key + ":" + s[key] + ";";
4176                         }
4177                     }
4178                     b += '"';
4179                 }
4180             }else{
4181                 if(attr == "cls"){
4182                     b += ' class="' + o["cls"] + '"';
4183                 }else if(attr == "htmlFor"){
4184                     b += ' for="' + o["htmlFor"] + '"';
4185                 }else{
4186                     b += " " + attr + '="' + o[attr] + '"';
4187                 }
4188             }
4189         }
4190         if(emptyTags.test(o.tag)){
4191             b += "/>";
4192         }else{
4193             b += ">";
4194             var cn = o.children || o.cn;
4195             if(cn){
4196                 //http://bugs.kde.org/show_bug.cgi?id=71506
4197                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4198                     for(var i = 0, len = cn.length; i < len; i++) {
4199                         b += createHtml(cn[i], b);
4200                     }
4201                 }else{
4202                     b += createHtml(cn, b);
4203                 }
4204             }
4205             if(o.html){
4206                 b += o.html;
4207             }
4208             b += "</" + o.tag + ">";
4209         }
4210         return b;
4211     };
4212
4213     // build as dom
4214     /** @ignore */
4215     var createDom = function(o, parentNode){
4216          
4217         // defininition craeted..
4218         var ns = false;
4219         if (o.ns && o.ns != 'html') {
4220                
4221             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4222                 xmlns[o.ns] = o.xmlns;
4223                 ns = o.xmlns;
4224             }
4225             if (typeof(xmlns[o.ns]) == 'undefined') {
4226                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4227             }
4228             ns = xmlns[o.ns];
4229         }
4230         
4231         
4232         if (typeof(o) == 'string') {
4233             return parentNode.appendChild(document.createTextNode(o));
4234         }
4235         o.tag = o.tag || div;
4236         if (o.ns && Roo.isIE) {
4237             ns = false;
4238             o.tag = o.ns + ':' + o.tag;
4239             
4240         }
4241         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4242         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4243         for(var attr in o){
4244             
4245             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4246                     attr == "style" || typeof o[attr] == "function") { continue; }
4247                     
4248             if(attr=="cls" && Roo.isIE){
4249                 el.className = o["cls"];
4250             }else{
4251                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4252                 else { 
4253                     el[attr] = o[attr];
4254                 }
4255             }
4256         }
4257         Roo.DomHelper.applyStyles(el, o.style);
4258         var cn = o.children || o.cn;
4259         if(cn){
4260             //http://bugs.kde.org/show_bug.cgi?id=71506
4261              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4262                 for(var i = 0, len = cn.length; i < len; i++) {
4263                     createDom(cn[i], el);
4264                 }
4265             }else{
4266                 createDom(cn, el);
4267             }
4268         }
4269         if(o.html){
4270             el.innerHTML = o.html;
4271         }
4272         if(parentNode){
4273            parentNode.appendChild(el);
4274         }
4275         return el;
4276     };
4277
4278     var ieTable = function(depth, s, h, e){
4279         tempTableEl.innerHTML = [s, h, e].join('');
4280         var i = -1, el = tempTableEl;
4281         while(++i < depth){
4282             el = el.firstChild;
4283         }
4284         return el;
4285     };
4286
4287     // kill repeat to save bytes
4288     var ts = '<table>',
4289         te = '</table>',
4290         tbs = ts+'<tbody>',
4291         tbe = '</tbody>'+te,
4292         trs = tbs + '<tr>',
4293         tre = '</tr>'+tbe;
4294
4295     /**
4296      * @ignore
4297      * Nasty code for IE's broken table implementation
4298      */
4299     var insertIntoTable = function(tag, where, el, html){
4300         if(!tempTableEl){
4301             tempTableEl = document.createElement('div');
4302         }
4303         var node;
4304         var before = null;
4305         if(tag == 'td'){
4306             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4307                 return;
4308             }
4309             if(where == 'beforebegin'){
4310                 before = el;
4311                 el = el.parentNode;
4312             } else{
4313                 before = el.nextSibling;
4314                 el = el.parentNode;
4315             }
4316             node = ieTable(4, trs, html, tre);
4317         }
4318         else if(tag == 'tr'){
4319             if(where == 'beforebegin'){
4320                 before = el;
4321                 el = el.parentNode;
4322                 node = ieTable(3, tbs, html, tbe);
4323             } else if(where == 'afterend'){
4324                 before = el.nextSibling;
4325                 el = el.parentNode;
4326                 node = ieTable(3, tbs, html, tbe);
4327             } else{ // INTO a TR
4328                 if(where == 'afterbegin'){
4329                     before = el.firstChild;
4330                 }
4331                 node = ieTable(4, trs, html, tre);
4332             }
4333         } else if(tag == 'tbody'){
4334             if(where == 'beforebegin'){
4335                 before = el;
4336                 el = el.parentNode;
4337                 node = ieTable(2, ts, html, te);
4338             } else if(where == 'afterend'){
4339                 before = el.nextSibling;
4340                 el = el.parentNode;
4341                 node = ieTable(2, ts, html, te);
4342             } else{
4343                 if(where == 'afterbegin'){
4344                     before = el.firstChild;
4345                 }
4346                 node = ieTable(3, tbs, html, tbe);
4347             }
4348         } else{ // TABLE
4349             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4350                 return;
4351             }
4352             if(where == 'afterbegin'){
4353                 before = el.firstChild;
4354             }
4355             node = ieTable(2, ts, html, te);
4356         }
4357         el.insertBefore(node, before);
4358         return node;
4359     };
4360
4361     return {
4362     /** True to force the use of DOM instead of html fragments @type Boolean */
4363     useDom : false,
4364
4365     /**
4366      * Returns the markup for the passed Element(s) config
4367      * @param {Object} o The Dom object spec (and children)
4368      * @return {String}
4369      */
4370     markup : function(o){
4371         return createHtml(o);
4372     },
4373
4374     /**
4375      * Applies a style specification to an element
4376      * @param {String/HTMLElement} el The element to apply styles to
4377      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4378      * a function which returns such a specification.
4379      */
4380     applyStyles : function(el, styles){
4381         if(styles){
4382            el = Roo.fly(el);
4383            if(typeof styles == "string"){
4384                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4385                var matches;
4386                while ((matches = re.exec(styles)) != null){
4387                    el.setStyle(matches[1], matches[2]);
4388                }
4389            }else if (typeof styles == "object"){
4390                for (var style in styles){
4391                   el.setStyle(style, styles[style]);
4392                }
4393            }else if (typeof styles == "function"){
4394                 Roo.DomHelper.applyStyles(el, styles.call());
4395            }
4396         }
4397     },
4398
4399     /**
4400      * Inserts an HTML fragment into the Dom
4401      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4402      * @param {HTMLElement} el The context element
4403      * @param {String} html The HTML fragmenet
4404      * @return {HTMLElement} The new node
4405      */
4406     insertHtml : function(where, el, html){
4407         where = where.toLowerCase();
4408         if(el.insertAdjacentHTML){
4409             if(tableRe.test(el.tagName)){
4410                 var rs;
4411                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4412                     return rs;
4413                 }
4414             }
4415             switch(where){
4416                 case "beforebegin":
4417                     el.insertAdjacentHTML('BeforeBegin', html);
4418                     return el.previousSibling;
4419                 case "afterbegin":
4420                     el.insertAdjacentHTML('AfterBegin', html);
4421                     return el.firstChild;
4422                 case "beforeend":
4423                     el.insertAdjacentHTML('BeforeEnd', html);
4424                     return el.lastChild;
4425                 case "afterend":
4426                     el.insertAdjacentHTML('AfterEnd', html);
4427                     return el.nextSibling;
4428             }
4429             throw 'Illegal insertion point -> "' + where + '"';
4430         }
4431         var range = el.ownerDocument.createRange();
4432         var frag;
4433         switch(where){
4434              case "beforebegin":
4435                 range.setStartBefore(el);
4436                 frag = range.createContextualFragment(html);
4437                 el.parentNode.insertBefore(frag, el);
4438                 return el.previousSibling;
4439              case "afterbegin":
4440                 if(el.firstChild){
4441                     range.setStartBefore(el.firstChild);
4442                     frag = range.createContextualFragment(html);
4443                     el.insertBefore(frag, el.firstChild);
4444                     return el.firstChild;
4445                 }else{
4446                     el.innerHTML = html;
4447                     return el.firstChild;
4448                 }
4449             case "beforeend":
4450                 if(el.lastChild){
4451                     range.setStartAfter(el.lastChild);
4452                     frag = range.createContextualFragment(html);
4453                     el.appendChild(frag);
4454                     return el.lastChild;
4455                 }else{
4456                     el.innerHTML = html;
4457                     return el.lastChild;
4458                 }
4459             case "afterend":
4460                 range.setStartAfter(el);
4461                 frag = range.createContextualFragment(html);
4462                 el.parentNode.insertBefore(frag, el.nextSibling);
4463                 return el.nextSibling;
4464             }
4465             throw 'Illegal insertion point -> "' + where + '"';
4466     },
4467
4468     /**
4469      * Creates new Dom element(s) and inserts them before el
4470      * @param {String/HTMLElement/Element} el The context element
4471      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473      * @return {HTMLElement/Roo.Element} The new node
4474      */
4475     insertBefore : function(el, o, returnElement){
4476         return this.doInsert(el, o, returnElement, "beforeBegin");
4477     },
4478
4479     /**
4480      * Creates new Dom element(s) and inserts them after el
4481      * @param {String/HTMLElement/Element} el The context element
4482      * @param {Object} o The Dom object spec (and children)
4483      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484      * @return {HTMLElement/Roo.Element} The new node
4485      */
4486     insertAfter : function(el, o, returnElement){
4487         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4488     },
4489
4490     /**
4491      * Creates new Dom element(s) and inserts them as the first child of el
4492      * @param {String/HTMLElement/Element} el The context element
4493      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4494      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4495      * @return {HTMLElement/Roo.Element} The new node
4496      */
4497     insertFirst : function(el, o, returnElement){
4498         return this.doInsert(el, o, returnElement, "afterBegin");
4499     },
4500
4501     // private
4502     doInsert : function(el, o, returnElement, pos, sibling){
4503         el = Roo.getDom(el);
4504         var newNode;
4505         if(this.useDom || o.ns){
4506             newNode = createDom(o, null);
4507             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4508         }else{
4509             var html = createHtml(o);
4510             newNode = this.insertHtml(pos, el, html);
4511         }
4512         return returnElement ? Roo.get(newNode, true) : newNode;
4513     },
4514
4515     /**
4516      * Creates new Dom element(s) and appends them to el
4517      * @param {String/HTMLElement/Element} el The context element
4518      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520      * @return {HTMLElement/Roo.Element} The new node
4521      */
4522     append : function(el, o, returnElement){
4523         el = Roo.getDom(el);
4524         var newNode;
4525         if(this.useDom || o.ns){
4526             newNode = createDom(o, null);
4527             el.appendChild(newNode);
4528         }else{
4529             var html = createHtml(o);
4530             newNode = this.insertHtml("beforeEnd", el, html);
4531         }
4532         return returnElement ? Roo.get(newNode, true) : newNode;
4533     },
4534
4535     /**
4536      * Creates new Dom element(s) and overwrites the contents of el with them
4537      * @param {String/HTMLElement/Element} el The context element
4538      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4539      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4540      * @return {HTMLElement/Roo.Element} The new node
4541      */
4542     overwrite : function(el, o, returnElement){
4543         el = Roo.getDom(el);
4544         if (o.ns) {
4545           
4546             while (el.childNodes.length) {
4547                 el.removeChild(el.firstChild);
4548             }
4549             createDom(o, el);
4550         } else {
4551             el.innerHTML = createHtml(o);   
4552         }
4553         
4554         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4555     },
4556
4557     /**
4558      * Creates a new Roo.DomHelper.Template from the Dom object spec
4559      * @param {Object} o The Dom object spec (and children)
4560      * @return {Roo.DomHelper.Template} The new template
4561      */
4562     createTemplate : function(o){
4563         var html = createHtml(o);
4564         return new Roo.Template(html);
4565     }
4566     };
4567 }();
4568 /*
4569  * Based on:
4570  * Ext JS Library 1.1.1
4571  * Copyright(c) 2006-2007, Ext JS, LLC.
4572  *
4573  * Originally Released Under LGPL - original licence link has changed is not relivant.
4574  *
4575  * Fork - LGPL
4576  * <script type="text/javascript">
4577  */
4578  
4579 /**
4580 * @class Roo.Template
4581 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4582 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4583 * Usage:
4584 <pre><code>
4585 var t = new Roo.Template({
4586     html :  '&lt;div name="{id}"&gt;' + 
4587         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4588         '&lt;/div&gt;',
4589     myformat: function (value, allValues) {
4590         return 'XX' + value;
4591     }
4592 });
4593 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4594 </code></pre>
4595 * For more information see this blog post with examples:
4596 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4597      - Create Elements using DOM, HTML fragments and Templates</a>. 
4598 * @constructor
4599 * @param {Object} cfg - Configuration object.
4600 */
4601 Roo.Template = function(cfg){
4602     // BC!
4603     if(cfg instanceof Array){
4604         cfg = cfg.join("");
4605     }else if(arguments.length > 1){
4606         cfg = Array.prototype.join.call(arguments, "");
4607     }
4608     
4609     
4610     if (typeof(cfg) == 'object') {
4611         Roo.apply(this,cfg)
4612     } else {
4613         // bc
4614         this.html = cfg;
4615     }
4616     if (this.url) {
4617         this.load();
4618     }
4619     
4620 };
4621 Roo.Template.prototype = {
4622     
4623     /**
4624      * @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..
4625      *                    it should be fixed so that template is observable...
4626      */
4627     url : false,
4628     /**
4629      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4630      */
4631     html : '',
4632     /**
4633      * Returns an HTML fragment of this template with the specified values applied.
4634      * @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'})
4635      * @return {String} The HTML fragment
4636      */
4637     applyTemplate : function(values){
4638         try {
4639            
4640             if(this.compiled){
4641                 return this.compiled(values);
4642             }
4643             var useF = this.disableFormats !== true;
4644             var fm = Roo.util.Format, tpl = this;
4645             var fn = function(m, name, format, args){
4646                 if(format && useF){
4647                     if(format.substr(0, 5) == "this."){
4648                         return tpl.call(format.substr(5), values[name], values);
4649                     }else{
4650                         if(args){
4651                             // quoted values are required for strings in compiled templates, 
4652                             // but for non compiled we need to strip them
4653                             // quoted reversed for jsmin
4654                             var re = /^\s*['"](.*)["']\s*$/;
4655                             args = args.split(',');
4656                             for(var i = 0, len = args.length; i < len; i++){
4657                                 args[i] = args[i].replace(re, "$1");
4658                             }
4659                             args = [values[name]].concat(args);
4660                         }else{
4661                             args = [values[name]];
4662                         }
4663                         return fm[format].apply(fm, args);
4664                     }
4665                 }else{
4666                     return values[name] !== undefined ? values[name] : "";
4667                 }
4668             };
4669             return this.html.replace(this.re, fn);
4670         } catch (e) {
4671             Roo.log(e);
4672             throw e;
4673         }
4674          
4675     },
4676     
4677     loading : false,
4678       
4679     load : function ()
4680     {
4681          
4682         if (this.loading) {
4683             return;
4684         }
4685         var _t = this;
4686         
4687         this.loading = true;
4688         this.compiled = false;
4689         
4690         var cx = new Roo.data.Connection();
4691         cx.request({
4692             url : this.url,
4693             method : 'GET',
4694             success : function (response) {
4695                 _t.loading = false;
4696                 _t.html = response.responseText;
4697                 _t.url = false;
4698                 _t.compile();
4699              },
4700             failure : function(response) {
4701                 Roo.log("Template failed to load from " + _t.url);
4702                 _t.loading = false;
4703             }
4704         });
4705     },
4706
4707     /**
4708      * Sets the HTML used as the template and optionally compiles it.
4709      * @param {String} html
4710      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4711      * @return {Roo.Template} this
4712      */
4713     set : function(html, compile){
4714         this.html = html;
4715         this.compiled = null;
4716         if(compile){
4717             this.compile();
4718         }
4719         return this;
4720     },
4721     
4722     /**
4723      * True to disable format functions (defaults to false)
4724      * @type Boolean
4725      */
4726     disableFormats : false,
4727     
4728     /**
4729     * The regular expression used to match template variables 
4730     * @type RegExp
4731     * @property 
4732     */
4733     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4734     
4735     /**
4736      * Compiles the template into an internal function, eliminating the RegEx overhead.
4737      * @return {Roo.Template} this
4738      */
4739     compile : function(){
4740         var fm = Roo.util.Format;
4741         var useF = this.disableFormats !== true;
4742         var sep = Roo.isGecko ? "+" : ",";
4743         var fn = function(m, name, format, args){
4744             if(format && useF){
4745                 args = args ? ',' + args : "";
4746                 if(format.substr(0, 5) != "this."){
4747                     format = "fm." + format + '(';
4748                 }else{
4749                     format = 'this.call("'+ format.substr(5) + '", ';
4750                     args = ", values";
4751                 }
4752             }else{
4753                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4754             }
4755             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4756         };
4757         var body;
4758         // branched to use + in gecko and [].join() in others
4759         if(Roo.isGecko){
4760             body = "this.compiled = function(values){ return '" +
4761                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4762                     "';};";
4763         }else{
4764             body = ["this.compiled = function(values){ return ['"];
4765             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4766             body.push("'].join('');};");
4767             body = body.join('');
4768         }
4769         /**
4770          * eval:var:values
4771          * eval:var:fm
4772          */
4773         eval(body);
4774         return this;
4775     },
4776     
4777     // private function used to call members
4778     call : function(fnName, value, allValues){
4779         return this[fnName](value, allValues);
4780     },
4781     
4782     /**
4783      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4784      * @param {String/HTMLElement/Roo.Element} el The context element
4785      * @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'})
4786      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787      * @return {HTMLElement/Roo.Element} The new node or Element
4788      */
4789     insertFirst: function(el, values, returnElement){
4790         return this.doInsert('afterBegin', el, values, returnElement);
4791     },
4792
4793     /**
4794      * Applies the supplied values to the template and inserts the new node(s) before el.
4795      * @param {String/HTMLElement/Roo.Element} el The context element
4796      * @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'})
4797      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798      * @return {HTMLElement/Roo.Element} The new node or Element
4799      */
4800     insertBefore: function(el, values, returnElement){
4801         return this.doInsert('beforeBegin', el, values, returnElement);
4802     },
4803
4804     /**
4805      * Applies the supplied values to the template and inserts the new node(s) after el.
4806      * @param {String/HTMLElement/Roo.Element} el The context element
4807      * @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'})
4808      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809      * @return {HTMLElement/Roo.Element} The new node or Element
4810      */
4811     insertAfter : function(el, values, returnElement){
4812         return this.doInsert('afterEnd', el, values, returnElement);
4813     },
4814     
4815     /**
4816      * Applies the supplied values to the template and appends the new node(s) to el.
4817      * @param {String/HTMLElement/Roo.Element} el The context element
4818      * @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'})
4819      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820      * @return {HTMLElement/Roo.Element} The new node or Element
4821      */
4822     append : function(el, values, returnElement){
4823         return this.doInsert('beforeEnd', el, values, returnElement);
4824     },
4825
4826     doInsert : function(where, el, values, returnEl){
4827         el = Roo.getDom(el);
4828         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4829         return returnEl ? Roo.get(newNode, true) : newNode;
4830     },
4831
4832     /**
4833      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4834      * @param {String/HTMLElement/Roo.Element} el The context element
4835      * @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'})
4836      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4837      * @return {HTMLElement/Roo.Element} The new node or Element
4838      */
4839     overwrite : function(el, values, returnElement){
4840         el = Roo.getDom(el);
4841         el.innerHTML = this.applyTemplate(values);
4842         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4843     }
4844 };
4845 /**
4846  * Alias for {@link #applyTemplate}
4847  * @method
4848  */
4849 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4850
4851 // backwards compat
4852 Roo.DomHelper.Template = Roo.Template;
4853
4854 /**
4855  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4856  * @param {String/HTMLElement} el A DOM element or its id
4857  * @returns {Roo.Template} The created template
4858  * @static
4859  */
4860 Roo.Template.from = function(el){
4861     el = Roo.getDom(el);
4862     return new Roo.Template(el.value || el.innerHTML);
4863 };/*
4864  * Based on:
4865  * Ext JS Library 1.1.1
4866  * Copyright(c) 2006-2007, Ext JS, LLC.
4867  *
4868  * Originally Released Under LGPL - original licence link has changed is not relivant.
4869  *
4870  * Fork - LGPL
4871  * <script type="text/javascript">
4872  */
4873  
4874
4875 /*
4876  * This is code is also distributed under MIT license for use
4877  * with jQuery and prototype JavaScript libraries.
4878  */
4879 /**
4880  * @class Roo.DomQuery
4881 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).
4882 <p>
4883 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>
4884
4885 <p>
4886 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.
4887 </p>
4888 <h4>Element Selectors:</h4>
4889 <ul class="list">
4890     <li> <b>*</b> any element</li>
4891     <li> <b>E</b> an element with the tag E</li>
4892     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4893     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4894     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4895     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4896 </ul>
4897 <h4>Attribute Selectors:</h4>
4898 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4899 <ul class="list">
4900     <li> <b>E[foo]</b> has an attribute "foo"</li>
4901     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4902     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4903     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4904     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4905     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4906     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4907 </ul>
4908 <h4>Pseudo Classes:</h4>
4909 <ul class="list">
4910     <li> <b>E:first-child</b> E is the first child of its parent</li>
4911     <li> <b>E:last-child</b> E is the last child of its parent</li>
4912     <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>
4913     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4914     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4915     <li> <b>E:only-child</b> E is the only child of its parent</li>
4916     <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>
4917     <li> <b>E:first</b> the first E in the resultset</li>
4918     <li> <b>E:last</b> the last E in the resultset</li>
4919     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4920     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4921     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4922     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4923     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4924     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4925     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4926     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4927     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4928 </ul>
4929 <h4>CSS Value Selectors:</h4>
4930 <ul class="list">
4931     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4932     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4933     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4934     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4935     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4936     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4937 </ul>
4938  * @singleton
4939  */
4940 Roo.DomQuery = function(){
4941     var cache = {}, simpleCache = {}, valueCache = {};
4942     var nonSpace = /\S/;
4943     var trimRe = /^\s+|\s+$/g;
4944     var tplRe = /\{(\d+)\}/g;
4945     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4946     var tagTokenRe = /^(#)?([\w-\*]+)/;
4947     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4948
4949     function child(p, index){
4950         var i = 0;
4951         var n = p.firstChild;
4952         while(n){
4953             if(n.nodeType == 1){
4954                if(++i == index){
4955                    return n;
4956                }
4957             }
4958             n = n.nextSibling;
4959         }
4960         return null;
4961     };
4962
4963     function next(n){
4964         while((n = n.nextSibling) && n.nodeType != 1);
4965         return n;
4966     };
4967
4968     function prev(n){
4969         while((n = n.previousSibling) && n.nodeType != 1);
4970         return n;
4971     };
4972
4973     function children(d){
4974         var n = d.firstChild, ni = -1;
4975             while(n){
4976                 var nx = n.nextSibling;
4977                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4978                     d.removeChild(n);
4979                 }else{
4980                     n.nodeIndex = ++ni;
4981                 }
4982                 n = nx;
4983             }
4984             return this;
4985         };
4986
4987     function byClassName(c, a, v){
4988         if(!v){
4989             return c;
4990         }
4991         var r = [], ri = -1, cn;
4992         for(var i = 0, ci; ci = c[i]; i++){
4993             if((' '+ci.className+' ').indexOf(v) != -1){
4994                 r[++ri] = ci;
4995             }
4996         }
4997         return r;
4998     };
4999
5000     function attrValue(n, attr){
5001         if(!n.tagName && typeof n.length != "undefined"){
5002             n = n[0];
5003         }
5004         if(!n){
5005             return null;
5006         }
5007         if(attr == "for"){
5008             return n.htmlFor;
5009         }
5010         if(attr == "class" || attr == "className"){
5011             return n.className;
5012         }
5013         return n.getAttribute(attr) || n[attr];
5014
5015     };
5016
5017     function getNodes(ns, mode, tagName){
5018         var result = [], ri = -1, cs;
5019         if(!ns){
5020             return result;
5021         }
5022         tagName = tagName || "*";
5023         if(typeof ns.getElementsByTagName != "undefined"){
5024             ns = [ns];
5025         }
5026         if(!mode){
5027             for(var i = 0, ni; ni = ns[i]; i++){
5028                 cs = ni.getElementsByTagName(tagName);
5029                 for(var j = 0, ci; ci = cs[j]; j++){
5030                     result[++ri] = ci;
5031                 }
5032             }
5033         }else if(mode == "/" || mode == ">"){
5034             var utag = tagName.toUpperCase();
5035             for(var i = 0, ni, cn; ni = ns[i]; i++){
5036                 cn = ni.children || ni.childNodes;
5037                 for(var j = 0, cj; cj = cn[j]; j++){
5038                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5039                         result[++ri] = cj;
5040                     }
5041                 }
5042             }
5043         }else if(mode == "+"){
5044             var utag = tagName.toUpperCase();
5045             for(var i = 0, n; n = ns[i]; i++){
5046                 while((n = n.nextSibling) && n.nodeType != 1);
5047                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5048                     result[++ri] = n;
5049                 }
5050             }
5051         }else if(mode == "~"){
5052             for(var i = 0, n; n = ns[i]; i++){
5053                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5054                 if(n){
5055                     result[++ri] = n;
5056                 }
5057             }
5058         }
5059         return result;
5060     };
5061
5062     function concat(a, b){
5063         if(b.slice){
5064             return a.concat(b);
5065         }
5066         for(var i = 0, l = b.length; i < l; i++){
5067             a[a.length] = b[i];
5068         }
5069         return a;
5070     }
5071
5072     function byTag(cs, tagName){
5073         if(cs.tagName || cs == document){
5074             cs = [cs];
5075         }
5076         if(!tagName){
5077             return cs;
5078         }
5079         var r = [], ri = -1;
5080         tagName = tagName.toLowerCase();
5081         for(var i = 0, ci; ci = cs[i]; i++){
5082             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5083                 r[++ri] = ci;
5084             }
5085         }
5086         return r;
5087     };
5088
5089     function byId(cs, attr, id){
5090         if(cs.tagName || cs == document){
5091             cs = [cs];
5092         }
5093         if(!id){
5094             return cs;
5095         }
5096         var r = [], ri = -1;
5097         for(var i = 0,ci; ci = cs[i]; i++){
5098             if(ci && ci.id == id){
5099                 r[++ri] = ci;
5100                 return r;
5101             }
5102         }
5103         return r;
5104     };
5105
5106     function byAttribute(cs, attr, value, op, custom){
5107         var r = [], ri = -1, st = custom=="{";
5108         var f = Roo.DomQuery.operators[op];
5109         for(var i = 0, ci; ci = cs[i]; i++){
5110             var a;
5111             if(st){
5112                 a = Roo.DomQuery.getStyle(ci, attr);
5113             }
5114             else if(attr == "class" || attr == "className"){
5115                 a = ci.className;
5116             }else if(attr == "for"){
5117                 a = ci.htmlFor;
5118             }else if(attr == "href"){
5119                 a = ci.getAttribute("href", 2);
5120             }else{
5121                 a = ci.getAttribute(attr);
5122             }
5123             if((f && f(a, value)) || (!f && a)){
5124                 r[++ri] = ci;
5125             }
5126         }
5127         return r;
5128     };
5129
5130     function byPseudo(cs, name, value){
5131         return Roo.DomQuery.pseudos[name](cs, value);
5132     };
5133
5134     // This is for IE MSXML which does not support expandos.
5135     // IE runs the same speed using setAttribute, however FF slows way down
5136     // and Safari completely fails so they need to continue to use expandos.
5137     var isIE = window.ActiveXObject ? true : false;
5138
5139     // this eval is stop the compressor from
5140     // renaming the variable to something shorter
5141     
5142     /** eval:var:batch */
5143     var batch = 30803; 
5144
5145     var key = 30803;
5146
5147     function nodupIEXml(cs){
5148         var d = ++key;
5149         cs[0].setAttribute("_nodup", d);
5150         var r = [cs[0]];
5151         for(var i = 1, len = cs.length; i < len; i++){
5152             var c = cs[i];
5153             if(!c.getAttribute("_nodup") != d){
5154                 c.setAttribute("_nodup", d);
5155                 r[r.length] = c;
5156             }
5157         }
5158         for(var i = 0, len = cs.length; i < len; i++){
5159             cs[i].removeAttribute("_nodup");
5160         }
5161         return r;
5162     }
5163
5164     function nodup(cs){
5165         if(!cs){
5166             return [];
5167         }
5168         var len = cs.length, c, i, r = cs, cj, ri = -1;
5169         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5170             return cs;
5171         }
5172         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5173             return nodupIEXml(cs);
5174         }
5175         var d = ++key;
5176         cs[0]._nodup = d;
5177         for(i = 1; c = cs[i]; i++){
5178             if(c._nodup != d){
5179                 c._nodup = d;
5180             }else{
5181                 r = [];
5182                 for(var j = 0; j < i; j++){
5183                     r[++ri] = cs[j];
5184                 }
5185                 for(j = i+1; cj = cs[j]; j++){
5186                     if(cj._nodup != d){
5187                         cj._nodup = d;
5188                         r[++ri] = cj;
5189                     }
5190                 }
5191                 return r;
5192             }
5193         }
5194         return r;
5195     }
5196
5197     function quickDiffIEXml(c1, c2){
5198         var d = ++key;
5199         for(var i = 0, len = c1.length; i < len; i++){
5200             c1[i].setAttribute("_qdiff", d);
5201         }
5202         var r = [];
5203         for(var i = 0, len = c2.length; i < len; i++){
5204             if(c2[i].getAttribute("_qdiff") != d){
5205                 r[r.length] = c2[i];
5206             }
5207         }
5208         for(var i = 0, len = c1.length; i < len; i++){
5209            c1[i].removeAttribute("_qdiff");
5210         }
5211         return r;
5212     }
5213
5214     function quickDiff(c1, c2){
5215         var len1 = c1.length;
5216         if(!len1){
5217             return c2;
5218         }
5219         if(isIE && c1[0].selectSingleNode){
5220             return quickDiffIEXml(c1, c2);
5221         }
5222         var d = ++key;
5223         for(var i = 0; i < len1; i++){
5224             c1[i]._qdiff = d;
5225         }
5226         var r = [];
5227         for(var i = 0, len = c2.length; i < len; i++){
5228             if(c2[i]._qdiff != d){
5229                 r[r.length] = c2[i];
5230             }
5231         }
5232         return r;
5233     }
5234
5235     function quickId(ns, mode, root, id){
5236         if(ns == root){
5237            var d = root.ownerDocument || root;
5238            return d.getElementById(id);
5239         }
5240         ns = getNodes(ns, mode, "*");
5241         return byId(ns, null, id);
5242     }
5243
5244     return {
5245         getStyle : function(el, name){
5246             return Roo.fly(el).getStyle(name);
5247         },
5248         /**
5249          * Compiles a selector/xpath query into a reusable function. The returned function
5250          * takes one parameter "root" (optional), which is the context node from where the query should start.
5251          * @param {String} selector The selector/xpath query
5252          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5253          * @return {Function}
5254          */
5255         compile : function(path, type){
5256             type = type || "select";
5257             
5258             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5259             var q = path, mode, lq;
5260             var tk = Roo.DomQuery.matchers;
5261             var tklen = tk.length;
5262             var mm;
5263
5264             // accept leading mode switch
5265             var lmode = q.match(modeRe);
5266             if(lmode && lmode[1]){
5267                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5268                 q = q.replace(lmode[1], "");
5269             }
5270             // strip leading slashes
5271             while(path.substr(0, 1)=="/"){
5272                 path = path.substr(1);
5273             }
5274
5275             while(q && lq != q){
5276                 lq = q;
5277                 var tm = q.match(tagTokenRe);
5278                 if(type == "select"){
5279                     if(tm){
5280                         if(tm[1] == "#"){
5281                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5282                         }else{
5283                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5284                         }
5285                         q = q.replace(tm[0], "");
5286                     }else if(q.substr(0, 1) != '@'){
5287                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5288                     }
5289                 }else{
5290                     if(tm){
5291                         if(tm[1] == "#"){
5292                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5293                         }else{
5294                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5295                         }
5296                         q = q.replace(tm[0], "");
5297                     }
5298                 }
5299                 while(!(mm = q.match(modeRe))){
5300                     var matched = false;
5301                     for(var j = 0; j < tklen; j++){
5302                         var t = tk[j];
5303                         var m = q.match(t.re);
5304                         if(m){
5305                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5306                                                     return m[i];
5307                                                 });
5308                             q = q.replace(m[0], "");
5309                             matched = true;
5310                             break;
5311                         }
5312                     }
5313                     // prevent infinite loop on bad selector
5314                     if(!matched){
5315                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5316                     }
5317                 }
5318                 if(mm[1]){
5319                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5320                     q = q.replace(mm[1], "");
5321                 }
5322             }
5323             fn[fn.length] = "return nodup(n);\n}";
5324             
5325              /** 
5326               * list of variables that need from compression as they are used by eval.
5327              *  eval:var:batch 
5328              *  eval:var:nodup
5329              *  eval:var:byTag
5330              *  eval:var:ById
5331              *  eval:var:getNodes
5332              *  eval:var:quickId
5333              *  eval:var:mode
5334              *  eval:var:root
5335              *  eval:var:n
5336              *  eval:var:byClassName
5337              *  eval:var:byPseudo
5338              *  eval:var:byAttribute
5339              *  eval:var:attrValue
5340              * 
5341              **/ 
5342             eval(fn.join(""));
5343             return f;
5344         },
5345
5346         /**
5347          * Selects a group of elements.
5348          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5349          * @param {Node} root (optional) The start of the query (defaults to document).
5350          * @return {Array}
5351          */
5352         select : function(path, root, type){
5353             if(!root || root == document){
5354                 root = document;
5355             }
5356             if(typeof root == "string"){
5357                 root = document.getElementById(root);
5358             }
5359             var paths = path.split(",");
5360             var results = [];
5361             for(var i = 0, len = paths.length; i < len; i++){
5362                 var p = paths[i].replace(trimRe, "");
5363                 if(!cache[p]){
5364                     cache[p] = Roo.DomQuery.compile(p);
5365                     if(!cache[p]){
5366                         throw p + " is not a valid selector";
5367                     }
5368                 }
5369                 var result = cache[p](root);
5370                 if(result && result != document){
5371                     results = results.concat(result);
5372                 }
5373             }
5374             if(paths.length > 1){
5375                 return nodup(results);
5376             }
5377             return results;
5378         },
5379
5380         /**
5381          * Selects a single element.
5382          * @param {String} selector The selector/xpath query
5383          * @param {Node} root (optional) The start of the query (defaults to document).
5384          * @return {Element}
5385          */
5386         selectNode : function(path, root){
5387             return Roo.DomQuery.select(path, root)[0];
5388         },
5389
5390         /**
5391          * Selects the value of a node, optionally replacing null with the defaultValue.
5392          * @param {String} selector The selector/xpath query
5393          * @param {Node} root (optional) The start of the query (defaults to document).
5394          * @param {String} defaultValue
5395          */
5396         selectValue : function(path, root, defaultValue){
5397             path = path.replace(trimRe, "");
5398             if(!valueCache[path]){
5399                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5400             }
5401             var n = valueCache[path](root);
5402             n = n[0] ? n[0] : n;
5403             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5404             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5405         },
5406
5407         /**
5408          * Selects the value of a node, parsing integers and floats.
5409          * @param {String} selector The selector/xpath query
5410          * @param {Node} root (optional) The start of the query (defaults to document).
5411          * @param {Number} defaultValue
5412          * @return {Number}
5413          */
5414         selectNumber : function(path, root, defaultValue){
5415             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5416             return parseFloat(v);
5417         },
5418
5419         /**
5420          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5421          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5422          * @param {String} selector The simple selector to test
5423          * @return {Boolean}
5424          */
5425         is : function(el, ss){
5426             if(typeof el == "string"){
5427                 el = document.getElementById(el);
5428             }
5429             var isArray = (el instanceof Array);
5430             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5431             return isArray ? (result.length == el.length) : (result.length > 0);
5432         },
5433
5434         /**
5435          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5436          * @param {Array} el An array of elements to filter
5437          * @param {String} selector The simple selector to test
5438          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5439          * the selector instead of the ones that match
5440          * @return {Array}
5441          */
5442         filter : function(els, ss, nonMatches){
5443             ss = ss.replace(trimRe, "");
5444             if(!simpleCache[ss]){
5445                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5446             }
5447             var result = simpleCache[ss](els);
5448             return nonMatches ? quickDiff(result, els) : result;
5449         },
5450
5451         /**
5452          * Collection of matching regular expressions and code snippets.
5453          */
5454         matchers : [{
5455                 re: /^\.([\w-]+)/,
5456                 select: 'n = byClassName(n, null, " {1} ");'
5457             }, {
5458                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5459                 select: 'n = byPseudo(n, "{1}", "{2}");'
5460             },{
5461                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5462                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5463             }, {
5464                 re: /^#([\w-]+)/,
5465                 select: 'n = byId(n, null, "{1}");'
5466             },{
5467                 re: /^@([\w-]+)/,
5468                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5469             }
5470         ],
5471
5472         /**
5473          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5474          * 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;.
5475          */
5476         operators : {
5477             "=" : function(a, v){
5478                 return a == v;
5479             },
5480             "!=" : function(a, v){
5481                 return a != v;
5482             },
5483             "^=" : function(a, v){
5484                 return a && a.substr(0, v.length) == v;
5485             },
5486             "$=" : function(a, v){
5487                 return a && a.substr(a.length-v.length) == v;
5488             },
5489             "*=" : function(a, v){
5490                 return a && a.indexOf(v) !== -1;
5491             },
5492             "%=" : function(a, v){
5493                 return (a % v) == 0;
5494             },
5495             "|=" : function(a, v){
5496                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5497             },
5498             "~=" : function(a, v){
5499                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5500             }
5501         },
5502
5503         /**
5504          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5505          * and the argument (if any) supplied in the selector.
5506          */
5507         pseudos : {
5508             "first-child" : function(c){
5509                 var r = [], ri = -1, n;
5510                 for(var i = 0, ci; ci = n = c[i]; i++){
5511                     while((n = n.previousSibling) && n.nodeType != 1);
5512                     if(!n){
5513                         r[++ri] = ci;
5514                     }
5515                 }
5516                 return r;
5517             },
5518
5519             "last-child" : function(c){
5520                 var r = [], ri = -1, n;
5521                 for(var i = 0, ci; ci = n = c[i]; i++){
5522                     while((n = n.nextSibling) && n.nodeType != 1);
5523                     if(!n){
5524                         r[++ri] = ci;
5525                     }
5526                 }
5527                 return r;
5528             },
5529
5530             "nth-child" : function(c, a) {
5531                 var r = [], ri = -1;
5532                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5533                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5534                 for(var i = 0, n; n = c[i]; i++){
5535                     var pn = n.parentNode;
5536                     if (batch != pn._batch) {
5537                         var j = 0;
5538                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5539                             if(cn.nodeType == 1){
5540                                cn.nodeIndex = ++j;
5541                             }
5542                         }
5543                         pn._batch = batch;
5544                     }
5545                     if (f == 1) {
5546                         if (l == 0 || n.nodeIndex == l){
5547                             r[++ri] = n;
5548                         }
5549                     } else if ((n.nodeIndex + l) % f == 0){
5550                         r[++ri] = n;
5551                     }
5552                 }
5553
5554                 return r;
5555             },
5556
5557             "only-child" : function(c){
5558                 var r = [], ri = -1;;
5559                 for(var i = 0, ci; ci = c[i]; i++){
5560                     if(!prev(ci) && !next(ci)){
5561                         r[++ri] = ci;
5562                     }
5563                 }
5564                 return r;
5565             },
5566
5567             "empty" : function(c){
5568                 var r = [], ri = -1;
5569                 for(var i = 0, ci; ci = c[i]; i++){
5570                     var cns = ci.childNodes, j = 0, cn, empty = true;
5571                     while(cn = cns[j]){
5572                         ++j;
5573                         if(cn.nodeType == 1 || cn.nodeType == 3){
5574                             empty = false;
5575                             break;
5576                         }
5577                     }
5578                     if(empty){
5579                         r[++ri] = ci;
5580                     }
5581                 }
5582                 return r;
5583             },
5584
5585             "contains" : function(c, v){
5586                 var r = [], ri = -1;
5587                 for(var i = 0, ci; ci = c[i]; i++){
5588                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5589                         r[++ri] = ci;
5590                     }
5591                 }
5592                 return r;
5593             },
5594
5595             "nodeValue" : function(c, v){
5596                 var r = [], ri = -1;
5597                 for(var i = 0, ci; ci = c[i]; i++){
5598                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5599                         r[++ri] = ci;
5600                     }
5601                 }
5602                 return r;
5603             },
5604
5605             "checked" : function(c){
5606                 var r = [], ri = -1;
5607                 for(var i = 0, ci; ci = c[i]; i++){
5608                     if(ci.checked == true){
5609                         r[++ri] = ci;
5610                     }
5611                 }
5612                 return r;
5613             },
5614
5615             "not" : function(c, ss){
5616                 return Roo.DomQuery.filter(c, ss, true);
5617             },
5618
5619             "odd" : function(c){
5620                 return this["nth-child"](c, "odd");
5621             },
5622
5623             "even" : function(c){
5624                 return this["nth-child"](c, "even");
5625             },
5626
5627             "nth" : function(c, a){
5628                 return c[a-1] || [];
5629             },
5630
5631             "first" : function(c){
5632                 return c[0] || [];
5633             },
5634
5635             "last" : function(c){
5636                 return c[c.length-1] || [];
5637             },
5638
5639             "has" : function(c, ss){
5640                 var s = Roo.DomQuery.select;
5641                 var r = [], ri = -1;
5642                 for(var i = 0, ci; ci = c[i]; i++){
5643                     if(s(ss, ci).length > 0){
5644                         r[++ri] = ci;
5645                     }
5646                 }
5647                 return r;
5648             },
5649
5650             "next" : function(c, ss){
5651                 var is = Roo.DomQuery.is;
5652                 var r = [], ri = -1;
5653                 for(var i = 0, ci; ci = c[i]; i++){
5654                     var n = next(ci);
5655                     if(n && is(n, ss)){
5656                         r[++ri] = ci;
5657                     }
5658                 }
5659                 return r;
5660             },
5661
5662             "prev" : function(c, ss){
5663                 var is = Roo.DomQuery.is;
5664                 var r = [], ri = -1;
5665                 for(var i = 0, ci; ci = c[i]; i++){
5666                     var n = prev(ci);
5667                     if(n && is(n, ss)){
5668                         r[++ri] = ci;
5669                     }
5670                 }
5671                 return r;
5672             }
5673         }
5674     };
5675 }();
5676
5677 /**
5678  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5679  * @param {String} path The selector/xpath query
5680  * @param {Node} root (optional) The start of the query (defaults to document).
5681  * @return {Array}
5682  * @member Roo
5683  * @method query
5684  */
5685 Roo.query = Roo.DomQuery.select;
5686 /*
5687  * Based on:
5688  * Ext JS Library 1.1.1
5689  * Copyright(c) 2006-2007, Ext JS, LLC.
5690  *
5691  * Originally Released Under LGPL - original licence link has changed is not relivant.
5692  *
5693  * Fork - LGPL
5694  * <script type="text/javascript">
5695  */
5696
5697 /**
5698  * @class Roo.util.Observable
5699  * Base class that provides a common interface for publishing events. Subclasses are expected to
5700  * to have a property "events" with all the events defined.<br>
5701  * For example:
5702  * <pre><code>
5703  Employee = function(name){
5704     this.name = name;
5705     this.addEvents({
5706         "fired" : true,
5707         "quit" : true
5708     });
5709  }
5710  Roo.extend(Employee, Roo.util.Observable);
5711 </code></pre>
5712  * @param {Object} config properties to use (incuding events / listeners)
5713  */
5714
5715 Roo.util.Observable = function(cfg){
5716     
5717     cfg = cfg|| {};
5718     this.addEvents(cfg.events || {});
5719     if (cfg.events) {
5720         delete cfg.events; // make sure
5721     }
5722      
5723     Roo.apply(this, cfg);
5724     
5725     if(this.listeners){
5726         this.on(this.listeners);
5727         delete this.listeners;
5728     }
5729 };
5730 Roo.util.Observable.prototype = {
5731     /** 
5732  * @cfg {Object} listeners  list of events and functions to call for this object, 
5733  * For example :
5734  * <pre><code>
5735     listeners :  { 
5736        'click' : function(e) {
5737            ..... 
5738         } ,
5739         .... 
5740     } 
5741   </code></pre>
5742  */
5743     
5744     
5745     /**
5746      * Fires the specified event with the passed parameters (minus the event name).
5747      * @param {String} eventName
5748      * @param {Object...} args Variable number of parameters are passed to handlers
5749      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5750      */
5751     fireEvent : function(){
5752         var ce = this.events[arguments[0].toLowerCase()];
5753         if(typeof ce == "object"){
5754             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5755         }else{
5756             return true;
5757         }
5758     },
5759
5760     // private
5761     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5762
5763     /**
5764      * Appends an event handler to this component
5765      * @param {String}   eventName The type of event to listen for
5766      * @param {Function} handler The method the event invokes
5767      * @param {Object}   scope (optional) The scope in which to execute the handler
5768      * function. The handler function's "this" context.
5769      * @param {Object}   options (optional) An object containing handler configuration
5770      * properties. This may contain any of the following properties:<ul>
5771      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5772      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5773      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5774      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5775      * by the specified number of milliseconds. If the event fires again within that time, the original
5776      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5777      * </ul><br>
5778      * <p>
5779      * <b>Combining Options</b><br>
5780      * Using the options argument, it is possible to combine different types of listeners:<br>
5781      * <br>
5782      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5783                 <pre><code>
5784                 el.on('click', this.onClick, this, {
5785                         single: true,
5786                 delay: 100,
5787                 forumId: 4
5788                 });
5789                 </code></pre>
5790      * <p>
5791      * <b>Attaching multiple handlers in 1 call</b><br>
5792      * The method also allows for a single argument to be passed which is a config object containing properties
5793      * which specify multiple handlers.
5794      * <pre><code>
5795                 el.on({
5796                         'click': {
5797                         fn: this.onClick,
5798                         scope: this,
5799                         delay: 100
5800                 }, 
5801                 'mouseover': {
5802                         fn: this.onMouseOver,
5803                         scope: this
5804                 },
5805                 'mouseout': {
5806                         fn: this.onMouseOut,
5807                         scope: this
5808                 }
5809                 });
5810                 </code></pre>
5811      * <p>
5812      * Or a shorthand syntax which passes the same scope object to all handlers:
5813         <pre><code>
5814                 el.on({
5815                         'click': this.onClick,
5816                 'mouseover': this.onMouseOver,
5817                 'mouseout': this.onMouseOut,
5818                 scope: this
5819                 });
5820                 </code></pre>
5821      */
5822     addListener : function(eventName, fn, scope, o){
5823         if(typeof eventName == "object"){
5824             o = eventName;
5825             for(var e in o){
5826                 if(this.filterOptRe.test(e)){
5827                     continue;
5828                 }
5829                 if(typeof o[e] == "function"){
5830                     // shared options
5831                     this.addListener(e, o[e], o.scope,  o);
5832                 }else{
5833                     // individual options
5834                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5835                 }
5836             }
5837             return;
5838         }
5839         o = (!o || typeof o == "boolean") ? {} : o;
5840         eventName = eventName.toLowerCase();
5841         var ce = this.events[eventName] || true;
5842         if(typeof ce == "boolean"){
5843             ce = new Roo.util.Event(this, eventName);
5844             this.events[eventName] = ce;
5845         }
5846         ce.addListener(fn, scope, o);
5847     },
5848
5849     /**
5850      * Removes a listener
5851      * @param {String}   eventName     The type of event to listen for
5852      * @param {Function} handler        The handler to remove
5853      * @param {Object}   scope  (optional) The scope (this object) for the handler
5854      */
5855     removeListener : function(eventName, fn, scope){
5856         var ce = this.events[eventName.toLowerCase()];
5857         if(typeof ce == "object"){
5858             ce.removeListener(fn, scope);
5859         }
5860     },
5861
5862     /**
5863      * Removes all listeners for this object
5864      */
5865     purgeListeners : function(){
5866         for(var evt in this.events){
5867             if(typeof this.events[evt] == "object"){
5868                  this.events[evt].clearListeners();
5869             }
5870         }
5871     },
5872
5873     relayEvents : function(o, events){
5874         var createHandler = function(ename){
5875             return function(){
5876                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5877             };
5878         };
5879         for(var i = 0, len = events.length; i < len; i++){
5880             var ename = events[i];
5881             if(!this.events[ename]){ this.events[ename] = true; };
5882             o.on(ename, createHandler(ename), this);
5883         }
5884     },
5885
5886     /**
5887      * Used to define events on this Observable
5888      * @param {Object} object The object with the events defined
5889      */
5890     addEvents : function(o){
5891         if(!this.events){
5892             this.events = {};
5893         }
5894         Roo.applyIf(this.events, o);
5895     },
5896
5897     /**
5898      * Checks to see if this object has any listeners for a specified event
5899      * @param {String} eventName The name of the event to check for
5900      * @return {Boolean} True if the event is being listened for, else false
5901      */
5902     hasListener : function(eventName){
5903         var e = this.events[eventName];
5904         return typeof e == "object" && e.listeners.length > 0;
5905     }
5906 };
5907 /**
5908  * Appends an event handler to this element (shorthand for addListener)
5909  * @param {String}   eventName     The type of event to listen for
5910  * @param {Function} handler        The method the event invokes
5911  * @param {Object}   scope (optional) The scope in which to execute the handler
5912  * function. The handler function's "this" context.
5913  * @param {Object}   options  (optional)
5914  * @method
5915  */
5916 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5917 /**
5918  * Removes a listener (shorthand for removeListener)
5919  * @param {String}   eventName     The type of event to listen for
5920  * @param {Function} handler        The handler to remove
5921  * @param {Object}   scope  (optional) The scope (this object) for the handler
5922  * @method
5923  */
5924 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5925
5926 /**
5927  * Starts capture on the specified Observable. All events will be passed
5928  * to the supplied function with the event name + standard signature of the event
5929  * <b>before</b> the event is fired. If the supplied function returns false,
5930  * the event will not fire.
5931  * @param {Observable} o The Observable to capture
5932  * @param {Function} fn The function to call
5933  * @param {Object} scope (optional) The scope (this object) for the fn
5934  * @static
5935  */
5936 Roo.util.Observable.capture = function(o, fn, scope){
5937     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5938 };
5939
5940 /**
5941  * Removes <b>all</b> added captures from the Observable.
5942  * @param {Observable} o The Observable to release
5943  * @static
5944  */
5945 Roo.util.Observable.releaseCapture = function(o){
5946     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5947 };
5948
5949 (function(){
5950
5951     var createBuffered = function(h, o, scope){
5952         var task = new Roo.util.DelayedTask();
5953         return function(){
5954             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5955         };
5956     };
5957
5958     var createSingle = function(h, e, fn, scope){
5959         return function(){
5960             e.removeListener(fn, scope);
5961             return h.apply(scope, arguments);
5962         };
5963     };
5964
5965     var createDelayed = function(h, o, scope){
5966         return function(){
5967             var args = Array.prototype.slice.call(arguments, 0);
5968             setTimeout(function(){
5969                 h.apply(scope, args);
5970             }, o.delay || 10);
5971         };
5972     };
5973
5974     Roo.util.Event = function(obj, name){
5975         this.name = name;
5976         this.obj = obj;
5977         this.listeners = [];
5978     };
5979
5980     Roo.util.Event.prototype = {
5981         addListener : function(fn, scope, options){
5982             var o = options || {};
5983             scope = scope || this.obj;
5984             if(!this.isListening(fn, scope)){
5985                 var l = {fn: fn, scope: scope, options: o};
5986                 var h = fn;
5987                 if(o.delay){
5988                     h = createDelayed(h, o, scope);
5989                 }
5990                 if(o.single){
5991                     h = createSingle(h, this, fn, scope);
5992                 }
5993                 if(o.buffer){
5994                     h = createBuffered(h, o, scope);
5995                 }
5996                 l.fireFn = h;
5997                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5998                     this.listeners.push(l);
5999                 }else{
6000                     this.listeners = this.listeners.slice(0);
6001                     this.listeners.push(l);
6002                 }
6003             }
6004         },
6005
6006         findListener : function(fn, scope){
6007             scope = scope || this.obj;
6008             var ls = this.listeners;
6009             for(var i = 0, len = ls.length; i < len; i++){
6010                 var l = ls[i];
6011                 if(l.fn == fn && l.scope == scope){
6012                     return i;
6013                 }
6014             }
6015             return -1;
6016         },
6017
6018         isListening : function(fn, scope){
6019             return this.findListener(fn, scope) != -1;
6020         },
6021
6022         removeListener : function(fn, scope){
6023             var index;
6024             if((index = this.findListener(fn, scope)) != -1){
6025                 if(!this.firing){
6026                     this.listeners.splice(index, 1);
6027                 }else{
6028                     this.listeners = this.listeners.slice(0);
6029                     this.listeners.splice(index, 1);
6030                 }
6031                 return true;
6032             }
6033             return false;
6034         },
6035
6036         clearListeners : function(){
6037             this.listeners = [];
6038         },
6039
6040         fire : function(){
6041             var ls = this.listeners, scope, len = ls.length;
6042             if(len > 0){
6043                 this.firing = true;
6044                 var args = Array.prototype.slice.call(arguments, 0);
6045                 for(var i = 0; i < len; i++){
6046                     var l = ls[i];
6047                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6048                         this.firing = false;
6049                         return false;
6050                     }
6051                 }
6052                 this.firing = false;
6053             }
6054             return true;
6055         }
6056     };
6057 })();/*
6058  * RooJS Library 
6059  * Copyright(c) 2007-2017, Roo J Solutions Ltd
6060  *
6061  * Licence LGPL 
6062  *
6063  */
6064  
6065 /**
6066  * @class Roo.Document
6067  * @extends Roo.util.Observable
6068  * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6069  * 
6070  * @param {Object} config the methods and properties of the 'base' class for the application.
6071  * 
6072  *  Generic Page handler - implement this to start your app..
6073  * 
6074  * eg.
6075  *  MyProject = new Roo.Document({
6076         events : {
6077             'load' : true // your events..
6078         },
6079         listeners : {
6080             'ready' : function() {
6081                 // fired on Roo.onReady()
6082             }
6083         }
6084  * 
6085  */
6086 Roo.Document = function(cfg) {
6087      
6088     this.addEvents({ 
6089         'ready' : true
6090     });
6091     Roo.util.Observable.call(this,cfg);
6092     
6093     var _this = this;
6094     
6095     Roo.onReady(function() {
6096         _this.fireEvent('ready');
6097     },null,false);
6098     
6099     
6100 }
6101
6102 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6103  * Based on:
6104  * Ext JS Library 1.1.1
6105  * Copyright(c) 2006-2007, Ext JS, LLC.
6106  *
6107  * Originally Released Under LGPL - original licence link has changed is not relivant.
6108  *
6109  * Fork - LGPL
6110  * <script type="text/javascript">
6111  */
6112
6113 /**
6114  * @class Roo.EventManager
6115  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6116  * several useful events directly.
6117  * See {@link Roo.EventObject} for more details on normalized event objects.
6118  * @singleton
6119  */
6120 Roo.EventManager = function(){
6121     var docReadyEvent, docReadyProcId, docReadyState = false;
6122     var resizeEvent, resizeTask, textEvent, textSize;
6123     var E = Roo.lib.Event;
6124     var D = Roo.lib.Dom;
6125
6126     
6127     
6128
6129     var fireDocReady = function(){
6130         if(!docReadyState){
6131             docReadyState = true;
6132             Roo.isReady = true;
6133             if(docReadyProcId){
6134                 clearInterval(docReadyProcId);
6135             }
6136             if(Roo.isGecko || Roo.isOpera) {
6137                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6138             }
6139             if(Roo.isIE){
6140                 var defer = document.getElementById("ie-deferred-loader");
6141                 if(defer){
6142                     defer.onreadystatechange = null;
6143                     defer.parentNode.removeChild(defer);
6144                 }
6145             }
6146             if(docReadyEvent){
6147                 docReadyEvent.fire();
6148                 docReadyEvent.clearListeners();
6149             }
6150         }
6151     };
6152     
6153     var initDocReady = function(){
6154         docReadyEvent = new Roo.util.Event();
6155         if(Roo.isGecko || Roo.isOpera) {
6156             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6157         }else if(Roo.isIE){
6158             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6159             var defer = document.getElementById("ie-deferred-loader");
6160             defer.onreadystatechange = function(){
6161                 if(this.readyState == "complete"){
6162                     fireDocReady();
6163                 }
6164             };
6165         }else if(Roo.isSafari){ 
6166             docReadyProcId = setInterval(function(){
6167                 var rs = document.readyState;
6168                 if(rs == "complete") {
6169                     fireDocReady();     
6170                  }
6171             }, 10);
6172         }
6173         // no matter what, make sure it fires on load
6174         E.on(window, "load", fireDocReady);
6175     };
6176
6177     var createBuffered = function(h, o){
6178         var task = new Roo.util.DelayedTask(h);
6179         return function(e){
6180             // create new event object impl so new events don't wipe out properties
6181             e = new Roo.EventObjectImpl(e);
6182             task.delay(o.buffer, h, null, [e]);
6183         };
6184     };
6185
6186     var createSingle = function(h, el, ename, fn){
6187         return function(e){
6188             Roo.EventManager.removeListener(el, ename, fn);
6189             h(e);
6190         };
6191     };
6192
6193     var createDelayed = function(h, o){
6194         return function(e){
6195             // create new event object impl so new events don't wipe out properties
6196             e = new Roo.EventObjectImpl(e);
6197             setTimeout(function(){
6198                 h(e);
6199             }, o.delay || 10);
6200         };
6201     };
6202     var transitionEndVal = false;
6203     
6204     var transitionEnd = function()
6205     {
6206         if (transitionEndVal) {
6207             return transitionEndVal;
6208         }
6209         var el = document.createElement('div');
6210
6211         var transEndEventNames = {
6212             WebkitTransition : 'webkitTransitionEnd',
6213             MozTransition    : 'transitionend',
6214             OTransition      : 'oTransitionEnd otransitionend',
6215             transition       : 'transitionend'
6216         };
6217     
6218         for (var name in transEndEventNames) {
6219             if (el.style[name] !== undefined) {
6220                 transitionEndVal = transEndEventNames[name];
6221                 return  transitionEndVal ;
6222             }
6223         }
6224     }
6225     
6226
6227     var listen = function(element, ename, opt, fn, scope){
6228         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6229         fn = fn || o.fn; scope = scope || o.scope;
6230         var el = Roo.getDom(element);
6231         
6232         
6233         if(!el){
6234             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6235         }
6236         
6237         if (ename == 'transitionend') {
6238             ename = transitionEnd();
6239         }
6240         var h = function(e){
6241             e = Roo.EventObject.setEvent(e);
6242             var t;
6243             if(o.delegate){
6244                 t = e.getTarget(o.delegate, el);
6245                 if(!t){
6246                     return;
6247                 }
6248             }else{
6249                 t = e.target;
6250             }
6251             if(o.stopEvent === true){
6252                 e.stopEvent();
6253             }
6254             if(o.preventDefault === true){
6255                e.preventDefault();
6256             }
6257             if(o.stopPropagation === true){
6258                 e.stopPropagation();
6259             }
6260
6261             if(o.normalized === false){
6262                 e = e.browserEvent;
6263             }
6264
6265             fn.call(scope || el, e, t, o);
6266         };
6267         if(o.delay){
6268             h = createDelayed(h, o);
6269         }
6270         if(o.single){
6271             h = createSingle(h, el, ename, fn);
6272         }
6273         if(o.buffer){
6274             h = createBuffered(h, o);
6275         }
6276         fn._handlers = fn._handlers || [];
6277         
6278         
6279         fn._handlers.push([Roo.id(el), ename, h]);
6280         
6281         
6282          
6283         E.on(el, ename, h);
6284         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6285             el.addEventListener("DOMMouseScroll", h, false);
6286             E.on(window, 'unload', function(){
6287                 el.removeEventListener("DOMMouseScroll", h, false);
6288             });
6289         }
6290         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6291             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6292         }
6293         return h;
6294     };
6295
6296     var stopListening = function(el, ename, fn){
6297         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6298         if(hds){
6299             for(var i = 0, len = hds.length; i < len; i++){
6300                 var h = hds[i];
6301                 if(h[0] == id && h[1] == ename){
6302                     hd = h[2];
6303                     hds.splice(i, 1);
6304                     break;
6305                 }
6306             }
6307         }
6308         E.un(el, ename, hd);
6309         el = Roo.getDom(el);
6310         if(ename == "mousewheel" && el.addEventListener){
6311             el.removeEventListener("DOMMouseScroll", hd, false);
6312         }
6313         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6314             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6315         }
6316     };
6317
6318     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6319     
6320     var pub = {
6321         
6322         
6323         /** 
6324          * Fix for doc tools
6325          * @scope Roo.EventManager
6326          */
6327         
6328         
6329         /** 
6330          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6331          * object with a Roo.EventObject
6332          * @param {Function} fn        The method the event invokes
6333          * @param {Object}   scope    An object that becomes the scope of the handler
6334          * @param {boolean}  override If true, the obj passed in becomes
6335          *                             the execution scope of the listener
6336          * @return {Function} The wrapped function
6337          * @deprecated
6338          */
6339         wrap : function(fn, scope, override){
6340             return function(e){
6341                 Roo.EventObject.setEvent(e);
6342                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6343             };
6344         },
6345         
6346         /**
6347      * Appends an event handler to an element (shorthand for addListener)
6348      * @param {String/HTMLElement}   element        The html element or id to assign the
6349      * @param {String}   eventName The type of event to listen for
6350      * @param {Function} handler The method the event invokes
6351      * @param {Object}   scope (optional) The scope in which to execute the handler
6352      * function. The handler function's "this" context.
6353      * @param {Object}   options (optional) An object containing handler configuration
6354      * properties. This may contain any of the following properties:<ul>
6355      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6356      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6357      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6358      * <li>preventDefault {Boolean} True to prevent the default action</li>
6359      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6360      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6361      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6362      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6363      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6364      * by the specified number of milliseconds. If the event fires again within that time, the original
6365      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6366      * </ul><br>
6367      * <p>
6368      * <b>Combining Options</b><br>
6369      * Using the options argument, it is possible to combine different types of listeners:<br>
6370      * <br>
6371      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6372      * Code:<pre><code>
6373 el.on('click', this.onClick, this, {
6374     single: true,
6375     delay: 100,
6376     stopEvent : true,
6377     forumId: 4
6378 });</code></pre>
6379      * <p>
6380      * <b>Attaching multiple handlers in 1 call</b><br>
6381       * The method also allows for a single argument to be passed which is a config object containing properties
6382      * which specify multiple handlers.
6383      * <p>
6384      * Code:<pre><code>
6385 el.on({
6386     'click' : {
6387         fn: this.onClick
6388         scope: this,
6389         delay: 100
6390     },
6391     'mouseover' : {
6392         fn: this.onMouseOver
6393         scope: this
6394     },
6395     'mouseout' : {
6396         fn: this.onMouseOut
6397         scope: this
6398     }
6399 });</code></pre>
6400      * <p>
6401      * Or a shorthand syntax:<br>
6402      * Code:<pre><code>
6403 el.on({
6404     'click' : this.onClick,
6405     'mouseover' : this.onMouseOver,
6406     'mouseout' : this.onMouseOut
6407     scope: this
6408 });</code></pre>
6409      */
6410         addListener : function(element, eventName, fn, scope, options){
6411             if(typeof eventName == "object"){
6412                 var o = eventName;
6413                 for(var e in o){
6414                     if(propRe.test(e)){
6415                         continue;
6416                     }
6417                     if(typeof o[e] == "function"){
6418                         // shared options
6419                         listen(element, e, o, o[e], o.scope);
6420                     }else{
6421                         // individual options
6422                         listen(element, e, o[e]);
6423                     }
6424                 }
6425                 return;
6426             }
6427             return listen(element, eventName, options, fn, scope);
6428         },
6429         
6430         /**
6431          * Removes an event handler
6432          *
6433          * @param {String/HTMLElement}   element        The id or html element to remove the 
6434          *                             event from
6435          * @param {String}   eventName     The type of event
6436          * @param {Function} fn
6437          * @return {Boolean} True if a listener was actually removed
6438          */
6439         removeListener : function(element, eventName, fn){
6440             return stopListening(element, eventName, fn);
6441         },
6442         
6443         /**
6444          * Fires when the document is ready (before onload and before images are loaded). Can be 
6445          * accessed shorthanded Roo.onReady().
6446          * @param {Function} fn        The method the event invokes
6447          * @param {Object}   scope    An  object that becomes the scope of the handler
6448          * @param {boolean}  options
6449          */
6450         onDocumentReady : function(fn, scope, options){
6451             if(docReadyState){ // if it already fired
6452                 docReadyEvent.addListener(fn, scope, options);
6453                 docReadyEvent.fire();
6454                 docReadyEvent.clearListeners();
6455                 return;
6456             }
6457             if(!docReadyEvent){
6458                 initDocReady();
6459             }
6460             docReadyEvent.addListener(fn, scope, options);
6461         },
6462         
6463         /**
6464          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6465          * @param {Function} fn        The method the event invokes
6466          * @param {Object}   scope    An object that becomes the scope of the handler
6467          * @param {boolean}  options
6468          */
6469         onWindowResize : function(fn, scope, options){
6470             if(!resizeEvent){
6471                 resizeEvent = new Roo.util.Event();
6472                 resizeTask = new Roo.util.DelayedTask(function(){
6473                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6474                 });
6475                 E.on(window, "resize", function(){
6476                     if(Roo.isIE){
6477                         resizeTask.delay(50);
6478                     }else{
6479                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6480                     }
6481                 });
6482             }
6483             resizeEvent.addListener(fn, scope, options);
6484         },
6485
6486         /**
6487          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6488          * @param {Function} fn        The method the event invokes
6489          * @param {Object}   scope    An object that becomes the scope of the handler
6490          * @param {boolean}  options
6491          */
6492         onTextResize : function(fn, scope, options){
6493             if(!textEvent){
6494                 textEvent = new Roo.util.Event();
6495                 var textEl = new Roo.Element(document.createElement('div'));
6496                 textEl.dom.className = 'x-text-resize';
6497                 textEl.dom.innerHTML = 'X';
6498                 textEl.appendTo(document.body);
6499                 textSize = textEl.dom.offsetHeight;
6500                 setInterval(function(){
6501                     if(textEl.dom.offsetHeight != textSize){
6502                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6503                     }
6504                 }, this.textResizeInterval);
6505             }
6506             textEvent.addListener(fn, scope, options);
6507         },
6508
6509         /**
6510          * Removes the passed window resize listener.
6511          * @param {Function} fn        The method the event invokes
6512          * @param {Object}   scope    The scope of handler
6513          */
6514         removeResizeListener : function(fn, scope){
6515             if(resizeEvent){
6516                 resizeEvent.removeListener(fn, scope);
6517             }
6518         },
6519
6520         // private
6521         fireResize : function(){
6522             if(resizeEvent){
6523                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6524             }   
6525         },
6526         /**
6527          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6528          */
6529         ieDeferSrc : false,
6530         /**
6531          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6532          */
6533         textResizeInterval : 50
6534     };
6535     
6536     /**
6537      * Fix for doc tools
6538      * @scopeAlias pub=Roo.EventManager
6539      */
6540     
6541      /**
6542      * Appends an event handler to an element (shorthand for addListener)
6543      * @param {String/HTMLElement}   element        The html element or id to assign the
6544      * @param {String}   eventName The type of event to listen for
6545      * @param {Function} handler The method the event invokes
6546      * @param {Object}   scope (optional) The scope in which to execute the handler
6547      * function. The handler function's "this" context.
6548      * @param {Object}   options (optional) An object containing handler configuration
6549      * properties. This may contain any of the following properties:<ul>
6550      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6551      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6552      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6553      * <li>preventDefault {Boolean} True to prevent the default action</li>
6554      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6555      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6556      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6557      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6558      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6559      * by the specified number of milliseconds. If the event fires again within that time, the original
6560      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6561      * </ul><br>
6562      * <p>
6563      * <b>Combining Options</b><br>
6564      * Using the options argument, it is possible to combine different types of listeners:<br>
6565      * <br>
6566      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6567      * Code:<pre><code>
6568 el.on('click', this.onClick, this, {
6569     single: true,
6570     delay: 100,
6571     stopEvent : true,
6572     forumId: 4
6573 });</code></pre>
6574      * <p>
6575      * <b>Attaching multiple handlers in 1 call</b><br>
6576       * The method also allows for a single argument to be passed which is a config object containing properties
6577      * which specify multiple handlers.
6578      * <p>
6579      * Code:<pre><code>
6580 el.on({
6581     'click' : {
6582         fn: this.onClick
6583         scope: this,
6584         delay: 100
6585     },
6586     'mouseover' : {
6587         fn: this.onMouseOver
6588         scope: this
6589     },
6590     'mouseout' : {
6591         fn: this.onMouseOut
6592         scope: this
6593     }
6594 });</code></pre>
6595      * <p>
6596      * Or a shorthand syntax:<br>
6597      * Code:<pre><code>
6598 el.on({
6599     'click' : this.onClick,
6600     'mouseover' : this.onMouseOver,
6601     'mouseout' : this.onMouseOut
6602     scope: this
6603 });</code></pre>
6604      */
6605     pub.on = pub.addListener;
6606     pub.un = pub.removeListener;
6607
6608     pub.stoppedMouseDownEvent = new Roo.util.Event();
6609     return pub;
6610 }();
6611 /**
6612   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6613   * @param {Function} fn        The method the event invokes
6614   * @param {Object}   scope    An  object that becomes the scope of the handler
6615   * @param {boolean}  override If true, the obj passed in becomes
6616   *                             the execution scope of the listener
6617   * @member Roo
6618   * @method onReady
6619  */
6620 Roo.onReady = Roo.EventManager.onDocumentReady;
6621
6622 Roo.onReady(function(){
6623     var bd = Roo.get(document.body);
6624     if(!bd){ return; }
6625
6626     var cls = [
6627             Roo.isIE ? "roo-ie"
6628             : Roo.isGecko ? "roo-gecko"
6629             : Roo.isOpera ? "roo-opera"
6630             : Roo.isSafari ? "roo-safari" : ""];
6631
6632     if(Roo.isMac){
6633         cls.push("roo-mac");
6634     }
6635     if(Roo.isLinux){
6636         cls.push("roo-linux");
6637     }
6638     if(Roo.isIOS){
6639         cls.push("roo-ios");
6640     }
6641     if(Roo.isTouch){
6642         cls.push("roo-touch");
6643     }
6644     if(Roo.isBorderBox){
6645         cls.push('roo-border-box');
6646     }
6647     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6648         var p = bd.dom.parentNode;
6649         if(p){
6650             p.className += ' roo-strict';
6651         }
6652     }
6653     bd.addClass(cls.join(' '));
6654 });
6655
6656 /**
6657  * @class Roo.EventObject
6658  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6659  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6660  * Example:
6661  * <pre><code>
6662  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6663     e.preventDefault();
6664     var target = e.getTarget();
6665     ...
6666  }
6667  var myDiv = Roo.get("myDiv");
6668  myDiv.on("click", handleClick);
6669  //or
6670  Roo.EventManager.on("myDiv", 'click', handleClick);
6671  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6672  </code></pre>
6673  * @singleton
6674  */
6675 Roo.EventObject = function(){
6676     
6677     var E = Roo.lib.Event;
6678     
6679     // safari keypress events for special keys return bad keycodes
6680     var safariKeys = {
6681         63234 : 37, // left
6682         63235 : 39, // right
6683         63232 : 38, // up
6684         63233 : 40, // down
6685         63276 : 33, // page up
6686         63277 : 34, // page down
6687         63272 : 46, // delete
6688         63273 : 36, // home
6689         63275 : 35  // end
6690     };
6691
6692     // normalize button clicks
6693     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6694                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6695
6696     Roo.EventObjectImpl = function(e){
6697         if(e){
6698             this.setEvent(e.browserEvent || e);
6699         }
6700     };
6701     Roo.EventObjectImpl.prototype = {
6702         /**
6703          * Used to fix doc tools.
6704          * @scope Roo.EventObject.prototype
6705          */
6706             
6707
6708         
6709         
6710         /** The normal browser event */
6711         browserEvent : null,
6712         /** The button pressed in a mouse event */
6713         button : -1,
6714         /** True if the shift key was down during the event */
6715         shiftKey : false,
6716         /** True if the control key was down during the event */
6717         ctrlKey : false,
6718         /** True if the alt key was down during the event */
6719         altKey : false,
6720
6721         /** Key constant 
6722         * @type Number */
6723         BACKSPACE : 8,
6724         /** Key constant 
6725         * @type Number */
6726         TAB : 9,
6727         /** Key constant 
6728         * @type Number */
6729         RETURN : 13,
6730         /** Key constant 
6731         * @type Number */
6732         ENTER : 13,
6733         /** Key constant 
6734         * @type Number */
6735         SHIFT : 16,
6736         /** Key constant 
6737         * @type Number */
6738         CONTROL : 17,
6739         /** Key constant 
6740         * @type Number */
6741         ESC : 27,
6742         /** Key constant 
6743         * @type Number */
6744         SPACE : 32,
6745         /** Key constant 
6746         * @type Number */
6747         PAGEUP : 33,
6748         /** Key constant 
6749         * @type Number */
6750         PAGEDOWN : 34,
6751         /** Key constant 
6752         * @type Number */
6753         END : 35,
6754         /** Key constant 
6755         * @type Number */
6756         HOME : 36,
6757         /** Key constant 
6758         * @type Number */
6759         LEFT : 37,
6760         /** Key constant 
6761         * @type Number */
6762         UP : 38,
6763         /** Key constant 
6764         * @type Number */
6765         RIGHT : 39,
6766         /** Key constant 
6767         * @type Number */
6768         DOWN : 40,
6769         /** Key constant 
6770         * @type Number */
6771         MINUS : 45,
6772         /** Key constant 
6773         * @type Number */
6774         DELETE : 46,
6775         /** Key constant 
6776         * @type Number */
6777         F5 : 116,
6778
6779            /** @private */
6780         setEvent : function(e){
6781             if(e == this || (e && e.browserEvent)){ // already wrapped
6782                 return e;
6783             }
6784             this.browserEvent = e;
6785             if(e){
6786                 // normalize buttons
6787                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6788                 if(e.type == 'click' && this.button == -1){
6789                     this.button = 0;
6790                 }
6791                 this.type = e.type;
6792                 this.shiftKey = e.shiftKey;
6793                 // mac metaKey behaves like ctrlKey
6794                 this.ctrlKey = e.ctrlKey || e.metaKey;
6795                 this.altKey = e.altKey;
6796                 // in getKey these will be normalized for the mac
6797                 this.keyCode = e.keyCode;
6798                 // keyup warnings on firefox.
6799                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6800                 // cache the target for the delayed and or buffered events
6801                 this.target = E.getTarget(e);
6802                 // same for XY
6803                 this.xy = E.getXY(e);
6804             }else{
6805                 this.button = -1;
6806                 this.shiftKey = false;
6807                 this.ctrlKey = false;
6808                 this.altKey = false;
6809                 this.keyCode = 0;
6810                 this.charCode =0;
6811                 this.target = null;
6812                 this.xy = [0, 0];
6813             }
6814             return this;
6815         },
6816
6817         /**
6818          * Stop the event (preventDefault and stopPropagation)
6819          */
6820         stopEvent : function(){
6821             if(this.browserEvent){
6822                 if(this.browserEvent.type == 'mousedown'){
6823                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6824                 }
6825                 E.stopEvent(this.browserEvent);
6826             }
6827         },
6828
6829         /**
6830          * Prevents the browsers default handling of the event.
6831          */
6832         preventDefault : function(){
6833             if(this.browserEvent){
6834                 E.preventDefault(this.browserEvent);
6835             }
6836         },
6837
6838         /** @private */
6839         isNavKeyPress : function(){
6840             var k = this.keyCode;
6841             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6842             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6843         },
6844
6845         isSpecialKey : function(){
6846             var k = this.keyCode;
6847             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6848             (k == 16) || (k == 17) ||
6849             (k >= 18 && k <= 20) ||
6850             (k >= 33 && k <= 35) ||
6851             (k >= 36 && k <= 39) ||
6852             (k >= 44 && k <= 45);
6853         },
6854         /**
6855          * Cancels bubbling of the event.
6856          */
6857         stopPropagation : function(){
6858             if(this.browserEvent){
6859                 if(this.type == 'mousedown'){
6860                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6861                 }
6862                 E.stopPropagation(this.browserEvent);
6863             }
6864         },
6865
6866         /**
6867          * Gets the key code for the event.
6868          * @return {Number}
6869          */
6870         getCharCode : function(){
6871             return this.charCode || this.keyCode;
6872         },
6873
6874         /**
6875          * Returns a normalized keyCode for the event.
6876          * @return {Number} The key code
6877          */
6878         getKey : function(){
6879             var k = this.keyCode || this.charCode;
6880             return Roo.isSafari ? (safariKeys[k] || k) : k;
6881         },
6882
6883         /**
6884          * Gets the x coordinate of the event.
6885          * @return {Number}
6886          */
6887         getPageX : function(){
6888             return this.xy[0];
6889         },
6890
6891         /**
6892          * Gets the y coordinate of the event.
6893          * @return {Number}
6894          */
6895         getPageY : function(){
6896             return this.xy[1];
6897         },
6898
6899         /**
6900          * Gets the time of the event.
6901          * @return {Number}
6902          */
6903         getTime : function(){
6904             if(this.browserEvent){
6905                 return E.getTime(this.browserEvent);
6906             }
6907             return null;
6908         },
6909
6910         /**
6911          * Gets the page coordinates of the event.
6912          * @return {Array} The xy values like [x, y]
6913          */
6914         getXY : function(){
6915             return this.xy;
6916         },
6917
6918         /**
6919          * Gets the target for the event.
6920          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6921          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6922                 search as a number or element (defaults to 10 || document.body)
6923          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6924          * @return {HTMLelement}
6925          */
6926         getTarget : function(selector, maxDepth, returnEl){
6927             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6928         },
6929         /**
6930          * Gets the related target.
6931          * @return {HTMLElement}
6932          */
6933         getRelatedTarget : function(){
6934             if(this.browserEvent){
6935                 return E.getRelatedTarget(this.browserEvent);
6936             }
6937             return null;
6938         },
6939
6940         /**
6941          * Normalizes mouse wheel delta across browsers
6942          * @return {Number} The delta
6943          */
6944         getWheelDelta : function(){
6945             var e = this.browserEvent;
6946             var delta = 0;
6947             if(e.wheelDelta){ /* IE/Opera. */
6948                 delta = e.wheelDelta/120;
6949             }else if(e.detail){ /* Mozilla case. */
6950                 delta = -e.detail/3;
6951             }
6952             return delta;
6953         },
6954
6955         /**
6956          * Returns true if the control, meta, shift or alt key was pressed during this event.
6957          * @return {Boolean}
6958          */
6959         hasModifier : function(){
6960             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6961         },
6962
6963         /**
6964          * Returns true if the target of this event equals el or is a child of el
6965          * @param {String/HTMLElement/Element} el
6966          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6967          * @return {Boolean}
6968          */
6969         within : function(el, related){
6970             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6971             return t && Roo.fly(el).contains(t);
6972         },
6973
6974         getPoint : function(){
6975             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6976         }
6977     };
6978
6979     return new Roo.EventObjectImpl();
6980 }();
6981             
6982     /*
6983  * Based on:
6984  * Ext JS Library 1.1.1
6985  * Copyright(c) 2006-2007, Ext JS, LLC.
6986  *
6987  * Originally Released Under LGPL - original licence link has changed is not relivant.
6988  *
6989  * Fork - LGPL
6990  * <script type="text/javascript">
6991  */
6992
6993  
6994 // was in Composite Element!??!?!
6995  
6996 (function(){
6997     var D = Roo.lib.Dom;
6998     var E = Roo.lib.Event;
6999     var A = Roo.lib.Anim;
7000
7001     // local style camelizing for speed
7002     var propCache = {};
7003     var camelRe = /(-[a-z])/gi;
7004     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7005     var view = document.defaultView;
7006
7007 /**
7008  * @class Roo.Element
7009  * Represents an Element in the DOM.<br><br>
7010  * Usage:<br>
7011 <pre><code>
7012 var el = Roo.get("my-div");
7013
7014 // or with getEl
7015 var el = getEl("my-div");
7016
7017 // or with a DOM element
7018 var el = Roo.get(myDivElement);
7019 </code></pre>
7020  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7021  * each call instead of constructing a new one.<br><br>
7022  * <b>Animations</b><br />
7023  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7024  * should either be a boolean (true) or an object literal with animation options. The animation options are:
7025 <pre>
7026 Option    Default   Description
7027 --------- --------  ---------------------------------------------
7028 duration  .35       The duration of the animation in seconds
7029 easing    easeOut   The YUI easing method
7030 callback  none      A function to execute when the anim completes
7031 scope     this      The scope (this) of the callback function
7032 </pre>
7033 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7034 * manipulate the animation. Here's an example:
7035 <pre><code>
7036 var el = Roo.get("my-div");
7037
7038 // no animation
7039 el.setWidth(100);
7040
7041 // default animation
7042 el.setWidth(100, true);
7043
7044 // animation with some options set
7045 el.setWidth(100, {
7046     duration: 1,
7047     callback: this.foo,
7048     scope: this
7049 });
7050
7051 // using the "anim" property to get the Anim object
7052 var opt = {
7053     duration: 1,
7054     callback: this.foo,
7055     scope: this
7056 };
7057 el.setWidth(100, opt);
7058 ...
7059 if(opt.anim.isAnimated()){
7060     opt.anim.stop();
7061 }
7062 </code></pre>
7063 * <b> Composite (Collections of) Elements</b><br />
7064  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7065  * @constructor Create a new Element directly.
7066  * @param {String/HTMLElement} element
7067  * @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).
7068  */
7069     Roo.Element = function(element, forceNew){
7070         var dom = typeof element == "string" ?
7071                 document.getElementById(element) : element;
7072         if(!dom){ // invalid id/element
7073             return null;
7074         }
7075         var id = dom.id;
7076         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7077             return Roo.Element.cache[id];
7078         }
7079
7080         /**
7081          * The DOM element
7082          * @type HTMLElement
7083          */
7084         this.dom = dom;
7085
7086         /**
7087          * The DOM element ID
7088          * @type String
7089          */
7090         this.id = id || Roo.id(dom);
7091     };
7092
7093     var El = Roo.Element;
7094
7095     El.prototype = {
7096         /**
7097          * The element's default display mode  (defaults to "")
7098          * @type String
7099          */
7100         originalDisplay : "",
7101
7102         visibilityMode : 1,
7103         /**
7104          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7105          * @type String
7106          */
7107         defaultUnit : "px",
7108         
7109         /**
7110          * Sets the element's visibility mode. When setVisible() is called it
7111          * will use this to determine whether to set the visibility or the display property.
7112          * @param visMode Element.VISIBILITY or Element.DISPLAY
7113          * @return {Roo.Element} this
7114          */
7115         setVisibilityMode : function(visMode){
7116             this.visibilityMode = visMode;
7117             return this;
7118         },
7119         /**
7120          * Convenience method for setVisibilityMode(Element.DISPLAY)
7121          * @param {String} display (optional) What to set display to when visible
7122          * @return {Roo.Element} this
7123          */
7124         enableDisplayMode : function(display){
7125             this.setVisibilityMode(El.DISPLAY);
7126             if(typeof display != "undefined") { this.originalDisplay = display; }
7127             return this;
7128         },
7129
7130         /**
7131          * 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)
7132          * @param {String} selector The simple selector to test
7133          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7134                 search as a number or element (defaults to 10 || document.body)
7135          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7136          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7137          */
7138         findParent : function(simpleSelector, maxDepth, returnEl){
7139             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7140             maxDepth = maxDepth || 50;
7141             if(typeof maxDepth != "number"){
7142                 stopEl = Roo.getDom(maxDepth);
7143                 maxDepth = 10;
7144             }
7145             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7146                 if(dq.is(p, simpleSelector)){
7147                     return returnEl ? Roo.get(p) : p;
7148                 }
7149                 depth++;
7150                 p = p.parentNode;
7151             }
7152             return null;
7153         },
7154
7155
7156         /**
7157          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7158          * @param {String} selector The simple selector to test
7159          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7160                 search as a number or element (defaults to 10 || document.body)
7161          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7162          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7163          */
7164         findParentNode : function(simpleSelector, maxDepth, returnEl){
7165             var p = Roo.fly(this.dom.parentNode, '_internal');
7166             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7167         },
7168
7169         /**
7170          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7171          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7172          * @param {String} selector The simple selector to test
7173          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7174                 search as a number or element (defaults to 10 || document.body)
7175          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7176          */
7177         up : function(simpleSelector, maxDepth){
7178             return this.findParentNode(simpleSelector, maxDepth, true);
7179         },
7180
7181
7182
7183         /**
7184          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7185          * @param {String} selector The simple selector to test
7186          * @return {Boolean} True if this element matches the selector, else false
7187          */
7188         is : function(simpleSelector){
7189             return Roo.DomQuery.is(this.dom, simpleSelector);
7190         },
7191
7192         /**
7193          * Perform animation on this element.
7194          * @param {Object} args The YUI animation control args
7195          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7196          * @param {Function} onComplete (optional) Function to call when animation completes
7197          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7198          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7199          * @return {Roo.Element} this
7200          */
7201         animate : function(args, duration, onComplete, easing, animType){
7202             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7203             return this;
7204         },
7205
7206         /*
7207          * @private Internal animation call
7208          */
7209         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7210             animType = animType || 'run';
7211             opt = opt || {};
7212             var anim = Roo.lib.Anim[animType](
7213                 this.dom, args,
7214                 (opt.duration || defaultDur) || .35,
7215                 (opt.easing || defaultEase) || 'easeOut',
7216                 function(){
7217                     Roo.callback(cb, this);
7218                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7219                 },
7220                 this
7221             );
7222             opt.anim = anim;
7223             return anim;
7224         },
7225
7226         // private legacy anim prep
7227         preanim : function(a, i){
7228             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7229         },
7230
7231         /**
7232          * Removes worthless text nodes
7233          * @param {Boolean} forceReclean (optional) By default the element
7234          * keeps track if it has been cleaned already so
7235          * you can call this over and over. However, if you update the element and
7236          * need to force a reclean, you can pass true.
7237          */
7238         clean : function(forceReclean){
7239             if(this.isCleaned && forceReclean !== true){
7240                 return this;
7241             }
7242             var ns = /\S/;
7243             var d = this.dom, n = d.firstChild, ni = -1;
7244             while(n){
7245                 var nx = n.nextSibling;
7246                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7247                     d.removeChild(n);
7248                 }else{
7249                     n.nodeIndex = ++ni;
7250                 }
7251                 n = nx;
7252             }
7253             this.isCleaned = true;
7254             return this;
7255         },
7256
7257         // private
7258         calcOffsetsTo : function(el){
7259             el = Roo.get(el);
7260             var d = el.dom;
7261             var restorePos = false;
7262             if(el.getStyle('position') == 'static'){
7263                 el.position('relative');
7264                 restorePos = true;
7265             }
7266             var x = 0, y =0;
7267             var op = this.dom;
7268             while(op && op != d && op.tagName != 'HTML'){
7269                 x+= op.offsetLeft;
7270                 y+= op.offsetTop;
7271                 op = op.offsetParent;
7272             }
7273             if(restorePos){
7274                 el.position('static');
7275             }
7276             return [x, y];
7277         },
7278
7279         /**
7280          * Scrolls this element into view within the passed container.
7281          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7282          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7283          * @return {Roo.Element} this
7284          */
7285         scrollIntoView : function(container, hscroll){
7286             var c = Roo.getDom(container) || document.body;
7287             var el = this.dom;
7288
7289             var o = this.calcOffsetsTo(c),
7290                 l = o[0],
7291                 t = o[1],
7292                 b = t+el.offsetHeight,
7293                 r = l+el.offsetWidth;
7294
7295             var ch = c.clientHeight;
7296             var ct = parseInt(c.scrollTop, 10);
7297             var cl = parseInt(c.scrollLeft, 10);
7298             var cb = ct + ch;
7299             var cr = cl + c.clientWidth;
7300
7301             if(t < ct){
7302                 c.scrollTop = t;
7303             }else if(b > cb){
7304                 c.scrollTop = b-ch;
7305             }
7306
7307             if(hscroll !== false){
7308                 if(l < cl){
7309                     c.scrollLeft = l;
7310                 }else if(r > cr){
7311                     c.scrollLeft = r-c.clientWidth;
7312                 }
7313             }
7314             return this;
7315         },
7316
7317         // private
7318         scrollChildIntoView : function(child, hscroll){
7319             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7320         },
7321
7322         /**
7323          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7324          * the new height may not be available immediately.
7325          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7326          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7327          * @param {Function} onComplete (optional) Function to call when animation completes
7328          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7329          * @return {Roo.Element} this
7330          */
7331         autoHeight : function(animate, duration, onComplete, easing){
7332             var oldHeight = this.getHeight();
7333             this.clip();
7334             this.setHeight(1); // force clipping
7335             setTimeout(function(){
7336                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7337                 if(!animate){
7338                     this.setHeight(height);
7339                     this.unclip();
7340                     if(typeof onComplete == "function"){
7341                         onComplete();
7342                     }
7343                 }else{
7344                     this.setHeight(oldHeight); // restore original height
7345                     this.setHeight(height, animate, duration, function(){
7346                         this.unclip();
7347                         if(typeof onComplete == "function") { onComplete(); }
7348                     }.createDelegate(this), easing);
7349                 }
7350             }.createDelegate(this), 0);
7351             return this;
7352         },
7353
7354         /**
7355          * Returns true if this element is an ancestor of the passed element
7356          * @param {HTMLElement/String} el The element to check
7357          * @return {Boolean} True if this element is an ancestor of el, else false
7358          */
7359         contains : function(el){
7360             if(!el){return false;}
7361             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7362         },
7363
7364         /**
7365          * Checks whether the element is currently visible using both visibility and display properties.
7366          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7367          * @return {Boolean} True if the element is currently visible, else false
7368          */
7369         isVisible : function(deep) {
7370             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7371             if(deep !== true || !vis){
7372                 return vis;
7373             }
7374             var p = this.dom.parentNode;
7375             while(p && p.tagName.toLowerCase() != "body"){
7376                 if(!Roo.fly(p, '_isVisible').isVisible()){
7377                     return false;
7378                 }
7379                 p = p.parentNode;
7380             }
7381             return true;
7382         },
7383
7384         /**
7385          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7386          * @param {String} selector The CSS selector
7387          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7388          * @return {CompositeElement/CompositeElementLite} The composite element
7389          */
7390         select : function(selector, unique){
7391             return El.select(selector, unique, this.dom);
7392         },
7393
7394         /**
7395          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7396          * @param {String} selector The CSS selector
7397          * @return {Array} An array of the matched nodes
7398          */
7399         query : function(selector, unique){
7400             return Roo.DomQuery.select(selector, this.dom);
7401         },
7402
7403         /**
7404          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7405          * @param {String} selector The CSS selector
7406          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7407          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7408          */
7409         child : function(selector, returnDom){
7410             var n = Roo.DomQuery.selectNode(selector, this.dom);
7411             return returnDom ? n : Roo.get(n);
7412         },
7413
7414         /**
7415          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7416          * @param {String} selector The CSS selector
7417          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7418          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7419          */
7420         down : function(selector, returnDom){
7421             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7422             return returnDom ? n : Roo.get(n);
7423         },
7424
7425         /**
7426          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7427          * @param {String} group The group the DD object is member of
7428          * @param {Object} config The DD config object
7429          * @param {Object} overrides An object containing methods to override/implement on the DD object
7430          * @return {Roo.dd.DD} The DD object
7431          */
7432         initDD : function(group, config, overrides){
7433             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7434             return Roo.apply(dd, overrides);
7435         },
7436
7437         /**
7438          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7439          * @param {String} group The group the DDProxy object is member of
7440          * @param {Object} config The DDProxy config object
7441          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7442          * @return {Roo.dd.DDProxy} The DDProxy object
7443          */
7444         initDDProxy : function(group, config, overrides){
7445             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7446             return Roo.apply(dd, overrides);
7447         },
7448
7449         /**
7450          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7451          * @param {String} group The group the DDTarget object is member of
7452          * @param {Object} config The DDTarget config object
7453          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7454          * @return {Roo.dd.DDTarget} The DDTarget object
7455          */
7456         initDDTarget : function(group, config, overrides){
7457             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7458             return Roo.apply(dd, overrides);
7459         },
7460
7461         /**
7462          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7463          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7464          * @param {Boolean} visible Whether the element is visible
7465          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7466          * @return {Roo.Element} this
7467          */
7468          setVisible : function(visible, animate){
7469             if(!animate || !A){
7470                 if(this.visibilityMode == El.DISPLAY){
7471                     this.setDisplayed(visible);
7472                 }else{
7473                     this.fixDisplay();
7474                     this.dom.style.visibility = visible ? "visible" : "hidden";
7475                 }
7476             }else{
7477                 // closure for composites
7478                 var dom = this.dom;
7479                 var visMode = this.visibilityMode;
7480                 if(visible){
7481                     this.setOpacity(.01);
7482                     this.setVisible(true);
7483                 }
7484                 this.anim({opacity: { to: (visible?1:0) }},
7485                       this.preanim(arguments, 1),
7486                       null, .35, 'easeIn', function(){
7487                          if(!visible){
7488                              if(visMode == El.DISPLAY){
7489                                  dom.style.display = "none";
7490                              }else{
7491                                  dom.style.visibility = "hidden";
7492                              }
7493                              Roo.get(dom).setOpacity(1);
7494                          }
7495                      });
7496             }
7497             return this;
7498         },
7499
7500         /**
7501          * Returns true if display is not "none"
7502          * @return {Boolean}
7503          */
7504         isDisplayed : function() {
7505             return this.getStyle("display") != "none";
7506         },
7507
7508         /**
7509          * Toggles the element's visibility or display, depending on visibility mode.
7510          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7511          * @return {Roo.Element} this
7512          */
7513         toggle : function(animate){
7514             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7515             return this;
7516         },
7517
7518         /**
7519          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7520          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7521          * @return {Roo.Element} this
7522          */
7523         setDisplayed : function(value) {
7524             if(typeof value == "boolean"){
7525                value = value ? this.originalDisplay : "none";
7526             }
7527             this.setStyle("display", value);
7528             return this;
7529         },
7530
7531         /**
7532          * Tries to focus the element. Any exceptions are caught and ignored.
7533          * @return {Roo.Element} this
7534          */
7535         focus : function() {
7536             try{
7537                 this.dom.focus();
7538             }catch(e){}
7539             return this;
7540         },
7541
7542         /**
7543          * Tries to blur the element. Any exceptions are caught and ignored.
7544          * @return {Roo.Element} this
7545          */
7546         blur : function() {
7547             try{
7548                 this.dom.blur();
7549             }catch(e){}
7550             return this;
7551         },
7552
7553         /**
7554          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7555          * @param {String/Array} className The CSS class to add, or an array of classes
7556          * @return {Roo.Element} this
7557          */
7558         addClass : function(className){
7559             if(className instanceof Array){
7560                 for(var i = 0, len = className.length; i < len; i++) {
7561                     this.addClass(className[i]);
7562                 }
7563             }else{
7564                 if(className && !this.hasClass(className)){
7565                     this.dom.className = this.dom.className + " " + className;
7566                 }
7567             }
7568             return this;
7569         },
7570
7571         /**
7572          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7573          * @param {String/Array} className The CSS class to add, or an array of classes
7574          * @return {Roo.Element} this
7575          */
7576         radioClass : function(className){
7577             var siblings = this.dom.parentNode.childNodes;
7578             for(var i = 0; i < siblings.length; i++) {
7579                 var s = siblings[i];
7580                 if(s.nodeType == 1){
7581                     Roo.get(s).removeClass(className);
7582                 }
7583             }
7584             this.addClass(className);
7585             return this;
7586         },
7587
7588         /**
7589          * Removes one or more CSS classes from the element.
7590          * @param {String/Array} className The CSS class to remove, or an array of classes
7591          * @return {Roo.Element} this
7592          */
7593         removeClass : function(className){
7594             if(!className || !this.dom.className){
7595                 return this;
7596             }
7597             if(className instanceof Array){
7598                 for(var i = 0, len = className.length; i < len; i++) {
7599                     this.removeClass(className[i]);
7600                 }
7601             }else{
7602                 if(this.hasClass(className)){
7603                     var re = this.classReCache[className];
7604                     if (!re) {
7605                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7606                        this.classReCache[className] = re;
7607                     }
7608                     this.dom.className =
7609                         this.dom.className.replace(re, " ");
7610                 }
7611             }
7612             return this;
7613         },
7614
7615         // private
7616         classReCache: {},
7617
7618         /**
7619          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7620          * @param {String} className The CSS class to toggle
7621          * @return {Roo.Element} this
7622          */
7623         toggleClass : function(className){
7624             if(this.hasClass(className)){
7625                 this.removeClass(className);
7626             }else{
7627                 this.addClass(className);
7628             }
7629             return this;
7630         },
7631
7632         /**
7633          * Checks if the specified CSS class exists on this element's DOM node.
7634          * @param {String} className The CSS class to check for
7635          * @return {Boolean} True if the class exists, else false
7636          */
7637         hasClass : function(className){
7638             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7639         },
7640
7641         /**
7642          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7643          * @param {String} oldClassName The CSS class to replace
7644          * @param {String} newClassName The replacement CSS class
7645          * @return {Roo.Element} this
7646          */
7647         replaceClass : function(oldClassName, newClassName){
7648             this.removeClass(oldClassName);
7649             this.addClass(newClassName);
7650             return this;
7651         },
7652
7653         /**
7654          * Returns an object with properties matching the styles requested.
7655          * For example, el.getStyles('color', 'font-size', 'width') might return
7656          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7657          * @param {String} style1 A style name
7658          * @param {String} style2 A style name
7659          * @param {String} etc.
7660          * @return {Object} The style object
7661          */
7662         getStyles : function(){
7663             var a = arguments, len = a.length, r = {};
7664             for(var i = 0; i < len; i++){
7665                 r[a[i]] = this.getStyle(a[i]);
7666             }
7667             return r;
7668         },
7669
7670         /**
7671          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7672          * @param {String} property The style property whose value is returned.
7673          * @return {String} The current value of the style property for this element.
7674          */
7675         getStyle : function(){
7676             return view && view.getComputedStyle ?
7677                 function(prop){
7678                     var el = this.dom, v, cs, camel;
7679                     if(prop == 'float'){
7680                         prop = "cssFloat";
7681                     }
7682                     if(el.style && (v = el.style[prop])){
7683                         return v;
7684                     }
7685                     if(cs = view.getComputedStyle(el, "")){
7686                         if(!(camel = propCache[prop])){
7687                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7688                         }
7689                         return cs[camel];
7690                     }
7691                     return null;
7692                 } :
7693                 function(prop){
7694                     var el = this.dom, v, cs, camel;
7695                     if(prop == 'opacity'){
7696                         if(typeof el.style.filter == 'string'){
7697                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7698                             if(m){
7699                                 var fv = parseFloat(m[1]);
7700                                 if(!isNaN(fv)){
7701                                     return fv ? fv / 100 : 0;
7702                                 }
7703                             }
7704                         }
7705                         return 1;
7706                     }else if(prop == 'float'){
7707                         prop = "styleFloat";
7708                     }
7709                     if(!(camel = propCache[prop])){
7710                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7711                     }
7712                     if(v = el.style[camel]){
7713                         return v;
7714                     }
7715                     if(cs = el.currentStyle){
7716                         return cs[camel];
7717                     }
7718                     return null;
7719                 };
7720         }(),
7721
7722         /**
7723          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7724          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7725          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7726          * @return {Roo.Element} this
7727          */
7728         setStyle : function(prop, value){
7729             if(typeof prop == "string"){
7730                 
7731                 if (prop == 'float') {
7732                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7733                     return this;
7734                 }
7735                 
7736                 var camel;
7737                 if(!(camel = propCache[prop])){
7738                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7739                 }
7740                 
7741                 if(camel == 'opacity') {
7742                     this.setOpacity(value);
7743                 }else{
7744                     this.dom.style[camel] = value;
7745                 }
7746             }else{
7747                 for(var style in prop){
7748                     if(typeof prop[style] != "function"){
7749                        this.setStyle(style, prop[style]);
7750                     }
7751                 }
7752             }
7753             return this;
7754         },
7755
7756         /**
7757          * More flexible version of {@link #setStyle} for setting style properties.
7758          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7759          * a function which returns such a specification.
7760          * @return {Roo.Element} this
7761          */
7762         applyStyles : function(style){
7763             Roo.DomHelper.applyStyles(this.dom, style);
7764             return this;
7765         },
7766
7767         /**
7768           * 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).
7769           * @return {Number} The X position of the element
7770           */
7771         getX : function(){
7772             return D.getX(this.dom);
7773         },
7774
7775         /**
7776           * 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).
7777           * @return {Number} The Y position of the element
7778           */
7779         getY : function(){
7780             return D.getY(this.dom);
7781         },
7782
7783         /**
7784           * 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).
7785           * @return {Array} The XY position of the element
7786           */
7787         getXY : function(){
7788             return D.getXY(this.dom);
7789         },
7790
7791         /**
7792          * 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).
7793          * @param {Number} The X position of the element
7794          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7795          * @return {Roo.Element} this
7796          */
7797         setX : function(x, animate){
7798             if(!animate || !A){
7799                 D.setX(this.dom, x);
7800             }else{
7801                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7802             }
7803             return this;
7804         },
7805
7806         /**
7807          * 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).
7808          * @param {Number} The Y position of the element
7809          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7810          * @return {Roo.Element} this
7811          */
7812         setY : function(y, animate){
7813             if(!animate || !A){
7814                 D.setY(this.dom, y);
7815             }else{
7816                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7817             }
7818             return this;
7819         },
7820
7821         /**
7822          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7823          * @param {String} left The left CSS property value
7824          * @return {Roo.Element} this
7825          */
7826         setLeft : function(left){
7827             this.setStyle("left", this.addUnits(left));
7828             return this;
7829         },
7830
7831         /**
7832          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7833          * @param {String} top The top CSS property value
7834          * @return {Roo.Element} this
7835          */
7836         setTop : function(top){
7837             this.setStyle("top", this.addUnits(top));
7838             return this;
7839         },
7840
7841         /**
7842          * Sets the element's CSS right style.
7843          * @param {String} right The right CSS property value
7844          * @return {Roo.Element} this
7845          */
7846         setRight : function(right){
7847             this.setStyle("right", this.addUnits(right));
7848             return this;
7849         },
7850
7851         /**
7852          * Sets the element's CSS bottom style.
7853          * @param {String} bottom The bottom CSS property value
7854          * @return {Roo.Element} this
7855          */
7856         setBottom : function(bottom){
7857             this.setStyle("bottom", this.addUnits(bottom));
7858             return this;
7859         },
7860
7861         /**
7862          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7863          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7864          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7865          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7866          * @return {Roo.Element} this
7867          */
7868         setXY : function(pos, animate){
7869             if(!animate || !A){
7870                 D.setXY(this.dom, pos);
7871             }else{
7872                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7873             }
7874             return this;
7875         },
7876
7877         /**
7878          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7879          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7880          * @param {Number} x X value for new position (coordinates are page-based)
7881          * @param {Number} y Y value for new position (coordinates are page-based)
7882          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7883          * @return {Roo.Element} this
7884          */
7885         setLocation : function(x, y, animate){
7886             this.setXY([x, y], this.preanim(arguments, 2));
7887             return this;
7888         },
7889
7890         /**
7891          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7892          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7893          * @param {Number} x X value for new position (coordinates are page-based)
7894          * @param {Number} y Y value for new position (coordinates are page-based)
7895          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7896          * @return {Roo.Element} this
7897          */
7898         moveTo : function(x, y, animate){
7899             this.setXY([x, y], this.preanim(arguments, 2));
7900             return this;
7901         },
7902
7903         /**
7904          * Returns the region of the given element.
7905          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7906          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7907          */
7908         getRegion : function(){
7909             return D.getRegion(this.dom);
7910         },
7911
7912         /**
7913          * Returns the offset height of the element
7914          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7915          * @return {Number} The element's height
7916          */
7917         getHeight : function(contentHeight){
7918             var h = this.dom.offsetHeight || 0;
7919             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7920         },
7921
7922         /**
7923          * Returns the offset width of the element
7924          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7925          * @return {Number} The element's width
7926          */
7927         getWidth : function(contentWidth){
7928             var w = this.dom.offsetWidth || 0;
7929             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7930         },
7931
7932         /**
7933          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7934          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7935          * if a height has not been set using CSS.
7936          * @return {Number}
7937          */
7938         getComputedHeight : function(){
7939             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7940             if(!h){
7941                 h = parseInt(this.getStyle('height'), 10) || 0;
7942                 if(!this.isBorderBox()){
7943                     h += this.getFrameWidth('tb');
7944                 }
7945             }
7946             return h;
7947         },
7948
7949         /**
7950          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7951          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7952          * if a width has not been set using CSS.
7953          * @return {Number}
7954          */
7955         getComputedWidth : function(){
7956             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7957             if(!w){
7958                 w = parseInt(this.getStyle('width'), 10) || 0;
7959                 if(!this.isBorderBox()){
7960                     w += this.getFrameWidth('lr');
7961                 }
7962             }
7963             return w;
7964         },
7965
7966         /**
7967          * Returns the size of the element.
7968          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7969          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7970          */
7971         getSize : function(contentSize){
7972             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7973         },
7974
7975         /**
7976          * Returns the width and height of the viewport.
7977          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7978          */
7979         getViewSize : function(){
7980             var d = this.dom, doc = document, aw = 0, ah = 0;
7981             if(d == doc || d == doc.body){
7982                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7983             }else{
7984                 return {
7985                     width : d.clientWidth,
7986                     height: d.clientHeight
7987                 };
7988             }
7989         },
7990
7991         /**
7992          * Returns the value of the "value" attribute
7993          * @param {Boolean} asNumber true to parse the value as a number
7994          * @return {String/Number}
7995          */
7996         getValue : function(asNumber){
7997             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7998         },
7999
8000         // private
8001         adjustWidth : function(width){
8002             if(typeof width == "number"){
8003                 if(this.autoBoxAdjust && !this.isBorderBox()){
8004                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8005                 }
8006                 if(width < 0){
8007                     width = 0;
8008                 }
8009             }
8010             return width;
8011         },
8012
8013         // private
8014         adjustHeight : function(height){
8015             if(typeof height == "number"){
8016                if(this.autoBoxAdjust && !this.isBorderBox()){
8017                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8018                }
8019                if(height < 0){
8020                    height = 0;
8021                }
8022             }
8023             return height;
8024         },
8025
8026         /**
8027          * Set the width of the element
8028          * @param {Number} width The new width
8029          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030          * @return {Roo.Element} this
8031          */
8032         setWidth : function(width, animate){
8033             width = this.adjustWidth(width);
8034             if(!animate || !A){
8035                 this.dom.style.width = this.addUnits(width);
8036             }else{
8037                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8038             }
8039             return this;
8040         },
8041
8042         /**
8043          * Set the height of the element
8044          * @param {Number} height The new height
8045          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8046          * @return {Roo.Element} this
8047          */
8048          setHeight : function(height, animate){
8049             height = this.adjustHeight(height);
8050             if(!animate || !A){
8051                 this.dom.style.height = this.addUnits(height);
8052             }else{
8053                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8054             }
8055             return this;
8056         },
8057
8058         /**
8059          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8060          * @param {Number} width The new width
8061          * @param {Number} height The new height
8062          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8063          * @return {Roo.Element} this
8064          */
8065          setSize : function(width, height, animate){
8066             if(typeof width == "object"){ // in case of object from getSize()
8067                 height = width.height; width = width.width;
8068             }
8069             width = this.adjustWidth(width); height = this.adjustHeight(height);
8070             if(!animate || !A){
8071                 this.dom.style.width = this.addUnits(width);
8072                 this.dom.style.height = this.addUnits(height);
8073             }else{
8074                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8075             }
8076             return this;
8077         },
8078
8079         /**
8080          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8081          * @param {Number} x X value for new position (coordinates are page-based)
8082          * @param {Number} y Y value for new position (coordinates are page-based)
8083          * @param {Number} width The new width
8084          * @param {Number} height The new height
8085          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8086          * @return {Roo.Element} this
8087          */
8088         setBounds : function(x, y, width, height, animate){
8089             if(!animate || !A){
8090                 this.setSize(width, height);
8091                 this.setLocation(x, y);
8092             }else{
8093                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8094                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8095                               this.preanim(arguments, 4), 'motion');
8096             }
8097             return this;
8098         },
8099
8100         /**
8101          * 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.
8102          * @param {Roo.lib.Region} region The region to fill
8103          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8104          * @return {Roo.Element} this
8105          */
8106         setRegion : function(region, animate){
8107             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8108             return this;
8109         },
8110
8111         /**
8112          * Appends an event handler
8113          *
8114          * @param {String}   eventName     The type of event to append
8115          * @param {Function} fn        The method the event invokes
8116          * @param {Object} scope       (optional) The scope (this object) of the fn
8117          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8118          */
8119         addListener : function(eventName, fn, scope, options){
8120             if (this.dom) {
8121                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8122             }
8123         },
8124
8125         /**
8126          * Removes an event handler from this element
8127          * @param {String} eventName the type of event to remove
8128          * @param {Function} fn the method the event invokes
8129          * @return {Roo.Element} this
8130          */
8131         removeListener : function(eventName, fn){
8132             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8133             return this;
8134         },
8135
8136         /**
8137          * Removes all previous added listeners from this element
8138          * @return {Roo.Element} this
8139          */
8140         removeAllListeners : function(){
8141             E.purgeElement(this.dom);
8142             return this;
8143         },
8144
8145         relayEvent : function(eventName, observable){
8146             this.on(eventName, function(e){
8147                 observable.fireEvent(eventName, e);
8148             });
8149         },
8150
8151         /**
8152          * Set the opacity of the element
8153          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8154          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8155          * @return {Roo.Element} this
8156          */
8157          setOpacity : function(opacity, animate){
8158             if(!animate || !A){
8159                 var s = this.dom.style;
8160                 if(Roo.isIE){
8161                     s.zoom = 1;
8162                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8163                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8164                 }else{
8165                     s.opacity = opacity;
8166                 }
8167             }else{
8168                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8169             }
8170             return this;
8171         },
8172
8173         /**
8174          * Gets the left X coordinate
8175          * @param {Boolean} local True to get the local css position instead of page coordinate
8176          * @return {Number}
8177          */
8178         getLeft : function(local){
8179             if(!local){
8180                 return this.getX();
8181             }else{
8182                 return parseInt(this.getStyle("left"), 10) || 0;
8183             }
8184         },
8185
8186         /**
8187          * Gets the right X coordinate of the element (element X position + element width)
8188          * @param {Boolean} local True to get the local css position instead of page coordinate
8189          * @return {Number}
8190          */
8191         getRight : function(local){
8192             if(!local){
8193                 return this.getX() + this.getWidth();
8194             }else{
8195                 return (this.getLeft(true) + this.getWidth()) || 0;
8196             }
8197         },
8198
8199         /**
8200          * Gets the top Y coordinate
8201          * @param {Boolean} local True to get the local css position instead of page coordinate
8202          * @return {Number}
8203          */
8204         getTop : function(local) {
8205             if(!local){
8206                 return this.getY();
8207             }else{
8208                 return parseInt(this.getStyle("top"), 10) || 0;
8209             }
8210         },
8211
8212         /**
8213          * Gets the bottom Y coordinate of the element (element Y position + element height)
8214          * @param {Boolean} local True to get the local css position instead of page coordinate
8215          * @return {Number}
8216          */
8217         getBottom : function(local){
8218             if(!local){
8219                 return this.getY() + this.getHeight();
8220             }else{
8221                 return (this.getTop(true) + this.getHeight()) || 0;
8222             }
8223         },
8224
8225         /**
8226         * Initializes positioning on this element. If a desired position is not passed, it will make the
8227         * the element positioned relative IF it is not already positioned.
8228         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8229         * @param {Number} zIndex (optional) The zIndex to apply
8230         * @param {Number} x (optional) Set the page X position
8231         * @param {Number} y (optional) Set the page Y position
8232         */
8233         position : function(pos, zIndex, x, y){
8234             if(!pos){
8235                if(this.getStyle('position') == 'static'){
8236                    this.setStyle('position', 'relative');
8237                }
8238             }else{
8239                 this.setStyle("position", pos);
8240             }
8241             if(zIndex){
8242                 this.setStyle("z-index", zIndex);
8243             }
8244             if(x !== undefined && y !== undefined){
8245                 this.setXY([x, y]);
8246             }else if(x !== undefined){
8247                 this.setX(x);
8248             }else if(y !== undefined){
8249                 this.setY(y);
8250             }
8251         },
8252
8253         /**
8254         * Clear positioning back to the default when the document was loaded
8255         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8256         * @return {Roo.Element} this
8257          */
8258         clearPositioning : function(value){
8259             value = value ||'';
8260             this.setStyle({
8261                 "left": value,
8262                 "right": value,
8263                 "top": value,
8264                 "bottom": value,
8265                 "z-index": "",
8266                 "position" : "static"
8267             });
8268             return this;
8269         },
8270
8271         /**
8272         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8273         * snapshot before performing an update and then restoring the element.
8274         * @return {Object}
8275         */
8276         getPositioning : function(){
8277             var l = this.getStyle("left");
8278             var t = this.getStyle("top");
8279             return {
8280                 "position" : this.getStyle("position"),
8281                 "left" : l,
8282                 "right" : l ? "" : this.getStyle("right"),
8283                 "top" : t,
8284                 "bottom" : t ? "" : this.getStyle("bottom"),
8285                 "z-index" : this.getStyle("z-index")
8286             };
8287         },
8288
8289         /**
8290          * Gets the width of the border(s) for the specified side(s)
8291          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8292          * passing lr would get the border (l)eft width + the border (r)ight width.
8293          * @return {Number} The width of the sides passed added together
8294          */
8295         getBorderWidth : function(side){
8296             return this.addStyles(side, El.borders);
8297         },
8298
8299         /**
8300          * Gets the width of the padding(s) for the specified side(s)
8301          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8302          * passing lr would get the padding (l)eft + the padding (r)ight.
8303          * @return {Number} The padding of the sides passed added together
8304          */
8305         getPadding : function(side){
8306             return this.addStyles(side, El.paddings);
8307         },
8308
8309         /**
8310         * Set positioning with an object returned by getPositioning().
8311         * @param {Object} posCfg
8312         * @return {Roo.Element} this
8313          */
8314         setPositioning : function(pc){
8315             this.applyStyles(pc);
8316             if(pc.right == "auto"){
8317                 this.dom.style.right = "";
8318             }
8319             if(pc.bottom == "auto"){
8320                 this.dom.style.bottom = "";
8321             }
8322             return this;
8323         },
8324
8325         // private
8326         fixDisplay : function(){
8327             if(this.getStyle("display") == "none"){
8328                 this.setStyle("visibility", "hidden");
8329                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8330                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8331                     this.setStyle("display", "block");
8332                 }
8333             }
8334         },
8335
8336         /**
8337          * Quick set left and top adding default units
8338          * @param {String} left The left CSS property value
8339          * @param {String} top The top CSS property value
8340          * @return {Roo.Element} this
8341          */
8342          setLeftTop : function(left, top){
8343             this.dom.style.left = this.addUnits(left);
8344             this.dom.style.top = this.addUnits(top);
8345             return this;
8346         },
8347
8348         /**
8349          * Move this element relative to its current position.
8350          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8351          * @param {Number} distance How far to move the element in pixels
8352          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8353          * @return {Roo.Element} this
8354          */
8355          move : function(direction, distance, animate){
8356             var xy = this.getXY();
8357             direction = direction.toLowerCase();
8358             switch(direction){
8359                 case "l":
8360                 case "left":
8361                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8362                     break;
8363                case "r":
8364                case "right":
8365                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8366                     break;
8367                case "t":
8368                case "top":
8369                case "up":
8370                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8371                     break;
8372                case "b":
8373                case "bottom":
8374                case "down":
8375                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8376                     break;
8377             }
8378             return this;
8379         },
8380
8381         /**
8382          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8383          * @return {Roo.Element} this
8384          */
8385         clip : function(){
8386             if(!this.isClipped){
8387                this.isClipped = true;
8388                this.originalClip = {
8389                    "o": this.getStyle("overflow"),
8390                    "x": this.getStyle("overflow-x"),
8391                    "y": this.getStyle("overflow-y")
8392                };
8393                this.setStyle("overflow", "hidden");
8394                this.setStyle("overflow-x", "hidden");
8395                this.setStyle("overflow-y", "hidden");
8396             }
8397             return this;
8398         },
8399
8400         /**
8401          *  Return clipping (overflow) to original clipping before clip() was called
8402          * @return {Roo.Element} this
8403          */
8404         unclip : function(){
8405             if(this.isClipped){
8406                 this.isClipped = false;
8407                 var o = this.originalClip;
8408                 if(o.o){this.setStyle("overflow", o.o);}
8409                 if(o.x){this.setStyle("overflow-x", o.x);}
8410                 if(o.y){this.setStyle("overflow-y", o.y);}
8411             }
8412             return this;
8413         },
8414
8415
8416         /**
8417          * Gets the x,y coordinates specified by the anchor position on the element.
8418          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8419          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8420          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8421          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8422          * @return {Array} [x, y] An array containing the element's x and y coordinates
8423          */
8424         getAnchorXY : function(anchor, local, s){
8425             //Passing a different size is useful for pre-calculating anchors,
8426             //especially for anchored animations that change the el size.
8427
8428             var w, h, vp = false;
8429             if(!s){
8430                 var d = this.dom;
8431                 if(d == document.body || d == document){
8432                     vp = true;
8433                     w = D.getViewWidth(); h = D.getViewHeight();
8434                 }else{
8435                     w = this.getWidth(); h = this.getHeight();
8436                 }
8437             }else{
8438                 w = s.width;  h = s.height;
8439             }
8440             var x = 0, y = 0, r = Math.round;
8441             switch((anchor || "tl").toLowerCase()){
8442                 case "c":
8443                     x = r(w*.5);
8444                     y = r(h*.5);
8445                 break;
8446                 case "t":
8447                     x = r(w*.5);
8448                     y = 0;
8449                 break;
8450                 case "l":
8451                     x = 0;
8452                     y = r(h*.5);
8453                 break;
8454                 case "r":
8455                     x = w;
8456                     y = r(h*.5);
8457                 break;
8458                 case "b":
8459                     x = r(w*.5);
8460                     y = h;
8461                 break;
8462                 case "tl":
8463                     x = 0;
8464                     y = 0;
8465                 break;
8466                 case "bl":
8467                     x = 0;
8468                     y = h;
8469                 break;
8470                 case "br":
8471                     x = w;
8472                     y = h;
8473                 break;
8474                 case "tr":
8475                     x = w;
8476                     y = 0;
8477                 break;
8478             }
8479             if(local === true){
8480                 return [x, y];
8481             }
8482             if(vp){
8483                 var sc = this.getScroll();
8484                 return [x + sc.left, y + sc.top];
8485             }
8486             //Add the element's offset xy
8487             var o = this.getXY();
8488             return [x+o[0], y+o[1]];
8489         },
8490
8491         /**
8492          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8493          * supported position values.
8494          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8495          * @param {String} position The position to align to.
8496          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8497          * @return {Array} [x, y]
8498          */
8499         getAlignToXY : function(el, p, o){
8500             el = Roo.get(el);
8501             var d = this.dom;
8502             if(!el.dom){
8503                 throw "Element.alignTo with an element that doesn't exist";
8504             }
8505             var c = false; //constrain to viewport
8506             var p1 = "", p2 = "";
8507             o = o || [0,0];
8508
8509             if(!p){
8510                 p = "tl-bl";
8511             }else if(p == "?"){
8512                 p = "tl-bl?";
8513             }else if(p.indexOf("-") == -1){
8514                 p = "tl-" + p;
8515             }
8516             p = p.toLowerCase();
8517             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8518             if(!m){
8519                throw "Element.alignTo with an invalid alignment " + p;
8520             }
8521             p1 = m[1]; p2 = m[2]; c = !!m[3];
8522
8523             //Subtract the aligned el's internal xy from the target's offset xy
8524             //plus custom offset to get the aligned el's new offset xy
8525             var a1 = this.getAnchorXY(p1, true);
8526             var a2 = el.getAnchorXY(p2, false);
8527             var x = a2[0] - a1[0] + o[0];
8528             var y = a2[1] - a1[1] + o[1];
8529             if(c){
8530                 //constrain the aligned el to viewport if necessary
8531                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8532                 // 5px of margin for ie
8533                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8534
8535                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8536                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8537                 //otherwise swap the aligned el to the opposite border of the target.
8538                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8539                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8540                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8541                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8542
8543                var doc = document;
8544                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8545                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8546
8547                if((x+w) > dw + scrollX){
8548                     x = swapX ? r.left-w : dw+scrollX-w;
8549                 }
8550                if(x < scrollX){
8551                    x = swapX ? r.right : scrollX;
8552                }
8553                if((y+h) > dh + scrollY){
8554                     y = swapY ? r.top-h : dh+scrollY-h;
8555                 }
8556                if (y < scrollY){
8557                    y = swapY ? r.bottom : scrollY;
8558                }
8559             }
8560             return [x,y];
8561         },
8562
8563         // private
8564         getConstrainToXY : function(){
8565             var os = {top:0, left:0, bottom:0, right: 0};
8566
8567             return function(el, local, offsets, proposedXY){
8568                 el = Roo.get(el);
8569                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8570
8571                 var vw, vh, vx = 0, vy = 0;
8572                 if(el.dom == document.body || el.dom == document){
8573                     vw = Roo.lib.Dom.getViewWidth();
8574                     vh = Roo.lib.Dom.getViewHeight();
8575                 }else{
8576                     vw = el.dom.clientWidth;
8577                     vh = el.dom.clientHeight;
8578                     if(!local){
8579                         var vxy = el.getXY();
8580                         vx = vxy[0];
8581                         vy = vxy[1];
8582                     }
8583                 }
8584
8585                 var s = el.getScroll();
8586
8587                 vx += offsets.left + s.left;
8588                 vy += offsets.top + s.top;
8589
8590                 vw -= offsets.right;
8591                 vh -= offsets.bottom;
8592
8593                 var vr = vx+vw;
8594                 var vb = vy+vh;
8595
8596                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8597                 var x = xy[0], y = xy[1];
8598                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8599
8600                 // only move it if it needs it
8601                 var moved = false;
8602
8603                 // first validate right/bottom
8604                 if((x + w) > vr){
8605                     x = vr - w;
8606                     moved = true;
8607                 }
8608                 if((y + h) > vb){
8609                     y = vb - h;
8610                     moved = true;
8611                 }
8612                 // then make sure top/left isn't negative
8613                 if(x < vx){
8614                     x = vx;
8615                     moved = true;
8616                 }
8617                 if(y < vy){
8618                     y = vy;
8619                     moved = true;
8620                 }
8621                 return moved ? [x, y] : false;
8622             };
8623         }(),
8624
8625         // private
8626         adjustForConstraints : function(xy, parent, offsets){
8627             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8628         },
8629
8630         /**
8631          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8632          * document it aligns it to the viewport.
8633          * The position parameter is optional, and can be specified in any one of the following formats:
8634          * <ul>
8635          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8636          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8637          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8638          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8639          *   <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
8640          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8641          * </ul>
8642          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8643          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8644          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8645          * that specified in order to enforce the viewport constraints.
8646          * Following are all of the supported anchor positions:
8647     <pre>
8648     Value  Description
8649     -----  -----------------------------
8650     tl     The top left corner (default)
8651     t      The center of the top edge
8652     tr     The top right corner
8653     l      The center of the left edge
8654     c      In the center of the element
8655     r      The center of the right edge
8656     bl     The bottom left corner
8657     b      The center of the bottom edge
8658     br     The bottom right corner
8659     </pre>
8660     Example Usage:
8661     <pre><code>
8662     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8663     el.alignTo("other-el");
8664
8665     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8666     el.alignTo("other-el", "tr?");
8667
8668     // align the bottom right corner of el with the center left edge of other-el
8669     el.alignTo("other-el", "br-l?");
8670
8671     // align the center of el with the bottom left corner of other-el and
8672     // adjust the x position by -6 pixels (and the y position by 0)
8673     el.alignTo("other-el", "c-bl", [-6, 0]);
8674     </code></pre>
8675          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8676          * @param {String} position The position to align to.
8677          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8678          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8679          * @return {Roo.Element} this
8680          */
8681         alignTo : function(element, position, offsets, animate){
8682             var xy = this.getAlignToXY(element, position, offsets);
8683             this.setXY(xy, this.preanim(arguments, 3));
8684             return this;
8685         },
8686
8687         /**
8688          * Anchors an element to another element and realigns it when the window is resized.
8689          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8690          * @param {String} position The position to align to.
8691          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8692          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8693          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8694          * is a number, it is used as the buffer delay (defaults to 50ms).
8695          * @param {Function} callback The function to call after the animation finishes
8696          * @return {Roo.Element} this
8697          */
8698         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8699             var action = function(){
8700                 this.alignTo(el, alignment, offsets, animate);
8701                 Roo.callback(callback, this);
8702             };
8703             Roo.EventManager.onWindowResize(action, this);
8704             var tm = typeof monitorScroll;
8705             if(tm != 'undefined'){
8706                 Roo.EventManager.on(window, 'scroll', action, this,
8707                     {buffer: tm == 'number' ? monitorScroll : 50});
8708             }
8709             action.call(this); // align immediately
8710             return this;
8711         },
8712         /**
8713          * Clears any opacity settings from this element. Required in some cases for IE.
8714          * @return {Roo.Element} this
8715          */
8716         clearOpacity : function(){
8717             if (window.ActiveXObject) {
8718                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8719                     this.dom.style.filter = "";
8720                 }
8721             } else {
8722                 this.dom.style.opacity = "";
8723                 this.dom.style["-moz-opacity"] = "";
8724                 this.dom.style["-khtml-opacity"] = "";
8725             }
8726             return this;
8727         },
8728
8729         /**
8730          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8731          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8732          * @return {Roo.Element} this
8733          */
8734         hide : function(animate){
8735             this.setVisible(false, this.preanim(arguments, 0));
8736             return this;
8737         },
8738
8739         /**
8740         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8741         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8742          * @return {Roo.Element} this
8743          */
8744         show : function(animate){
8745             this.setVisible(true, this.preanim(arguments, 0));
8746             return this;
8747         },
8748
8749         /**
8750          * @private Test if size has a unit, otherwise appends the default
8751          */
8752         addUnits : function(size){
8753             return Roo.Element.addUnits(size, this.defaultUnit);
8754         },
8755
8756         /**
8757          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8758          * @return {Roo.Element} this
8759          */
8760         beginMeasure : function(){
8761             var el = this.dom;
8762             if(el.offsetWidth || el.offsetHeight){
8763                 return this; // offsets work already
8764             }
8765             var changed = [];
8766             var p = this.dom, b = document.body; // start with this element
8767             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8768                 var pe = Roo.get(p);
8769                 if(pe.getStyle('display') == 'none'){
8770                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8771                     p.style.visibility = "hidden";
8772                     p.style.display = "block";
8773                 }
8774                 p = p.parentNode;
8775             }
8776             this._measureChanged = changed;
8777             return this;
8778
8779         },
8780
8781         /**
8782          * Restores displays to before beginMeasure was called
8783          * @return {Roo.Element} this
8784          */
8785         endMeasure : function(){
8786             var changed = this._measureChanged;
8787             if(changed){
8788                 for(var i = 0, len = changed.length; i < len; i++) {
8789                     var r = changed[i];
8790                     r.el.style.visibility = r.visibility;
8791                     r.el.style.display = "none";
8792                 }
8793                 this._measureChanged = null;
8794             }
8795             return this;
8796         },
8797
8798         /**
8799         * Update the innerHTML of this element, optionally searching for and processing scripts
8800         * @param {String} html The new HTML
8801         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8802         * @param {Function} callback For async script loading you can be noticed when the update completes
8803         * @return {Roo.Element} this
8804          */
8805         update : function(html, loadScripts, callback){
8806             if(typeof html == "undefined"){
8807                 html = "";
8808             }
8809             if(loadScripts !== true){
8810                 this.dom.innerHTML = html;
8811                 if(typeof callback == "function"){
8812                     callback();
8813                 }
8814                 return this;
8815             }
8816             var id = Roo.id();
8817             var dom = this.dom;
8818
8819             html += '<span id="' + id + '"></span>';
8820
8821             E.onAvailable(id, function(){
8822                 var hd = document.getElementsByTagName("head")[0];
8823                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8824                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8825                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8826
8827                 var match;
8828                 while(match = re.exec(html)){
8829                     var attrs = match[1];
8830                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8831                     if(srcMatch && srcMatch[2]){
8832                        var s = document.createElement("script");
8833                        s.src = srcMatch[2];
8834                        var typeMatch = attrs.match(typeRe);
8835                        if(typeMatch && typeMatch[2]){
8836                            s.type = typeMatch[2];
8837                        }
8838                        hd.appendChild(s);
8839                     }else if(match[2] && match[2].length > 0){
8840                         if(window.execScript) {
8841                            window.execScript(match[2]);
8842                         } else {
8843                             /**
8844                              * eval:var:id
8845                              * eval:var:dom
8846                              * eval:var:html
8847                              * 
8848                              */
8849                            window.eval(match[2]);
8850                         }
8851                     }
8852                 }
8853                 var el = document.getElementById(id);
8854                 if(el){el.parentNode.removeChild(el);}
8855                 if(typeof callback == "function"){
8856                     callback();
8857                 }
8858             });
8859             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8860             return this;
8861         },
8862
8863         /**
8864          * Direct access to the UpdateManager update() method (takes the same parameters).
8865          * @param {String/Function} url The url for this request or a function to call to get the url
8866          * @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}
8867          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8868          * @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.
8869          * @return {Roo.Element} this
8870          */
8871         load : function(){
8872             var um = this.getUpdateManager();
8873             um.update.apply(um, arguments);
8874             return this;
8875         },
8876
8877         /**
8878         * Gets this element's UpdateManager
8879         * @return {Roo.UpdateManager} The UpdateManager
8880         */
8881         getUpdateManager : function(){
8882             if(!this.updateManager){
8883                 this.updateManager = new Roo.UpdateManager(this);
8884             }
8885             return this.updateManager;
8886         },
8887
8888         /**
8889          * Disables text selection for this element (normalized across browsers)
8890          * @return {Roo.Element} this
8891          */
8892         unselectable : function(){
8893             this.dom.unselectable = "on";
8894             this.swallowEvent("selectstart", true);
8895             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8896             this.addClass("x-unselectable");
8897             return this;
8898         },
8899
8900         /**
8901         * Calculates the x, y to center this element on the screen
8902         * @return {Array} The x, y values [x, y]
8903         */
8904         getCenterXY : function(){
8905             return this.getAlignToXY(document, 'c-c');
8906         },
8907
8908         /**
8909         * Centers the Element in either the viewport, or another Element.
8910         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8911         */
8912         center : function(centerIn){
8913             this.alignTo(centerIn || document, 'c-c');
8914             return this;
8915         },
8916
8917         /**
8918          * Tests various css rules/browsers to determine if this element uses a border box
8919          * @return {Boolean}
8920          */
8921         isBorderBox : function(){
8922             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8923         },
8924
8925         /**
8926          * Return a box {x, y, width, height} that can be used to set another elements
8927          * size/location to match this element.
8928          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8929          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8930          * @return {Object} box An object in the format {x, y, width, height}
8931          */
8932         getBox : function(contentBox, local){
8933             var xy;
8934             if(!local){
8935                 xy = this.getXY();
8936             }else{
8937                 var left = parseInt(this.getStyle("left"), 10) || 0;
8938                 var top = parseInt(this.getStyle("top"), 10) || 0;
8939                 xy = [left, top];
8940             }
8941             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8942             if(!contentBox){
8943                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8944             }else{
8945                 var l = this.getBorderWidth("l")+this.getPadding("l");
8946                 var r = this.getBorderWidth("r")+this.getPadding("r");
8947                 var t = this.getBorderWidth("t")+this.getPadding("t");
8948                 var b = this.getBorderWidth("b")+this.getPadding("b");
8949                 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)};
8950             }
8951             bx.right = bx.x + bx.width;
8952             bx.bottom = bx.y + bx.height;
8953             return bx;
8954         },
8955
8956         /**
8957          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8958          for more information about the sides.
8959          * @param {String} sides
8960          * @return {Number}
8961          */
8962         getFrameWidth : function(sides, onlyContentBox){
8963             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8964         },
8965
8966         /**
8967          * 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.
8968          * @param {Object} box The box to fill {x, y, width, height}
8969          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8970          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8971          * @return {Roo.Element} this
8972          */
8973         setBox : function(box, adjust, animate){
8974             var w = box.width, h = box.height;
8975             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8976                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8977                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8978             }
8979             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8980             return this;
8981         },
8982
8983         /**
8984          * Forces the browser to repaint this element
8985          * @return {Roo.Element} this
8986          */
8987          repaint : function(){
8988             var dom = this.dom;
8989             this.addClass("x-repaint");
8990             setTimeout(function(){
8991                 Roo.get(dom).removeClass("x-repaint");
8992             }, 1);
8993             return this;
8994         },
8995
8996         /**
8997          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8998          * then it returns the calculated width of the sides (see getPadding)
8999          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9000          * @return {Object/Number}
9001          */
9002         getMargins : function(side){
9003             if(!side){
9004                 return {
9005                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
9006                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
9007                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9008                     right: parseInt(this.getStyle("margin-right"), 10) || 0
9009                 };
9010             }else{
9011                 return this.addStyles(side, El.margins);
9012              }
9013         },
9014
9015         // private
9016         addStyles : function(sides, styles){
9017             var val = 0, v, w;
9018             for(var i = 0, len = sides.length; i < len; i++){
9019                 v = this.getStyle(styles[sides.charAt(i)]);
9020                 if(v){
9021                      w = parseInt(v, 10);
9022                      if(w){ val += w; }
9023                 }
9024             }
9025             return val;
9026         },
9027
9028         /**
9029          * Creates a proxy element of this element
9030          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9031          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9032          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9033          * @return {Roo.Element} The new proxy element
9034          */
9035         createProxy : function(config, renderTo, matchBox){
9036             if(renderTo){
9037                 renderTo = Roo.getDom(renderTo);
9038             }else{
9039                 renderTo = document.body;
9040             }
9041             config = typeof config == "object" ?
9042                 config : {tag : "div", cls: config};
9043             var proxy = Roo.DomHelper.append(renderTo, config, true);
9044             if(matchBox){
9045                proxy.setBox(this.getBox());
9046             }
9047             return proxy;
9048         },
9049
9050         /**
9051          * Puts a mask over this element to disable user interaction. Requires core.css.
9052          * This method can only be applied to elements which accept child nodes.
9053          * @param {String} msg (optional) A message to display in the mask
9054          * @param {String} msgCls (optional) A css class to apply to the msg element
9055          * @return {Element} The mask  element
9056          */
9057         mask : function(msg, msgCls)
9058         {
9059             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9060                 this.setStyle("position", "relative");
9061             }
9062             if(!this._mask){
9063                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9064             }
9065             this.addClass("x-masked");
9066             this._mask.setDisplayed(true);
9067             
9068             // we wander
9069             var z = 0;
9070             var dom = this.dom;
9071             while (dom && dom.style) {
9072                 if (!isNaN(parseInt(dom.style.zIndex))) {
9073                     z = Math.max(z, parseInt(dom.style.zIndex));
9074                 }
9075                 dom = dom.parentNode;
9076             }
9077             // if we are masking the body - then it hides everything..
9078             if (this.dom == document.body) {
9079                 z = 1000000;
9080                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9081                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9082             }
9083            
9084             if(typeof msg == 'string'){
9085                 if(!this._maskMsg){
9086                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9087                 }
9088                 var mm = this._maskMsg;
9089                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9090                 if (mm.dom.firstChild) { // weird IE issue?
9091                     mm.dom.firstChild.innerHTML = msg;
9092                 }
9093                 mm.setDisplayed(true);
9094                 mm.center(this);
9095                 mm.setStyle('z-index', z + 102);
9096             }
9097             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9098                 this._mask.setHeight(this.getHeight());
9099             }
9100             this._mask.setStyle('z-index', z + 100);
9101             
9102             return this._mask;
9103         },
9104
9105         /**
9106          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9107          * it is cached for reuse.
9108          */
9109         unmask : function(removeEl){
9110             if(this._mask){
9111                 if(removeEl === true){
9112                     this._mask.remove();
9113                     delete this._mask;
9114                     if(this._maskMsg){
9115                         this._maskMsg.remove();
9116                         delete this._maskMsg;
9117                     }
9118                 }else{
9119                     this._mask.setDisplayed(false);
9120                     if(this._maskMsg){
9121                         this._maskMsg.setDisplayed(false);
9122                     }
9123                 }
9124             }
9125             this.removeClass("x-masked");
9126         },
9127
9128         /**
9129          * Returns true if this element is masked
9130          * @return {Boolean}
9131          */
9132         isMasked : function(){
9133             return this._mask && this._mask.isVisible();
9134         },
9135
9136         /**
9137          * Creates an iframe shim for this element to keep selects and other windowed objects from
9138          * showing through.
9139          * @return {Roo.Element} The new shim element
9140          */
9141         createShim : function(){
9142             var el = document.createElement('iframe');
9143             el.frameBorder = 'no';
9144             el.className = 'roo-shim';
9145             if(Roo.isIE && Roo.isSecure){
9146                 el.src = Roo.SSL_SECURE_URL;
9147             }
9148             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9149             shim.autoBoxAdjust = false;
9150             return shim;
9151         },
9152
9153         /**
9154          * Removes this element from the DOM and deletes it from the cache
9155          */
9156         remove : function(){
9157             if(this.dom.parentNode){
9158                 this.dom.parentNode.removeChild(this.dom);
9159             }
9160             delete El.cache[this.dom.id];
9161         },
9162
9163         /**
9164          * Sets up event handlers to add and remove a css class when the mouse is over this element
9165          * @param {String} className
9166          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9167          * mouseout events for children elements
9168          * @return {Roo.Element} this
9169          */
9170         addClassOnOver : function(className, preventFlicker){
9171             this.on("mouseover", function(){
9172                 Roo.fly(this, '_internal').addClass(className);
9173             }, this.dom);
9174             var removeFn = function(e){
9175                 if(preventFlicker !== true || !e.within(this, true)){
9176                     Roo.fly(this, '_internal').removeClass(className);
9177                 }
9178             };
9179             this.on("mouseout", removeFn, this.dom);
9180             return this;
9181         },
9182
9183         /**
9184          * Sets up event handlers to add and remove a css class when this element has the focus
9185          * @param {String} className
9186          * @return {Roo.Element} this
9187          */
9188         addClassOnFocus : function(className){
9189             this.on("focus", function(){
9190                 Roo.fly(this, '_internal').addClass(className);
9191             }, this.dom);
9192             this.on("blur", function(){
9193                 Roo.fly(this, '_internal').removeClass(className);
9194             }, this.dom);
9195             return this;
9196         },
9197         /**
9198          * 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)
9199          * @param {String} className
9200          * @return {Roo.Element} this
9201          */
9202         addClassOnClick : function(className){
9203             var dom = this.dom;
9204             this.on("mousedown", function(){
9205                 Roo.fly(dom, '_internal').addClass(className);
9206                 var d = Roo.get(document);
9207                 var fn = function(){
9208                     Roo.fly(dom, '_internal').removeClass(className);
9209                     d.removeListener("mouseup", fn);
9210                 };
9211                 d.on("mouseup", fn);
9212             });
9213             return this;
9214         },
9215
9216         /**
9217          * Stops the specified event from bubbling and optionally prevents the default action
9218          * @param {String} eventName
9219          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9220          * @return {Roo.Element} this
9221          */
9222         swallowEvent : function(eventName, preventDefault){
9223             var fn = function(e){
9224                 e.stopPropagation();
9225                 if(preventDefault){
9226                     e.preventDefault();
9227                 }
9228             };
9229             if(eventName instanceof Array){
9230                 for(var i = 0, len = eventName.length; i < len; i++){
9231                      this.on(eventName[i], fn);
9232                 }
9233                 return this;
9234             }
9235             this.on(eventName, fn);
9236             return this;
9237         },
9238
9239         /**
9240          * @private
9241          */
9242       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9243
9244         /**
9245          * Sizes this element to its parent element's dimensions performing
9246          * neccessary box adjustments.
9247          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9248          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9249          * @return {Roo.Element} this
9250          */
9251         fitToParent : function(monitorResize, targetParent) {
9252           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9253           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9254           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9255             return;
9256           }
9257           var p = Roo.get(targetParent || this.dom.parentNode);
9258           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9259           if (monitorResize === true) {
9260             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9261             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9262           }
9263           return this;
9264         },
9265
9266         /**
9267          * Gets the next sibling, skipping text nodes
9268          * @return {HTMLElement} The next sibling or null
9269          */
9270         getNextSibling : function(){
9271             var n = this.dom.nextSibling;
9272             while(n && n.nodeType != 1){
9273                 n = n.nextSibling;
9274             }
9275             return n;
9276         },
9277
9278         /**
9279          * Gets the previous sibling, skipping text nodes
9280          * @return {HTMLElement} The previous sibling or null
9281          */
9282         getPrevSibling : function(){
9283             var n = this.dom.previousSibling;
9284             while(n && n.nodeType != 1){
9285                 n = n.previousSibling;
9286             }
9287             return n;
9288         },
9289
9290
9291         /**
9292          * Appends the passed element(s) to this element
9293          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9294          * @return {Roo.Element} this
9295          */
9296         appendChild: function(el){
9297             el = Roo.get(el);
9298             el.appendTo(this);
9299             return this;
9300         },
9301
9302         /**
9303          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9304          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9305          * automatically generated with the specified attributes.
9306          * @param {HTMLElement} insertBefore (optional) a child element of this element
9307          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9308          * @return {Roo.Element} The new child element
9309          */
9310         createChild: function(config, insertBefore, returnDom){
9311             config = config || {tag:'div'};
9312             if(insertBefore){
9313                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9314             }
9315             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9316         },
9317
9318         /**
9319          * Appends this element to the passed element
9320          * @param {String/HTMLElement/Element} el The new parent element
9321          * @return {Roo.Element} this
9322          */
9323         appendTo: function(el){
9324             el = Roo.getDom(el);
9325             el.appendChild(this.dom);
9326             return this;
9327         },
9328
9329         /**
9330          * Inserts this element before the passed element in the DOM
9331          * @param {String/HTMLElement/Element} el The element to insert before
9332          * @return {Roo.Element} this
9333          */
9334         insertBefore: function(el){
9335             el = Roo.getDom(el);
9336             el.parentNode.insertBefore(this.dom, el);
9337             return this;
9338         },
9339
9340         /**
9341          * Inserts this element after the passed element in the DOM
9342          * @param {String/HTMLElement/Element} el The element to insert after
9343          * @return {Roo.Element} this
9344          */
9345         insertAfter: function(el){
9346             el = Roo.getDom(el);
9347             el.parentNode.insertBefore(this.dom, el.nextSibling);
9348             return this;
9349         },
9350
9351         /**
9352          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9353          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9354          * @return {Roo.Element} The new child
9355          */
9356         insertFirst: function(el, returnDom){
9357             el = el || {};
9358             if(typeof el == 'object' && !el.nodeType){ // dh config
9359                 return this.createChild(el, this.dom.firstChild, returnDom);
9360             }else{
9361                 el = Roo.getDom(el);
9362                 this.dom.insertBefore(el, this.dom.firstChild);
9363                 return !returnDom ? Roo.get(el) : el;
9364             }
9365         },
9366
9367         /**
9368          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9369          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9370          * @param {String} where (optional) 'before' or 'after' defaults to before
9371          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9372          * @return {Roo.Element} the inserted Element
9373          */
9374         insertSibling: function(el, where, returnDom){
9375             where = where ? where.toLowerCase() : 'before';
9376             el = el || {};
9377             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9378
9379             if(typeof el == 'object' && !el.nodeType){ // dh config
9380                 if(where == 'after' && !this.dom.nextSibling){
9381                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9382                 }else{
9383                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9384                 }
9385
9386             }else{
9387                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9388                             where == 'before' ? this.dom : this.dom.nextSibling);
9389                 if(!returnDom){
9390                     rt = Roo.get(rt);
9391                 }
9392             }
9393             return rt;
9394         },
9395
9396         /**
9397          * Creates and wraps this element with another element
9398          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9399          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9400          * @return {HTMLElement/Element} The newly created wrapper element
9401          */
9402         wrap: function(config, returnDom){
9403             if(!config){
9404                 config = {tag: "div"};
9405             }
9406             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9407             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9408             return newEl;
9409         },
9410
9411         /**
9412          * Replaces the passed element with this element
9413          * @param {String/HTMLElement/Element} el The element to replace
9414          * @return {Roo.Element} this
9415          */
9416         replace: function(el){
9417             el = Roo.get(el);
9418             this.insertBefore(el);
9419             el.remove();
9420             return this;
9421         },
9422
9423         /**
9424          * Inserts an html fragment into this element
9425          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9426          * @param {String} html The HTML fragment
9427          * @param {Boolean} returnEl True to return an Roo.Element
9428          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9429          */
9430         insertHtml : function(where, html, returnEl){
9431             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9432             return returnEl ? Roo.get(el) : el;
9433         },
9434
9435         /**
9436          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9437          * @param {Object} o The object with the attributes
9438          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9439          * @return {Roo.Element} this
9440          */
9441         set : function(o, useSet){
9442             var el = this.dom;
9443             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9444             for(var attr in o){
9445                 if(attr == "style" || typeof o[attr] == "function")  { continue; }
9446                 if(attr=="cls"){
9447                     el.className = o["cls"];
9448                 }else{
9449                     if(useSet) {
9450                         el.setAttribute(attr, o[attr]);
9451                     } else {
9452                         el[attr] = o[attr];
9453                     }
9454                 }
9455             }
9456             if(o.style){
9457                 Roo.DomHelper.applyStyles(el, o.style);
9458             }
9459             return this;
9460         },
9461
9462         /**
9463          * Convenience method for constructing a KeyMap
9464          * @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:
9465          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9466          * @param {Function} fn The function to call
9467          * @param {Object} scope (optional) The scope of the function
9468          * @return {Roo.KeyMap} The KeyMap created
9469          */
9470         addKeyListener : function(key, fn, scope){
9471             var config;
9472             if(typeof key != "object" || key instanceof Array){
9473                 config = {
9474                     key: key,
9475                     fn: fn,
9476                     scope: scope
9477                 };
9478             }else{
9479                 config = {
9480                     key : key.key,
9481                     shift : key.shift,
9482                     ctrl : key.ctrl,
9483                     alt : key.alt,
9484                     fn: fn,
9485                     scope: scope
9486                 };
9487             }
9488             return new Roo.KeyMap(this, config);
9489         },
9490
9491         /**
9492          * Creates a KeyMap for this element
9493          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9494          * @return {Roo.KeyMap} The KeyMap created
9495          */
9496         addKeyMap : function(config){
9497             return new Roo.KeyMap(this, config);
9498         },
9499
9500         /**
9501          * Returns true if this element is scrollable.
9502          * @return {Boolean}
9503          */
9504          isScrollable : function(){
9505             var dom = this.dom;
9506             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9507         },
9508
9509         /**
9510          * 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().
9511          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9512          * @param {Number} value The new scroll value
9513          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9514          * @return {Element} this
9515          */
9516
9517         scrollTo : function(side, value, animate){
9518             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9519             if(!animate || !A){
9520                 this.dom[prop] = value;
9521             }else{
9522                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9523                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9524             }
9525             return this;
9526         },
9527
9528         /**
9529          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9530          * within this element's scrollable range.
9531          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9532          * @param {Number} distance How far to scroll the element in pixels
9533          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9534          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9535          * was scrolled as far as it could go.
9536          */
9537          scroll : function(direction, distance, animate){
9538              if(!this.isScrollable()){
9539                  return;
9540              }
9541              var el = this.dom;
9542              var l = el.scrollLeft, t = el.scrollTop;
9543              var w = el.scrollWidth, h = el.scrollHeight;
9544              var cw = el.clientWidth, ch = el.clientHeight;
9545              direction = direction.toLowerCase();
9546              var scrolled = false;
9547              var a = this.preanim(arguments, 2);
9548              switch(direction){
9549                  case "l":
9550                  case "left":
9551                      if(w - l > cw){
9552                          var v = Math.min(l + distance, w-cw);
9553                          this.scrollTo("left", v, a);
9554                          scrolled = true;
9555                      }
9556                      break;
9557                 case "r":
9558                 case "right":
9559                      if(l > 0){
9560                          var v = Math.max(l - distance, 0);
9561                          this.scrollTo("left", v, a);
9562                          scrolled = true;
9563                      }
9564                      break;
9565                 case "t":
9566                 case "top":
9567                 case "up":
9568                      if(t > 0){
9569                          var v = Math.max(t - distance, 0);
9570                          this.scrollTo("top", v, a);
9571                          scrolled = true;
9572                      }
9573                      break;
9574                 case "b":
9575                 case "bottom":
9576                 case "down":
9577                      if(h - t > ch){
9578                          var v = Math.min(t + distance, h-ch);
9579                          this.scrollTo("top", v, a);
9580                          scrolled = true;
9581                      }
9582                      break;
9583              }
9584              return scrolled;
9585         },
9586
9587         /**
9588          * Translates the passed page coordinates into left/top css values for this element
9589          * @param {Number/Array} x The page x or an array containing [x, y]
9590          * @param {Number} y The page y
9591          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9592          */
9593         translatePoints : function(x, y){
9594             if(typeof x == 'object' || x instanceof Array){
9595                 y = x[1]; x = x[0];
9596             }
9597             var p = this.getStyle('position');
9598             var o = this.getXY();
9599
9600             var l = parseInt(this.getStyle('left'), 10);
9601             var t = parseInt(this.getStyle('top'), 10);
9602
9603             if(isNaN(l)){
9604                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9605             }
9606             if(isNaN(t)){
9607                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9608             }
9609
9610             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9611         },
9612
9613         /**
9614          * Returns the current scroll position of the element.
9615          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9616          */
9617         getScroll : function(){
9618             var d = this.dom, doc = document;
9619             if(d == doc || d == doc.body){
9620                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9621                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9622                 return {left: l, top: t};
9623             }else{
9624                 return {left: d.scrollLeft, top: d.scrollTop};
9625             }
9626         },
9627
9628         /**
9629          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9630          * are convert to standard 6 digit hex color.
9631          * @param {String} attr The css attribute
9632          * @param {String} defaultValue The default value to use when a valid color isn't found
9633          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9634          * YUI color anims.
9635          */
9636         getColor : function(attr, defaultValue, prefix){
9637             var v = this.getStyle(attr);
9638             if(!v || v == "transparent" || v == "inherit") {
9639                 return defaultValue;
9640             }
9641             var color = typeof prefix == "undefined" ? "#" : prefix;
9642             if(v.substr(0, 4) == "rgb("){
9643                 var rvs = v.slice(4, v.length -1).split(",");
9644                 for(var i = 0; i < 3; i++){
9645                     var h = parseInt(rvs[i]).toString(16);
9646                     if(h < 16){
9647                         h = "0" + h;
9648                     }
9649                     color += h;
9650                 }
9651             } else {
9652                 if(v.substr(0, 1) == "#"){
9653                     if(v.length == 4) {
9654                         for(var i = 1; i < 4; i++){
9655                             var c = v.charAt(i);
9656                             color +=  c + c;
9657                         }
9658                     }else if(v.length == 7){
9659                         color += v.substr(1);
9660                     }
9661                 }
9662             }
9663             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9664         },
9665
9666         /**
9667          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9668          * gradient background, rounded corners and a 4-way shadow.
9669          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9670          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9671          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9672          * @return {Roo.Element} this
9673          */
9674         boxWrap : function(cls){
9675             cls = cls || 'x-box';
9676             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9677             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9678             return el;
9679         },
9680
9681         /**
9682          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9683          * @param {String} namespace The namespace in which to look for the attribute
9684          * @param {String} name The attribute name
9685          * @return {String} The attribute value
9686          */
9687         getAttributeNS : Roo.isIE ? function(ns, name){
9688             var d = this.dom;
9689             var type = typeof d[ns+":"+name];
9690             if(type != 'undefined' && type != 'unknown'){
9691                 return d[ns+":"+name];
9692             }
9693             return d[name];
9694         } : function(ns, name){
9695             var d = this.dom;
9696             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9697         },
9698         
9699         
9700         /**
9701          * Sets or Returns the value the dom attribute value
9702          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9703          * @param {String} value (optional) The value to set the attribute to
9704          * @return {String} The attribute value
9705          */
9706         attr : function(name){
9707             if (arguments.length > 1) {
9708                 this.dom.setAttribute(name, arguments[1]);
9709                 return arguments[1];
9710             }
9711             if (typeof(name) == 'object') {
9712                 for(var i in name) {
9713                     this.attr(i, name[i]);
9714                 }
9715                 return name;
9716             }
9717             
9718             
9719             if (!this.dom.hasAttribute(name)) {
9720                 return undefined;
9721             }
9722             return this.dom.getAttribute(name);
9723         }
9724         
9725         
9726         
9727     };
9728
9729     var ep = El.prototype;
9730
9731     /**
9732      * Appends an event handler (Shorthand for addListener)
9733      * @param {String}   eventName     The type of event to append
9734      * @param {Function} fn        The method the event invokes
9735      * @param {Object} scope       (optional) The scope (this object) of the fn
9736      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9737      * @method
9738      */
9739     ep.on = ep.addListener;
9740         // backwards compat
9741     ep.mon = ep.addListener;
9742
9743     /**
9744      * Removes an event handler from this element (shorthand for removeListener)
9745      * @param {String} eventName the type of event to remove
9746      * @param {Function} fn the method the event invokes
9747      * @return {Roo.Element} this
9748      * @method
9749      */
9750     ep.un = ep.removeListener;
9751
9752     /**
9753      * true to automatically adjust width and height settings for box-model issues (default to true)
9754      */
9755     ep.autoBoxAdjust = true;
9756
9757     // private
9758     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9759
9760     // private
9761     El.addUnits = function(v, defaultUnit){
9762         if(v === "" || v == "auto"){
9763             return v;
9764         }
9765         if(v === undefined){
9766             return '';
9767         }
9768         if(typeof v == "number" || !El.unitPattern.test(v)){
9769             return v + (defaultUnit || 'px');
9770         }
9771         return v;
9772     };
9773
9774     // special markup used throughout Roo when box wrapping elements
9775     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>';
9776     /**
9777      * Visibility mode constant - Use visibility to hide element
9778      * @static
9779      * @type Number
9780      */
9781     El.VISIBILITY = 1;
9782     /**
9783      * Visibility mode constant - Use display to hide element
9784      * @static
9785      * @type Number
9786      */
9787     El.DISPLAY = 2;
9788
9789     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9790     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9791     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9792
9793
9794
9795     /**
9796      * @private
9797      */
9798     El.cache = {};
9799
9800     var docEl;
9801
9802     /**
9803      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9804      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9805      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9806      * @return {Element} The Element object
9807      * @static
9808      */
9809     El.get = function(el){
9810         var ex, elm, id;
9811         if(!el){ return null; }
9812         if(typeof el == "string"){ // element id
9813             if(!(elm = document.getElementById(el))){
9814                 return null;
9815             }
9816             if(ex = El.cache[el]){
9817                 ex.dom = elm;
9818             }else{
9819                 ex = El.cache[el] = new El(elm);
9820             }
9821             return ex;
9822         }else if(el.tagName){ // dom element
9823             if(!(id = el.id)){
9824                 id = Roo.id(el);
9825             }
9826             if(ex = El.cache[id]){
9827                 ex.dom = el;
9828             }else{
9829                 ex = El.cache[id] = new El(el);
9830             }
9831             return ex;
9832         }else if(el instanceof El){
9833             if(el != docEl){
9834                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9835                                                               // catch case where it hasn't been appended
9836                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9837             }
9838             return el;
9839         }else if(el.isComposite){
9840             return el;
9841         }else if(el instanceof Array){
9842             return El.select(el);
9843         }else if(el == document){
9844             // create a bogus element object representing the document object
9845             if(!docEl){
9846                 var f = function(){};
9847                 f.prototype = El.prototype;
9848                 docEl = new f();
9849                 docEl.dom = document;
9850             }
9851             return docEl;
9852         }
9853         return null;
9854     };
9855
9856     // private
9857     El.uncache = function(el){
9858         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9859             if(a[i]){
9860                 delete El.cache[a[i].id || a[i]];
9861             }
9862         }
9863     };
9864
9865     // private
9866     // Garbage collection - uncache elements/purge listeners on orphaned elements
9867     // so we don't hold a reference and cause the browser to retain them
9868     El.garbageCollect = function(){
9869         if(!Roo.enableGarbageCollector){
9870             clearInterval(El.collectorThread);
9871             return;
9872         }
9873         for(var eid in El.cache){
9874             var el = El.cache[eid], d = el.dom;
9875             // -------------------------------------------------------
9876             // Determining what is garbage:
9877             // -------------------------------------------------------
9878             // !d
9879             // dom node is null, definitely garbage
9880             // -------------------------------------------------------
9881             // !d.parentNode
9882             // no parentNode == direct orphan, definitely garbage
9883             // -------------------------------------------------------
9884             // !d.offsetParent && !document.getElementById(eid)
9885             // display none elements have no offsetParent so we will
9886             // also try to look it up by it's id. However, check
9887             // offsetParent first so we don't do unneeded lookups.
9888             // This enables collection of elements that are not orphans
9889             // directly, but somewhere up the line they have an orphan
9890             // parent.
9891             // -------------------------------------------------------
9892             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9893                 delete El.cache[eid];
9894                 if(d && Roo.enableListenerCollection){
9895                     E.purgeElement(d);
9896                 }
9897             }
9898         }
9899     }
9900     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9901
9902
9903     // dom is optional
9904     El.Flyweight = function(dom){
9905         this.dom = dom;
9906     };
9907     El.Flyweight.prototype = El.prototype;
9908
9909     El._flyweights = {};
9910     /**
9911      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9912      * the dom node can be overwritten by other code.
9913      * @param {String/HTMLElement} el The dom node or id
9914      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9915      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9916      * @static
9917      * @return {Element} The shared Element object
9918      */
9919     El.fly = function(el, named){
9920         named = named || '_global';
9921         el = Roo.getDom(el);
9922         if(!el){
9923             return null;
9924         }
9925         if(!El._flyweights[named]){
9926             El._flyweights[named] = new El.Flyweight();
9927         }
9928         El._flyweights[named].dom = el;
9929         return El._flyweights[named];
9930     };
9931
9932     /**
9933      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9934      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9935      * Shorthand of {@link Roo.Element#get}
9936      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9937      * @return {Element} The Element object
9938      * @member Roo
9939      * @method get
9940      */
9941     Roo.get = El.get;
9942     /**
9943      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9944      * the dom node can be overwritten by other code.
9945      * Shorthand of {@link Roo.Element#fly}
9946      * @param {String/HTMLElement} el The dom node or id
9947      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9948      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9949      * @static
9950      * @return {Element} The shared Element object
9951      * @member Roo
9952      * @method fly
9953      */
9954     Roo.fly = El.fly;
9955
9956     // speedy lookup for elements never to box adjust
9957     var noBoxAdjust = Roo.isStrict ? {
9958         select:1
9959     } : {
9960         input:1, select:1, textarea:1
9961     };
9962     if(Roo.isIE || Roo.isGecko){
9963         noBoxAdjust['button'] = 1;
9964     }
9965
9966
9967     Roo.EventManager.on(window, 'unload', function(){
9968         delete El.cache;
9969         delete El._flyweights;
9970     });
9971 })();
9972
9973
9974
9975
9976 if(Roo.DomQuery){
9977     Roo.Element.selectorFunction = Roo.DomQuery.select;
9978 }
9979
9980 Roo.Element.select = function(selector, unique, root){
9981     var els;
9982     if(typeof selector == "string"){
9983         els = Roo.Element.selectorFunction(selector, root);
9984     }else if(selector.length !== undefined){
9985         els = selector;
9986     }else{
9987         throw "Invalid selector";
9988     }
9989     if(unique === true){
9990         return new Roo.CompositeElement(els);
9991     }else{
9992         return new Roo.CompositeElementLite(els);
9993     }
9994 };
9995 /**
9996  * Selects elements based on the passed CSS selector to enable working on them as 1.
9997  * @param {String/Array} selector The CSS selector or an array of elements
9998  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9999  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10000  * @return {CompositeElementLite/CompositeElement}
10001  * @member Roo
10002  * @method select
10003  */
10004 Roo.select = Roo.Element.select;
10005
10006
10007
10008
10009
10010
10011
10012
10013
10014
10015
10016
10017
10018
10019 /*
10020  * Based on:
10021  * Ext JS Library 1.1.1
10022  * Copyright(c) 2006-2007, Ext JS, LLC.
10023  *
10024  * Originally Released Under LGPL - original licence link has changed is not relivant.
10025  *
10026  * Fork - LGPL
10027  * <script type="text/javascript">
10028  */
10029
10030
10031
10032 //Notifies Element that fx methods are available
10033 Roo.enableFx = true;
10034
10035 /**
10036  * @class Roo.Fx
10037  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
10038  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10039  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
10040  * Element effects to work.</p><br/>
10041  *
10042  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10043  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10044  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10045  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10046  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10047  * expected results and should be done with care.</p><br/>
10048  *
10049  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10050  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10051 <pre>
10052 Value  Description
10053 -----  -----------------------------
10054 tl     The top left corner
10055 t      The center of the top edge
10056 tr     The top right corner
10057 l      The center of the left edge
10058 r      The center of the right edge
10059 bl     The bottom left corner
10060 b      The center of the bottom edge
10061 br     The bottom right corner
10062 </pre>
10063  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10064  * below are common options that can be passed to any Fx method.</b>
10065  * @cfg {Function} callback A function called when the effect is finished
10066  * @cfg {Object} scope The scope of the effect function
10067  * @cfg {String} easing A valid Easing value for the effect
10068  * @cfg {String} afterCls A css class to apply after the effect
10069  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10070  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10071  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10072  * effects that end with the element being visually hidden, ignored otherwise)
10073  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10074  * a function which returns such a specification that will be applied to the Element after the effect finishes
10075  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10076  * @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
10077  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10078  */
10079 Roo.Fx = {
10080         /**
10081          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10082          * origin for the slide effect.  This function automatically handles wrapping the element with
10083          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10084          * Usage:
10085          *<pre><code>
10086 // default: slide the element in from the top
10087 el.slideIn();
10088
10089 // custom: slide the element in from the right with a 2-second duration
10090 el.slideIn('r', { duration: 2 });
10091
10092 // common config options shown with default values
10093 el.slideIn('t', {
10094     easing: 'easeOut',
10095     duration: .5
10096 });
10097 </code></pre>
10098          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10099          * @param {Object} options (optional) Object literal with any of the Fx config options
10100          * @return {Roo.Element} The Element
10101          */
10102     slideIn : function(anchor, o){
10103         var el = this.getFxEl();
10104         o = o || {};
10105
10106         el.queueFx(o, function(){
10107
10108             anchor = anchor || "t";
10109
10110             // fix display to visibility
10111             this.fixDisplay();
10112
10113             // restore values after effect
10114             var r = this.getFxRestore();
10115             var b = this.getBox();
10116             // fixed size for slide
10117             this.setSize(b);
10118
10119             // wrap if needed
10120             var wrap = this.fxWrap(r.pos, o, "hidden");
10121
10122             var st = this.dom.style;
10123             st.visibility = "visible";
10124             st.position = "absolute";
10125
10126             // clear out temp styles after slide and unwrap
10127             var after = function(){
10128                 el.fxUnwrap(wrap, r.pos, o);
10129                 st.width = r.width;
10130                 st.height = r.height;
10131                 el.afterFx(o);
10132             };
10133             // time to calc the positions
10134             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10135
10136             switch(anchor.toLowerCase()){
10137                 case "t":
10138                     wrap.setSize(b.width, 0);
10139                     st.left = st.bottom = "0";
10140                     a = {height: bh};
10141                 break;
10142                 case "l":
10143                     wrap.setSize(0, b.height);
10144                     st.right = st.top = "0";
10145                     a = {width: bw};
10146                 break;
10147                 case "r":
10148                     wrap.setSize(0, b.height);
10149                     wrap.setX(b.right);
10150                     st.left = st.top = "0";
10151                     a = {width: bw, points: pt};
10152                 break;
10153                 case "b":
10154                     wrap.setSize(b.width, 0);
10155                     wrap.setY(b.bottom);
10156                     st.left = st.top = "0";
10157                     a = {height: bh, points: pt};
10158                 break;
10159                 case "tl":
10160                     wrap.setSize(0, 0);
10161                     st.right = st.bottom = "0";
10162                     a = {width: bw, height: bh};
10163                 break;
10164                 case "bl":
10165                     wrap.setSize(0, 0);
10166                     wrap.setY(b.y+b.height);
10167                     st.right = st.top = "0";
10168                     a = {width: bw, height: bh, points: pt};
10169                 break;
10170                 case "br":
10171                     wrap.setSize(0, 0);
10172                     wrap.setXY([b.right, b.bottom]);
10173                     st.left = st.top = "0";
10174                     a = {width: bw, height: bh, points: pt};
10175                 break;
10176                 case "tr":
10177                     wrap.setSize(0, 0);
10178                     wrap.setX(b.x+b.width);
10179                     st.left = st.bottom = "0";
10180                     a = {width: bw, height: bh, points: pt};
10181                 break;
10182             }
10183             this.dom.style.visibility = "visible";
10184             wrap.show();
10185
10186             arguments.callee.anim = wrap.fxanim(a,
10187                 o,
10188                 'motion',
10189                 .5,
10190                 'easeOut', after);
10191         });
10192         return this;
10193     },
10194     
10195         /**
10196          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10197          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10198          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10199          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10200          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10201          * Usage:
10202          *<pre><code>
10203 // default: slide the element out to the top
10204 el.slideOut();
10205
10206 // custom: slide the element out to the right with a 2-second duration
10207 el.slideOut('r', { duration: 2 });
10208
10209 // common config options shown with default values
10210 el.slideOut('t', {
10211     easing: 'easeOut',
10212     duration: .5,
10213     remove: false,
10214     useDisplay: false
10215 });
10216 </code></pre>
10217          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10218          * @param {Object} options (optional) Object literal with any of the Fx config options
10219          * @return {Roo.Element} The Element
10220          */
10221     slideOut : function(anchor, o){
10222         var el = this.getFxEl();
10223         o = o || {};
10224
10225         el.queueFx(o, function(){
10226
10227             anchor = anchor || "t";
10228
10229             // restore values after effect
10230             var r = this.getFxRestore();
10231             
10232             var b = this.getBox();
10233             // fixed size for slide
10234             this.setSize(b);
10235
10236             // wrap if needed
10237             var wrap = this.fxWrap(r.pos, o, "visible");
10238
10239             var st = this.dom.style;
10240             st.visibility = "visible";
10241             st.position = "absolute";
10242
10243             wrap.setSize(b);
10244
10245             var after = function(){
10246                 if(o.useDisplay){
10247                     el.setDisplayed(false);
10248                 }else{
10249                     el.hide();
10250                 }
10251
10252                 el.fxUnwrap(wrap, r.pos, o);
10253
10254                 st.width = r.width;
10255                 st.height = r.height;
10256
10257                 el.afterFx(o);
10258             };
10259
10260             var a, zero = {to: 0};
10261             switch(anchor.toLowerCase()){
10262                 case "t":
10263                     st.left = st.bottom = "0";
10264                     a = {height: zero};
10265                 break;
10266                 case "l":
10267                     st.right = st.top = "0";
10268                     a = {width: zero};
10269                 break;
10270                 case "r":
10271                     st.left = st.top = "0";
10272                     a = {width: zero, points: {to:[b.right, b.y]}};
10273                 break;
10274                 case "b":
10275                     st.left = st.top = "0";
10276                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10277                 break;
10278                 case "tl":
10279                     st.right = st.bottom = "0";
10280                     a = {width: zero, height: zero};
10281                 break;
10282                 case "bl":
10283                     st.right = st.top = "0";
10284                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10285                 break;
10286                 case "br":
10287                     st.left = st.top = "0";
10288                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10289                 break;
10290                 case "tr":
10291                     st.left = st.bottom = "0";
10292                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10293                 break;
10294             }
10295
10296             arguments.callee.anim = wrap.fxanim(a,
10297                 o,
10298                 'motion',
10299                 .5,
10300                 "easeOut", after);
10301         });
10302         return this;
10303     },
10304
10305         /**
10306          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10307          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10308          * The element must be removed from the DOM using the 'remove' config option if desired.
10309          * Usage:
10310          *<pre><code>
10311 // default
10312 el.puff();
10313
10314 // common config options shown with default values
10315 el.puff({
10316     easing: 'easeOut',
10317     duration: .5,
10318     remove: false,
10319     useDisplay: false
10320 });
10321 </code></pre>
10322          * @param {Object} options (optional) Object literal with any of the Fx config options
10323          * @return {Roo.Element} The Element
10324          */
10325     puff : function(o){
10326         var el = this.getFxEl();
10327         o = o || {};
10328
10329         el.queueFx(o, function(){
10330             this.clearOpacity();
10331             this.show();
10332
10333             // restore values after effect
10334             var r = this.getFxRestore();
10335             var st = this.dom.style;
10336
10337             var after = function(){
10338                 if(o.useDisplay){
10339                     el.setDisplayed(false);
10340                 }else{
10341                     el.hide();
10342                 }
10343
10344                 el.clearOpacity();
10345
10346                 el.setPositioning(r.pos);
10347                 st.width = r.width;
10348                 st.height = r.height;
10349                 st.fontSize = '';
10350                 el.afterFx(o);
10351             };
10352
10353             var width = this.getWidth();
10354             var height = this.getHeight();
10355
10356             arguments.callee.anim = this.fxanim({
10357                     width : {to: this.adjustWidth(width * 2)},
10358                     height : {to: this.adjustHeight(height * 2)},
10359                     points : {by: [-(width * .5), -(height * .5)]},
10360                     opacity : {to: 0},
10361                     fontSize: {to:200, unit: "%"}
10362                 },
10363                 o,
10364                 'motion',
10365                 .5,
10366                 "easeOut", after);
10367         });
10368         return this;
10369     },
10370
10371         /**
10372          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10373          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10374          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10375          * Usage:
10376          *<pre><code>
10377 // default
10378 el.switchOff();
10379
10380 // all config options shown with default values
10381 el.switchOff({
10382     easing: 'easeIn',
10383     duration: .3,
10384     remove: false,
10385     useDisplay: false
10386 });
10387 </code></pre>
10388          * @param {Object} options (optional) Object literal with any of the Fx config options
10389          * @return {Roo.Element} The Element
10390          */
10391     switchOff : function(o){
10392         var el = this.getFxEl();
10393         o = o || {};
10394
10395         el.queueFx(o, function(){
10396             this.clearOpacity();
10397             this.clip();
10398
10399             // restore values after effect
10400             var r = this.getFxRestore();
10401             var st = this.dom.style;
10402
10403             var after = function(){
10404                 if(o.useDisplay){
10405                     el.setDisplayed(false);
10406                 }else{
10407                     el.hide();
10408                 }
10409
10410                 el.clearOpacity();
10411                 el.setPositioning(r.pos);
10412                 st.width = r.width;
10413                 st.height = r.height;
10414
10415                 el.afterFx(o);
10416             };
10417
10418             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10419                 this.clearOpacity();
10420                 (function(){
10421                     this.fxanim({
10422                         height:{to:1},
10423                         points:{by:[0, this.getHeight() * .5]}
10424                     }, o, 'motion', 0.3, 'easeIn', after);
10425                 }).defer(100, this);
10426             });
10427         });
10428         return this;
10429     },
10430
10431     /**
10432      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10433      * changed using the "attr" config option) and then fading back to the original color. If no original
10434      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10435      * Usage:
10436 <pre><code>
10437 // default: highlight background to yellow
10438 el.highlight();
10439
10440 // custom: highlight foreground text to blue for 2 seconds
10441 el.highlight("0000ff", { attr: 'color', duration: 2 });
10442
10443 // common config options shown with default values
10444 el.highlight("ffff9c", {
10445     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10446     endColor: (current color) or "ffffff",
10447     easing: 'easeIn',
10448     duration: 1
10449 });
10450 </code></pre>
10451      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10452      * @param {Object} options (optional) Object literal with any of the Fx config options
10453      * @return {Roo.Element} The Element
10454      */ 
10455     highlight : function(color, o){
10456         var el = this.getFxEl();
10457         o = o || {};
10458
10459         el.queueFx(o, function(){
10460             color = color || "ffff9c";
10461             attr = o.attr || "backgroundColor";
10462
10463             this.clearOpacity();
10464             this.show();
10465
10466             var origColor = this.getColor(attr);
10467             var restoreColor = this.dom.style[attr];
10468             endColor = (o.endColor || origColor) || "ffffff";
10469
10470             var after = function(){
10471                 el.dom.style[attr] = restoreColor;
10472                 el.afterFx(o);
10473             };
10474
10475             var a = {};
10476             a[attr] = {from: color, to: endColor};
10477             arguments.callee.anim = this.fxanim(a,
10478                 o,
10479                 'color',
10480                 1,
10481                 'easeIn', after);
10482         });
10483         return this;
10484     },
10485
10486    /**
10487     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10488     * Usage:
10489 <pre><code>
10490 // default: a single light blue ripple
10491 el.frame();
10492
10493 // custom: 3 red ripples lasting 3 seconds total
10494 el.frame("ff0000", 3, { duration: 3 });
10495
10496 // common config options shown with default values
10497 el.frame("C3DAF9", 1, {
10498     duration: 1 //duration of entire animation (not each individual ripple)
10499     // Note: Easing is not configurable and will be ignored if included
10500 });
10501 </code></pre>
10502     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10503     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10504     * @param {Object} options (optional) Object literal with any of the Fx config options
10505     * @return {Roo.Element} The Element
10506     */
10507     frame : function(color, count, o){
10508         var el = this.getFxEl();
10509         o = o || {};
10510
10511         el.queueFx(o, function(){
10512             color = color || "#C3DAF9";
10513             if(color.length == 6){
10514                 color = "#" + color;
10515             }
10516             count = count || 1;
10517             duration = o.duration || 1;
10518             this.show();
10519
10520             var b = this.getBox();
10521             var animFn = function(){
10522                 var proxy = this.createProxy({
10523
10524                      style:{
10525                         visbility:"hidden",
10526                         position:"absolute",
10527                         "z-index":"35000", // yee haw
10528                         border:"0px solid " + color
10529                      }
10530                   });
10531                 var scale = Roo.isBorderBox ? 2 : 1;
10532                 proxy.animate({
10533                     top:{from:b.y, to:b.y - 20},
10534                     left:{from:b.x, to:b.x - 20},
10535                     borderWidth:{from:0, to:10},
10536                     opacity:{from:1, to:0},
10537                     height:{from:b.height, to:(b.height + (20*scale))},
10538                     width:{from:b.width, to:(b.width + (20*scale))}
10539                 }, duration, function(){
10540                     proxy.remove();
10541                 });
10542                 if(--count > 0){
10543                      animFn.defer((duration/2)*1000, this);
10544                 }else{
10545                     el.afterFx(o);
10546                 }
10547             };
10548             animFn.call(this);
10549         });
10550         return this;
10551     },
10552
10553    /**
10554     * Creates a pause before any subsequent queued effects begin.  If there are
10555     * no effects queued after the pause it will have no effect.
10556     * Usage:
10557 <pre><code>
10558 el.pause(1);
10559 </code></pre>
10560     * @param {Number} seconds The length of time to pause (in seconds)
10561     * @return {Roo.Element} The Element
10562     */
10563     pause : function(seconds){
10564         var el = this.getFxEl();
10565         var o = {};
10566
10567         el.queueFx(o, function(){
10568             setTimeout(function(){
10569                 el.afterFx(o);
10570             }, seconds * 1000);
10571         });
10572         return this;
10573     },
10574
10575    /**
10576     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10577     * using the "endOpacity" config option.
10578     * Usage:
10579 <pre><code>
10580 // default: fade in from opacity 0 to 100%
10581 el.fadeIn();
10582
10583 // custom: fade in from opacity 0 to 75% over 2 seconds
10584 el.fadeIn({ endOpacity: .75, duration: 2});
10585
10586 // common config options shown with default values
10587 el.fadeIn({
10588     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10589     easing: 'easeOut',
10590     duration: .5
10591 });
10592 </code></pre>
10593     * @param {Object} options (optional) Object literal with any of the Fx config options
10594     * @return {Roo.Element} The Element
10595     */
10596     fadeIn : function(o){
10597         var el = this.getFxEl();
10598         o = o || {};
10599         el.queueFx(o, function(){
10600             this.setOpacity(0);
10601             this.fixDisplay();
10602             this.dom.style.visibility = 'visible';
10603             var to = o.endOpacity || 1;
10604             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10605                 o, null, .5, "easeOut", function(){
10606                 if(to == 1){
10607                     this.clearOpacity();
10608                 }
10609                 el.afterFx(o);
10610             });
10611         });
10612         return this;
10613     },
10614
10615    /**
10616     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10617     * using the "endOpacity" config option.
10618     * Usage:
10619 <pre><code>
10620 // default: fade out from the element's current opacity to 0
10621 el.fadeOut();
10622
10623 // custom: fade out from the element's current opacity to 25% over 2 seconds
10624 el.fadeOut({ endOpacity: .25, duration: 2});
10625
10626 // common config options shown with default values
10627 el.fadeOut({
10628     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10629     easing: 'easeOut',
10630     duration: .5
10631     remove: false,
10632     useDisplay: false
10633 });
10634 </code></pre>
10635     * @param {Object} options (optional) Object literal with any of the Fx config options
10636     * @return {Roo.Element} The Element
10637     */
10638     fadeOut : function(o){
10639         var el = this.getFxEl();
10640         o = o || {};
10641         el.queueFx(o, function(){
10642             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10643                 o, null, .5, "easeOut", function(){
10644                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10645                      this.dom.style.display = "none";
10646                 }else{
10647                      this.dom.style.visibility = "hidden";
10648                 }
10649                 this.clearOpacity();
10650                 el.afterFx(o);
10651             });
10652         });
10653         return this;
10654     },
10655
10656    /**
10657     * Animates the transition of an element's dimensions from a starting height/width
10658     * to an ending height/width.
10659     * Usage:
10660 <pre><code>
10661 // change height and width to 100x100 pixels
10662 el.scale(100, 100);
10663
10664 // common config options shown with default values.  The height and width will default to
10665 // the element's existing values if passed as null.
10666 el.scale(
10667     [element's width],
10668     [element's height], {
10669     easing: 'easeOut',
10670     duration: .35
10671 });
10672 </code></pre>
10673     * @param {Number} width  The new width (pass undefined to keep the original width)
10674     * @param {Number} height  The new height (pass undefined to keep the original height)
10675     * @param {Object} options (optional) Object literal with any of the Fx config options
10676     * @return {Roo.Element} The Element
10677     */
10678     scale : function(w, h, o){
10679         this.shift(Roo.apply({}, o, {
10680             width: w,
10681             height: h
10682         }));
10683         return this;
10684     },
10685
10686    /**
10687     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10688     * Any of these properties not specified in the config object will not be changed.  This effect 
10689     * requires that at least one new dimension, position or opacity setting must be passed in on
10690     * the config object in order for the function to have any effect.
10691     * Usage:
10692 <pre><code>
10693 // slide the element horizontally to x position 200 while changing the height and opacity
10694 el.shift({ x: 200, height: 50, opacity: .8 });
10695
10696 // common config options shown with default values.
10697 el.shift({
10698     width: [element's width],
10699     height: [element's height],
10700     x: [element's x position],
10701     y: [element's y position],
10702     opacity: [element's opacity],
10703     easing: 'easeOut',
10704     duration: .35
10705 });
10706 </code></pre>
10707     * @param {Object} options  Object literal with any of the Fx config options
10708     * @return {Roo.Element} The Element
10709     */
10710     shift : function(o){
10711         var el = this.getFxEl();
10712         o = o || {};
10713         el.queueFx(o, function(){
10714             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10715             if(w !== undefined){
10716                 a.width = {to: this.adjustWidth(w)};
10717             }
10718             if(h !== undefined){
10719                 a.height = {to: this.adjustHeight(h)};
10720             }
10721             if(x !== undefined || y !== undefined){
10722                 a.points = {to: [
10723                     x !== undefined ? x : this.getX(),
10724                     y !== undefined ? y : this.getY()
10725                 ]};
10726             }
10727             if(op !== undefined){
10728                 a.opacity = {to: op};
10729             }
10730             if(o.xy !== undefined){
10731                 a.points = {to: o.xy};
10732             }
10733             arguments.callee.anim = this.fxanim(a,
10734                 o, 'motion', .35, "easeOut", function(){
10735                 el.afterFx(o);
10736             });
10737         });
10738         return this;
10739     },
10740
10741         /**
10742          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10743          * ending point of the effect.
10744          * Usage:
10745          *<pre><code>
10746 // default: slide the element downward while fading out
10747 el.ghost();
10748
10749 // custom: slide the element out to the right with a 2-second duration
10750 el.ghost('r', { duration: 2 });
10751
10752 // common config options shown with default values
10753 el.ghost('b', {
10754     easing: 'easeOut',
10755     duration: .5
10756     remove: false,
10757     useDisplay: false
10758 });
10759 </code></pre>
10760          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10761          * @param {Object} options (optional) Object literal with any of the Fx config options
10762          * @return {Roo.Element} The Element
10763          */
10764     ghost : function(anchor, o){
10765         var el = this.getFxEl();
10766         o = o || {};
10767
10768         el.queueFx(o, function(){
10769             anchor = anchor || "b";
10770
10771             // restore values after effect
10772             var r = this.getFxRestore();
10773             var w = this.getWidth(),
10774                 h = this.getHeight();
10775
10776             var st = this.dom.style;
10777
10778             var after = function(){
10779                 if(o.useDisplay){
10780                     el.setDisplayed(false);
10781                 }else{
10782                     el.hide();
10783                 }
10784
10785                 el.clearOpacity();
10786                 el.setPositioning(r.pos);
10787                 st.width = r.width;
10788                 st.height = r.height;
10789
10790                 el.afterFx(o);
10791             };
10792
10793             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10794             switch(anchor.toLowerCase()){
10795                 case "t":
10796                     pt.by = [0, -h];
10797                 break;
10798                 case "l":
10799                     pt.by = [-w, 0];
10800                 break;
10801                 case "r":
10802                     pt.by = [w, 0];
10803                 break;
10804                 case "b":
10805                     pt.by = [0, h];
10806                 break;
10807                 case "tl":
10808                     pt.by = [-w, -h];
10809                 break;
10810                 case "bl":
10811                     pt.by = [-w, h];
10812                 break;
10813                 case "br":
10814                     pt.by = [w, h];
10815                 break;
10816                 case "tr":
10817                     pt.by = [w, -h];
10818                 break;
10819             }
10820
10821             arguments.callee.anim = this.fxanim(a,
10822                 o,
10823                 'motion',
10824                 .5,
10825                 "easeOut", after);
10826         });
10827         return this;
10828     },
10829
10830         /**
10831          * Ensures that all effects queued after syncFx is called on the element are
10832          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10833          * @return {Roo.Element} The Element
10834          */
10835     syncFx : function(){
10836         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10837             block : false,
10838             concurrent : true,
10839             stopFx : false
10840         });
10841         return this;
10842     },
10843
10844         /**
10845          * Ensures that all effects queued after sequenceFx is called on the element are
10846          * run in sequence.  This is the opposite of {@link #syncFx}.
10847          * @return {Roo.Element} The Element
10848          */
10849     sequenceFx : function(){
10850         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10851             block : false,
10852             concurrent : false,
10853             stopFx : false
10854         });
10855         return this;
10856     },
10857
10858         /* @private */
10859     nextFx : function(){
10860         var ef = this.fxQueue[0];
10861         if(ef){
10862             ef.call(this);
10863         }
10864     },
10865
10866         /**
10867          * Returns true if the element has any effects actively running or queued, else returns false.
10868          * @return {Boolean} True if element has active effects, else false
10869          */
10870     hasActiveFx : function(){
10871         return this.fxQueue && this.fxQueue[0];
10872     },
10873
10874         /**
10875          * Stops any running effects and clears the element's internal effects queue if it contains
10876          * any additional effects that haven't started yet.
10877          * @return {Roo.Element} The Element
10878          */
10879     stopFx : function(){
10880         if(this.hasActiveFx()){
10881             var cur = this.fxQueue[0];
10882             if(cur && cur.anim && cur.anim.isAnimated()){
10883                 this.fxQueue = [cur]; // clear out others
10884                 cur.anim.stop(true);
10885             }
10886         }
10887         return this;
10888     },
10889
10890         /* @private */
10891     beforeFx : function(o){
10892         if(this.hasActiveFx() && !o.concurrent){
10893            if(o.stopFx){
10894                this.stopFx();
10895                return true;
10896            }
10897            return false;
10898         }
10899         return true;
10900     },
10901
10902         /**
10903          * Returns true if the element is currently blocking so that no other effect can be queued
10904          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10905          * used to ensure that an effect initiated by a user action runs to completion prior to the
10906          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10907          * @return {Boolean} True if blocking, else false
10908          */
10909     hasFxBlock : function(){
10910         var q = this.fxQueue;
10911         return q && q[0] && q[0].block;
10912     },
10913
10914         /* @private */
10915     queueFx : function(o, fn){
10916         if(!this.fxQueue){
10917             this.fxQueue = [];
10918         }
10919         if(!this.hasFxBlock()){
10920             Roo.applyIf(o, this.fxDefaults);
10921             if(!o.concurrent){
10922                 var run = this.beforeFx(o);
10923                 fn.block = o.block;
10924                 this.fxQueue.push(fn);
10925                 if(run){
10926                     this.nextFx();
10927                 }
10928             }else{
10929                 fn.call(this);
10930             }
10931         }
10932         return this;
10933     },
10934
10935         /* @private */
10936     fxWrap : function(pos, o, vis){
10937         var wrap;
10938         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10939             var wrapXY;
10940             if(o.fixPosition){
10941                 wrapXY = this.getXY();
10942             }
10943             var div = document.createElement("div");
10944             div.style.visibility = vis;
10945             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10946             wrap.setPositioning(pos);
10947             if(wrap.getStyle("position") == "static"){
10948                 wrap.position("relative");
10949             }
10950             this.clearPositioning('auto');
10951             wrap.clip();
10952             wrap.dom.appendChild(this.dom);
10953             if(wrapXY){
10954                 wrap.setXY(wrapXY);
10955             }
10956         }
10957         return wrap;
10958     },
10959
10960         /* @private */
10961     fxUnwrap : function(wrap, pos, o){
10962         this.clearPositioning();
10963         this.setPositioning(pos);
10964         if(!o.wrap){
10965             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10966             wrap.remove();
10967         }
10968     },
10969
10970         /* @private */
10971     getFxRestore : function(){
10972         var st = this.dom.style;
10973         return {pos: this.getPositioning(), width: st.width, height : st.height};
10974     },
10975
10976         /* @private */
10977     afterFx : function(o){
10978         if(o.afterStyle){
10979             this.applyStyles(o.afterStyle);
10980         }
10981         if(o.afterCls){
10982             this.addClass(o.afterCls);
10983         }
10984         if(o.remove === true){
10985             this.remove();
10986         }
10987         Roo.callback(o.callback, o.scope, [this]);
10988         if(!o.concurrent){
10989             this.fxQueue.shift();
10990             this.nextFx();
10991         }
10992     },
10993
10994         /* @private */
10995     getFxEl : function(){ // support for composite element fx
10996         return Roo.get(this.dom);
10997     },
10998
10999         /* @private */
11000     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11001         animType = animType || 'run';
11002         opt = opt || {};
11003         var anim = Roo.lib.Anim[animType](
11004             this.dom, args,
11005             (opt.duration || defaultDur) || .35,
11006             (opt.easing || defaultEase) || 'easeOut',
11007             function(){
11008                 Roo.callback(cb, this);
11009             },
11010             this
11011         );
11012         opt.anim = anim;
11013         return anim;
11014     }
11015 };
11016
11017 // backwords compat
11018 Roo.Fx.resize = Roo.Fx.scale;
11019
11020 //When included, Roo.Fx is automatically applied to Element so that all basic
11021 //effects are available directly via the Element API
11022 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11023  * Based on:
11024  * Ext JS Library 1.1.1
11025  * Copyright(c) 2006-2007, Ext JS, LLC.
11026  *
11027  * Originally Released Under LGPL - original licence link has changed is not relivant.
11028  *
11029  * Fork - LGPL
11030  * <script type="text/javascript">
11031  */
11032
11033
11034 /**
11035  * @class Roo.CompositeElement
11036  * Standard composite class. Creates a Roo.Element for every element in the collection.
11037  * <br><br>
11038  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11039  * actions will be performed on all the elements in this collection.</b>
11040  * <br><br>
11041  * All methods return <i>this</i> and can be chained.
11042  <pre><code>
11043  var els = Roo.select("#some-el div.some-class", true);
11044  // or select directly from an existing element
11045  var el = Roo.get('some-el');
11046  el.select('div.some-class', true);
11047
11048  els.setWidth(100); // all elements become 100 width
11049  els.hide(true); // all elements fade out and hide
11050  // or
11051  els.setWidth(100).hide(true);
11052  </code></pre>
11053  */
11054 Roo.CompositeElement = function(els){
11055     this.elements = [];
11056     this.addElements(els);
11057 };
11058 Roo.CompositeElement.prototype = {
11059     isComposite: true,
11060     addElements : function(els){
11061         if(!els) {
11062             return this;
11063         }
11064         if(typeof els == "string"){
11065             els = Roo.Element.selectorFunction(els);
11066         }
11067         var yels = this.elements;
11068         var index = yels.length-1;
11069         for(var i = 0, len = els.length; i < len; i++) {
11070                 yels[++index] = Roo.get(els[i]);
11071         }
11072         return this;
11073     },
11074
11075     /**
11076     * Clears this composite and adds the elements returned by the passed selector.
11077     * @param {String/Array} els A string CSS selector, an array of elements or an element
11078     * @return {CompositeElement} this
11079     */
11080     fill : function(els){
11081         this.elements = [];
11082         this.add(els);
11083         return this;
11084     },
11085
11086     /**
11087     * Filters this composite to only elements that match the passed selector.
11088     * @param {String} selector A string CSS selector
11089     * @param {Boolean} inverse return inverse filter (not matches)
11090     * @return {CompositeElement} this
11091     */
11092     filter : function(selector, inverse){
11093         var els = [];
11094         inverse = inverse || false;
11095         this.each(function(el){
11096             var match = inverse ? !el.is(selector) : el.is(selector);
11097             if(match){
11098                 els[els.length] = el.dom;
11099             }
11100         });
11101         this.fill(els);
11102         return this;
11103     },
11104
11105     invoke : function(fn, args){
11106         var els = this.elements;
11107         for(var i = 0, len = els.length; i < len; i++) {
11108                 Roo.Element.prototype[fn].apply(els[i], args);
11109         }
11110         return this;
11111     },
11112     /**
11113     * Adds elements to this composite.
11114     * @param {String/Array} els A string CSS selector, an array of elements or an element
11115     * @return {CompositeElement} this
11116     */
11117     add : function(els){
11118         if(typeof els == "string"){
11119             this.addElements(Roo.Element.selectorFunction(els));
11120         }else if(els.length !== undefined){
11121             this.addElements(els);
11122         }else{
11123             this.addElements([els]);
11124         }
11125         return this;
11126     },
11127     /**
11128     * Calls the passed function passing (el, this, index) for each element in this composite.
11129     * @param {Function} fn The function to call
11130     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11131     * @return {CompositeElement} this
11132     */
11133     each : function(fn, scope){
11134         var els = this.elements;
11135         for(var i = 0, len = els.length; i < len; i++){
11136             if(fn.call(scope || els[i], els[i], this, i) === false) {
11137                 break;
11138             }
11139         }
11140         return this;
11141     },
11142
11143     /**
11144      * Returns the Element object at the specified index
11145      * @param {Number} index
11146      * @return {Roo.Element}
11147      */
11148     item : function(index){
11149         return this.elements[index] || null;
11150     },
11151
11152     /**
11153      * Returns the first Element
11154      * @return {Roo.Element}
11155      */
11156     first : function(){
11157         return this.item(0);
11158     },
11159
11160     /**
11161      * Returns the last Element
11162      * @return {Roo.Element}
11163      */
11164     last : function(){
11165         return this.item(this.elements.length-1);
11166     },
11167
11168     /**
11169      * Returns the number of elements in this composite
11170      * @return Number
11171      */
11172     getCount : function(){
11173         return this.elements.length;
11174     },
11175
11176     /**
11177      * Returns true if this composite contains the passed element
11178      * @return Boolean
11179      */
11180     contains : function(el){
11181         return this.indexOf(el) !== -1;
11182     },
11183
11184     /**
11185      * Returns true if this composite contains the passed element
11186      * @return Boolean
11187      */
11188     indexOf : function(el){
11189         return this.elements.indexOf(Roo.get(el));
11190     },
11191
11192
11193     /**
11194     * Removes the specified element(s).
11195     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11196     * or an array of any of those.
11197     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11198     * @return {CompositeElement} this
11199     */
11200     removeElement : function(el, removeDom){
11201         if(el instanceof Array){
11202             for(var i = 0, len = el.length; i < len; i++){
11203                 this.removeElement(el[i]);
11204             }
11205             return this;
11206         }
11207         var index = typeof el == 'number' ? el : this.indexOf(el);
11208         if(index !== -1){
11209             if(removeDom){
11210                 var d = this.elements[index];
11211                 if(d.dom){
11212                     d.remove();
11213                 }else{
11214                     d.parentNode.removeChild(d);
11215                 }
11216             }
11217             this.elements.splice(index, 1);
11218         }
11219         return this;
11220     },
11221
11222     /**
11223     * Replaces the specified element with the passed element.
11224     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11225     * to replace.
11226     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11227     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11228     * @return {CompositeElement} this
11229     */
11230     replaceElement : function(el, replacement, domReplace){
11231         var index = typeof el == 'number' ? el : this.indexOf(el);
11232         if(index !== -1){
11233             if(domReplace){
11234                 this.elements[index].replaceWith(replacement);
11235             }else{
11236                 this.elements.splice(index, 1, Roo.get(replacement))
11237             }
11238         }
11239         return this;
11240     },
11241
11242     /**
11243      * Removes all elements.
11244      */
11245     clear : function(){
11246         this.elements = [];
11247     }
11248 };
11249 (function(){
11250     Roo.CompositeElement.createCall = function(proto, fnName){
11251         if(!proto[fnName]){
11252             proto[fnName] = function(){
11253                 return this.invoke(fnName, arguments);
11254             };
11255         }
11256     };
11257     for(var fnName in Roo.Element.prototype){
11258         if(typeof Roo.Element.prototype[fnName] == "function"){
11259             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11260         }
11261     };
11262 })();
11263 /*
11264  * Based on:
11265  * Ext JS Library 1.1.1
11266  * Copyright(c) 2006-2007, Ext JS, LLC.
11267  *
11268  * Originally Released Under LGPL - original licence link has changed is not relivant.
11269  *
11270  * Fork - LGPL
11271  * <script type="text/javascript">
11272  */
11273
11274 /**
11275  * @class Roo.CompositeElementLite
11276  * @extends Roo.CompositeElement
11277  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11278  <pre><code>
11279  var els = Roo.select("#some-el div.some-class");
11280  // or select directly from an existing element
11281  var el = Roo.get('some-el');
11282  el.select('div.some-class');
11283
11284  els.setWidth(100); // all elements become 100 width
11285  els.hide(true); // all elements fade out and hide
11286  // or
11287  els.setWidth(100).hide(true);
11288  </code></pre><br><br>
11289  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11290  * actions will be performed on all the elements in this collection.</b>
11291  */
11292 Roo.CompositeElementLite = function(els){
11293     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11294     this.el = new Roo.Element.Flyweight();
11295 };
11296 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11297     addElements : function(els){
11298         if(els){
11299             if(els instanceof Array){
11300                 this.elements = this.elements.concat(els);
11301             }else{
11302                 var yels = this.elements;
11303                 var index = yels.length-1;
11304                 for(var i = 0, len = els.length; i < len; i++) {
11305                     yels[++index] = els[i];
11306                 }
11307             }
11308         }
11309         return this;
11310     },
11311     invoke : function(fn, args){
11312         var els = this.elements;
11313         var el = this.el;
11314         for(var i = 0, len = els.length; i < len; i++) {
11315             el.dom = els[i];
11316                 Roo.Element.prototype[fn].apply(el, args);
11317         }
11318         return this;
11319     },
11320     /**
11321      * Returns a flyweight Element of the dom element object at the specified index
11322      * @param {Number} index
11323      * @return {Roo.Element}
11324      */
11325     item : function(index){
11326         if(!this.elements[index]){
11327             return null;
11328         }
11329         this.el.dom = this.elements[index];
11330         return this.el;
11331     },
11332
11333     // fixes scope with flyweight
11334     addListener : function(eventName, handler, scope, opt){
11335         var els = this.elements;
11336         for(var i = 0, len = els.length; i < len; i++) {
11337             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11338         }
11339         return this;
11340     },
11341
11342     /**
11343     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11344     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11345     * a reference to the dom node, use el.dom.</b>
11346     * @param {Function} fn The function to call
11347     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11348     * @return {CompositeElement} this
11349     */
11350     each : function(fn, scope){
11351         var els = this.elements;
11352         var el = this.el;
11353         for(var i = 0, len = els.length; i < len; i++){
11354             el.dom = els[i];
11355                 if(fn.call(scope || el, el, this, i) === false){
11356                 break;
11357             }
11358         }
11359         return this;
11360     },
11361
11362     indexOf : function(el){
11363         return this.elements.indexOf(Roo.getDom(el));
11364     },
11365
11366     replaceElement : function(el, replacement, domReplace){
11367         var index = typeof el == 'number' ? el : this.indexOf(el);
11368         if(index !== -1){
11369             replacement = Roo.getDom(replacement);
11370             if(domReplace){
11371                 var d = this.elements[index];
11372                 d.parentNode.insertBefore(replacement, d);
11373                 d.parentNode.removeChild(d);
11374             }
11375             this.elements.splice(index, 1, replacement);
11376         }
11377         return this;
11378     }
11379 });
11380 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11381
11382 /*
11383  * Based on:
11384  * Ext JS Library 1.1.1
11385  * Copyright(c) 2006-2007, Ext JS, LLC.
11386  *
11387  * Originally Released Under LGPL - original licence link has changed is not relivant.
11388  *
11389  * Fork - LGPL
11390  * <script type="text/javascript">
11391  */
11392
11393  
11394
11395 /**
11396  * @class Roo.data.Connection
11397  * @extends Roo.util.Observable
11398  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11399  * either to a configured URL, or to a URL specified at request time.<br><br>
11400  * <p>
11401  * Requests made by this class are asynchronous, and will return immediately. No data from
11402  * the server will be available to the statement immediately following the {@link #request} call.
11403  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11404  * <p>
11405  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11406  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11407  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11408  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11409  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11410  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11411  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11412  * standard DOM methods.
11413  * @constructor
11414  * @param {Object} config a configuration object.
11415  */
11416 Roo.data.Connection = function(config){
11417     Roo.apply(this, config);
11418     this.addEvents({
11419         /**
11420          * @event beforerequest
11421          * Fires before a network request is made to retrieve a data object.
11422          * @param {Connection} conn This Connection object.
11423          * @param {Object} options The options config object passed to the {@link #request} method.
11424          */
11425         "beforerequest" : true,
11426         /**
11427          * @event requestcomplete
11428          * Fires if the request was successfully completed.
11429          * @param {Connection} conn This Connection object.
11430          * @param {Object} response The XHR object containing the response data.
11431          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11432          * @param {Object} options The options config object passed to the {@link #request} method.
11433          */
11434         "requestcomplete" : true,
11435         /**
11436          * @event requestexception
11437          * Fires if an error HTTP status was returned from the server.
11438          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11439          * @param {Connection} conn This Connection object.
11440          * @param {Object} response The XHR object containing the response data.
11441          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11442          * @param {Object} options The options config object passed to the {@link #request} method.
11443          */
11444         "requestexception" : true
11445     });
11446     Roo.data.Connection.superclass.constructor.call(this);
11447 };
11448
11449 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11450     /**
11451      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11452      */
11453     /**
11454      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11455      * extra parameters to each request made by this object. (defaults to undefined)
11456      */
11457     /**
11458      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11459      *  to each request made by this object. (defaults to undefined)
11460      */
11461     /**
11462      * @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)
11463      */
11464     /**
11465      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11466      */
11467     timeout : 30000,
11468     /**
11469      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11470      * @type Boolean
11471      */
11472     autoAbort:false,
11473
11474     /**
11475      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11476      * @type Boolean
11477      */
11478     disableCaching: true,
11479
11480     /**
11481      * Sends an HTTP request to a remote server.
11482      * @param {Object} options An object which may contain the following properties:<ul>
11483      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11484      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11485      * request, a url encoded string or a function to call to get either.</li>
11486      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11487      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11488      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11489      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11490      * <li>options {Object} The parameter to the request call.</li>
11491      * <li>success {Boolean} True if the request succeeded.</li>
11492      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11493      * </ul></li>
11494      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11495      * The callback is passed the following parameters:<ul>
11496      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11497      * <li>options {Object} The parameter to the request call.</li>
11498      * </ul></li>
11499      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11500      * The callback is passed the following parameters:<ul>
11501      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11502      * <li>options {Object} The parameter to the request call.</li>
11503      * </ul></li>
11504      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11505      * for the callback function. Defaults to the browser window.</li>
11506      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11507      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11508      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11509      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11510      * params for the post data. Any params will be appended to the URL.</li>
11511      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11512      * </ul>
11513      * @return {Number} transactionId
11514      */
11515     request : function(o){
11516         if(this.fireEvent("beforerequest", this, o) !== false){
11517             var p = o.params;
11518
11519             if(typeof p == "function"){
11520                 p = p.call(o.scope||window, o);
11521             }
11522             if(typeof p == "object"){
11523                 p = Roo.urlEncode(o.params);
11524             }
11525             if(this.extraParams){
11526                 var extras = Roo.urlEncode(this.extraParams);
11527                 p = p ? (p + '&' + extras) : extras;
11528             }
11529
11530             var url = o.url || this.url;
11531             if(typeof url == 'function'){
11532                 url = url.call(o.scope||window, o);
11533             }
11534
11535             if(o.form){
11536                 var form = Roo.getDom(o.form);
11537                 url = url || form.action;
11538
11539                 var enctype = form.getAttribute("enctype");
11540                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11541                     return this.doFormUpload(o, p, url);
11542                 }
11543                 var f = Roo.lib.Ajax.serializeForm(form);
11544                 p = p ? (p + '&' + f) : f;
11545             }
11546
11547             var hs = o.headers;
11548             if(this.defaultHeaders){
11549                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11550                 if(!o.headers){
11551                     o.headers = hs;
11552                 }
11553             }
11554
11555             var cb = {
11556                 success: this.handleResponse,
11557                 failure: this.handleFailure,
11558                 scope: this,
11559                 argument: {options: o},
11560                 timeout : o.timeout || this.timeout
11561             };
11562
11563             var method = o.method||this.method||(p ? "POST" : "GET");
11564
11565             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11566                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11567             }
11568
11569             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11570                 if(o.autoAbort){
11571                     this.abort();
11572                 }
11573             }else if(this.autoAbort !== false){
11574                 this.abort();
11575             }
11576
11577             if((method == 'GET' && p) || o.xmlData){
11578                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11579                 p = '';
11580             }
11581             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11582             return this.transId;
11583         }else{
11584             Roo.callback(o.callback, o.scope, [o, null, null]);
11585             return null;
11586         }
11587     },
11588
11589     /**
11590      * Determine whether this object has a request outstanding.
11591      * @param {Number} transactionId (Optional) defaults to the last transaction
11592      * @return {Boolean} True if there is an outstanding request.
11593      */
11594     isLoading : function(transId){
11595         if(transId){
11596             return Roo.lib.Ajax.isCallInProgress(transId);
11597         }else{
11598             return this.transId ? true : false;
11599         }
11600     },
11601
11602     /**
11603      * Aborts any outstanding request.
11604      * @param {Number} transactionId (Optional) defaults to the last transaction
11605      */
11606     abort : function(transId){
11607         if(transId || this.isLoading()){
11608             Roo.lib.Ajax.abort(transId || this.transId);
11609         }
11610     },
11611
11612     // private
11613     handleResponse : function(response){
11614         this.transId = false;
11615         var options = response.argument.options;
11616         response.argument = options ? options.argument : null;
11617         this.fireEvent("requestcomplete", this, response, options);
11618         Roo.callback(options.success, options.scope, [response, options]);
11619         Roo.callback(options.callback, options.scope, [options, true, response]);
11620     },
11621
11622     // private
11623     handleFailure : function(response, e){
11624         this.transId = false;
11625         var options = response.argument.options;
11626         response.argument = options ? options.argument : null;
11627         this.fireEvent("requestexception", this, response, options, e);
11628         Roo.callback(options.failure, options.scope, [response, options]);
11629         Roo.callback(options.callback, options.scope, [options, false, response]);
11630     },
11631
11632     // private
11633     doFormUpload : function(o, ps, url){
11634         var id = Roo.id();
11635         var frame = document.createElement('iframe');
11636         frame.id = id;
11637         frame.name = id;
11638         frame.className = 'x-hidden';
11639         if(Roo.isIE){
11640             frame.src = Roo.SSL_SECURE_URL;
11641         }
11642         document.body.appendChild(frame);
11643
11644         if(Roo.isIE){
11645            document.frames[id].name = id;
11646         }
11647
11648         var form = Roo.getDom(o.form);
11649         form.target = id;
11650         form.method = 'POST';
11651         form.enctype = form.encoding = 'multipart/form-data';
11652         if(url){
11653             form.action = url;
11654         }
11655
11656         var hiddens, hd;
11657         if(ps){ // add dynamic params
11658             hiddens = [];
11659             ps = Roo.urlDecode(ps, false);
11660             for(var k in ps){
11661                 if(ps.hasOwnProperty(k)){
11662                     hd = document.createElement('input');
11663                     hd.type = 'hidden';
11664                     hd.name = k;
11665                     hd.value = ps[k];
11666                     form.appendChild(hd);
11667                     hiddens.push(hd);
11668                 }
11669             }
11670         }
11671
11672         function cb(){
11673             var r = {  // bogus response object
11674                 responseText : '',
11675                 responseXML : null
11676             };
11677
11678             r.argument = o ? o.argument : null;
11679
11680             try { //
11681                 var doc;
11682                 if(Roo.isIE){
11683                     doc = frame.contentWindow.document;
11684                 }else {
11685                     doc = (frame.contentDocument || window.frames[id].document);
11686                 }
11687                 if(doc && doc.body){
11688                     r.responseText = doc.body.innerHTML;
11689                 }
11690                 if(doc && doc.XMLDocument){
11691                     r.responseXML = doc.XMLDocument;
11692                 }else {
11693                     r.responseXML = doc;
11694                 }
11695             }
11696             catch(e) {
11697                 // ignore
11698             }
11699
11700             Roo.EventManager.removeListener(frame, 'load', cb, this);
11701
11702             this.fireEvent("requestcomplete", this, r, o);
11703             Roo.callback(o.success, o.scope, [r, o]);
11704             Roo.callback(o.callback, o.scope, [o, true, r]);
11705
11706             setTimeout(function(){document.body.removeChild(frame);}, 100);
11707         }
11708
11709         Roo.EventManager.on(frame, 'load', cb, this);
11710         form.submit();
11711
11712         if(hiddens){ // remove dynamic params
11713             for(var i = 0, len = hiddens.length; i < len; i++){
11714                 form.removeChild(hiddens[i]);
11715             }
11716         }
11717     }
11718 });
11719 /*
11720  * Based on:
11721  * Ext JS Library 1.1.1
11722  * Copyright(c) 2006-2007, Ext JS, LLC.
11723  *
11724  * Originally Released Under LGPL - original licence link has changed is not relivant.
11725  *
11726  * Fork - LGPL
11727  * <script type="text/javascript">
11728  */
11729  
11730 /**
11731  * Global Ajax request class.
11732  * 
11733  * @class Roo.Ajax
11734  * @extends Roo.data.Connection
11735  * @static
11736  * 
11737  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11738  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11739  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11740  * @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)
11741  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11742  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11743  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11744  */
11745 Roo.Ajax = new Roo.data.Connection({
11746     // fix up the docs
11747     /**
11748      * @scope Roo.Ajax
11749      * @type {Boolear} 
11750      */
11751     autoAbort : false,
11752
11753     /**
11754      * Serialize the passed form into a url encoded string
11755      * @scope Roo.Ajax
11756      * @param {String/HTMLElement} form
11757      * @return {String}
11758      */
11759     serializeForm : function(form){
11760         return Roo.lib.Ajax.serializeForm(form);
11761     }
11762 });/*
11763  * Based on:
11764  * Ext JS Library 1.1.1
11765  * Copyright(c) 2006-2007, Ext JS, LLC.
11766  *
11767  * Originally Released Under LGPL - original licence link has changed is not relivant.
11768  *
11769  * Fork - LGPL
11770  * <script type="text/javascript">
11771  */
11772
11773  
11774 /**
11775  * @class Roo.UpdateManager
11776  * @extends Roo.util.Observable
11777  * Provides AJAX-style update for Element object.<br><br>
11778  * Usage:<br>
11779  * <pre><code>
11780  * // Get it from a Roo.Element object
11781  * var el = Roo.get("foo");
11782  * var mgr = el.getUpdateManager();
11783  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11784  * ...
11785  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11786  * <br>
11787  * // or directly (returns the same UpdateManager instance)
11788  * var mgr = new Roo.UpdateManager("myElementId");
11789  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11790  * mgr.on("update", myFcnNeedsToKnow);
11791  * <br>
11792    // short handed call directly from the element object
11793    Roo.get("foo").load({
11794         url: "bar.php",
11795         scripts:true,
11796         params: "for=bar",
11797         text: "Loading Foo..."
11798    });
11799  * </code></pre>
11800  * @constructor
11801  * Create new UpdateManager directly.
11802  * @param {String/HTMLElement/Roo.Element} el The element to update
11803  * @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).
11804  */
11805 Roo.UpdateManager = function(el, forceNew){
11806     el = Roo.get(el);
11807     if(!forceNew && el.updateManager){
11808         return el.updateManager;
11809     }
11810     /**
11811      * The Element object
11812      * @type Roo.Element
11813      */
11814     this.el = el;
11815     /**
11816      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11817      * @type String
11818      */
11819     this.defaultUrl = null;
11820
11821     this.addEvents({
11822         /**
11823          * @event beforeupdate
11824          * Fired before an update is made, return false from your handler and the update is cancelled.
11825          * @param {Roo.Element} el
11826          * @param {String/Object/Function} url
11827          * @param {String/Object} params
11828          */
11829         "beforeupdate": true,
11830         /**
11831          * @event update
11832          * Fired after successful update is made.
11833          * @param {Roo.Element} el
11834          * @param {Object} oResponseObject The response Object
11835          */
11836         "update": true,
11837         /**
11838          * @event failure
11839          * Fired on update failure.
11840          * @param {Roo.Element} el
11841          * @param {Object} oResponseObject The response Object
11842          */
11843         "failure": true
11844     });
11845     var d = Roo.UpdateManager.defaults;
11846     /**
11847      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11848      * @type String
11849      */
11850     this.sslBlankUrl = d.sslBlankUrl;
11851     /**
11852      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11853      * @type Boolean
11854      */
11855     this.disableCaching = d.disableCaching;
11856     /**
11857      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11858      * @type String
11859      */
11860     this.indicatorText = d.indicatorText;
11861     /**
11862      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11863      * @type String
11864      */
11865     this.showLoadIndicator = d.showLoadIndicator;
11866     /**
11867      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11868      * @type Number
11869      */
11870     this.timeout = d.timeout;
11871
11872     /**
11873      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11874      * @type Boolean
11875      */
11876     this.loadScripts = d.loadScripts;
11877
11878     /**
11879      * Transaction object of current executing transaction
11880      */
11881     this.transaction = null;
11882
11883     /**
11884      * @private
11885      */
11886     this.autoRefreshProcId = null;
11887     /**
11888      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11889      * @type Function
11890      */
11891     this.refreshDelegate = this.refresh.createDelegate(this);
11892     /**
11893      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11894      * @type Function
11895      */
11896     this.updateDelegate = this.update.createDelegate(this);
11897     /**
11898      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11899      * @type Function
11900      */
11901     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11902     /**
11903      * @private
11904      */
11905     this.successDelegate = this.processSuccess.createDelegate(this);
11906     /**
11907      * @private
11908      */
11909     this.failureDelegate = this.processFailure.createDelegate(this);
11910
11911     if(!this.renderer){
11912      /**
11913       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11914       */
11915     this.renderer = new Roo.UpdateManager.BasicRenderer();
11916     }
11917     
11918     Roo.UpdateManager.superclass.constructor.call(this);
11919 };
11920
11921 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11922     /**
11923      * Get the Element this UpdateManager is bound to
11924      * @return {Roo.Element} The element
11925      */
11926     getEl : function(){
11927         return this.el;
11928     },
11929     /**
11930      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11931      * @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:
11932 <pre><code>
11933 um.update({<br/>
11934     url: "your-url.php",<br/>
11935     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11936     callback: yourFunction,<br/>
11937     scope: yourObject, //(optional scope)  <br/>
11938     discardUrl: false, <br/>
11939     nocache: false,<br/>
11940     text: "Loading...",<br/>
11941     timeout: 30,<br/>
11942     scripts: false<br/>
11943 });
11944 </code></pre>
11945      * The only required property is url. The optional properties nocache, text and scripts
11946      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11947      * @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}
11948      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11949      * @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.
11950      */
11951     update : function(url, params, callback, discardUrl){
11952         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11953             var method = this.method,
11954                 cfg;
11955             if(typeof url == "object"){ // must be config object
11956                 cfg = url;
11957                 url = cfg.url;
11958                 params = params || cfg.params;
11959                 callback = callback || cfg.callback;
11960                 discardUrl = discardUrl || cfg.discardUrl;
11961                 if(callback && cfg.scope){
11962                     callback = callback.createDelegate(cfg.scope);
11963                 }
11964                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11965                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11966                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11967                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11968                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11969             }
11970             this.showLoading();
11971             if(!discardUrl){
11972                 this.defaultUrl = url;
11973             }
11974             if(typeof url == "function"){
11975                 url = url.call(this);
11976             }
11977
11978             method = method || (params ? "POST" : "GET");
11979             if(method == "GET"){
11980                 url = this.prepareUrl(url);
11981             }
11982
11983             var o = Roo.apply(cfg ||{}, {
11984                 url : url,
11985                 params: params,
11986                 success: this.successDelegate,
11987                 failure: this.failureDelegate,
11988                 callback: undefined,
11989                 timeout: (this.timeout*1000),
11990                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11991             });
11992             Roo.log("updated manager called with timeout of " + o.timeout);
11993             this.transaction = Roo.Ajax.request(o);
11994         }
11995     },
11996
11997     /**
11998      * 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.
11999      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12000      * @param {String/HTMLElement} form The form Id or form element
12001      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12002      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12003      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12004      */
12005     formUpdate : function(form, url, reset, callback){
12006         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12007             if(typeof url == "function"){
12008                 url = url.call(this);
12009             }
12010             form = Roo.getDom(form);
12011             this.transaction = Roo.Ajax.request({
12012                 form: form,
12013                 url:url,
12014                 success: this.successDelegate,
12015                 failure: this.failureDelegate,
12016                 timeout: (this.timeout*1000),
12017                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12018             });
12019             this.showLoading.defer(1, this);
12020         }
12021     },
12022
12023     /**
12024      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12025      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12026      */
12027     refresh : function(callback){
12028         if(this.defaultUrl == null){
12029             return;
12030         }
12031         this.update(this.defaultUrl, null, callback, true);
12032     },
12033
12034     /**
12035      * Set this element to auto refresh.
12036      * @param {Number} interval How often to update (in seconds).
12037      * @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)
12038      * @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}
12039      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12040      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12041      */
12042     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12043         if(refreshNow){
12044             this.update(url || this.defaultUrl, params, callback, true);
12045         }
12046         if(this.autoRefreshProcId){
12047             clearInterval(this.autoRefreshProcId);
12048         }
12049         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12050     },
12051
12052     /**
12053      * Stop auto refresh on this element.
12054      */
12055      stopAutoRefresh : function(){
12056         if(this.autoRefreshProcId){
12057             clearInterval(this.autoRefreshProcId);
12058             delete this.autoRefreshProcId;
12059         }
12060     },
12061
12062     isAutoRefreshing : function(){
12063        return this.autoRefreshProcId ? true : false;
12064     },
12065     /**
12066      * Called to update the element to "Loading" state. Override to perform custom action.
12067      */
12068     showLoading : function(){
12069         if(this.showLoadIndicator){
12070             this.el.update(this.indicatorText);
12071         }
12072     },
12073
12074     /**
12075      * Adds unique parameter to query string if disableCaching = true
12076      * @private
12077      */
12078     prepareUrl : function(url){
12079         if(this.disableCaching){
12080             var append = "_dc=" + (new Date().getTime());
12081             if(url.indexOf("?") !== -1){
12082                 url += "&" + append;
12083             }else{
12084                 url += "?" + append;
12085             }
12086         }
12087         return url;
12088     },
12089
12090     /**
12091      * @private
12092      */
12093     processSuccess : function(response){
12094         this.transaction = null;
12095         if(response.argument.form && response.argument.reset){
12096             try{ // put in try/catch since some older FF releases had problems with this
12097                 response.argument.form.reset();
12098             }catch(e){}
12099         }
12100         if(this.loadScripts){
12101             this.renderer.render(this.el, response, this,
12102                 this.updateComplete.createDelegate(this, [response]));
12103         }else{
12104             this.renderer.render(this.el, response, this);
12105             this.updateComplete(response);
12106         }
12107     },
12108
12109     updateComplete : function(response){
12110         this.fireEvent("update", this.el, response);
12111         if(typeof response.argument.callback == "function"){
12112             response.argument.callback(this.el, true, response);
12113         }
12114     },
12115
12116     /**
12117      * @private
12118      */
12119     processFailure : function(response){
12120         this.transaction = null;
12121         this.fireEvent("failure", this.el, response);
12122         if(typeof response.argument.callback == "function"){
12123             response.argument.callback(this.el, false, response);
12124         }
12125     },
12126
12127     /**
12128      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12129      * @param {Object} renderer The object implementing the render() method
12130      */
12131     setRenderer : function(renderer){
12132         this.renderer = renderer;
12133     },
12134
12135     getRenderer : function(){
12136        return this.renderer;
12137     },
12138
12139     /**
12140      * Set the defaultUrl used for updates
12141      * @param {String/Function} defaultUrl The url or a function to call to get the url
12142      */
12143     setDefaultUrl : function(defaultUrl){
12144         this.defaultUrl = defaultUrl;
12145     },
12146
12147     /**
12148      * Aborts the executing transaction
12149      */
12150     abort : function(){
12151         if(this.transaction){
12152             Roo.Ajax.abort(this.transaction);
12153         }
12154     },
12155
12156     /**
12157      * Returns true if an update is in progress
12158      * @return {Boolean}
12159      */
12160     isUpdating : function(){
12161         if(this.transaction){
12162             return Roo.Ajax.isLoading(this.transaction);
12163         }
12164         return false;
12165     }
12166 });
12167
12168 /**
12169  * @class Roo.UpdateManager.defaults
12170  * @static (not really - but it helps the doc tool)
12171  * The defaults collection enables customizing the default properties of UpdateManager
12172  */
12173    Roo.UpdateManager.defaults = {
12174        /**
12175          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12176          * @type Number
12177          */
12178          timeout : 30,
12179
12180          /**
12181          * True to process scripts by default (Defaults to false).
12182          * @type Boolean
12183          */
12184         loadScripts : false,
12185
12186         /**
12187         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12188         * @type String
12189         */
12190         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12191         /**
12192          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12193          * @type Boolean
12194          */
12195         disableCaching : false,
12196         /**
12197          * Whether to show indicatorText when loading (Defaults to true).
12198          * @type Boolean
12199          */
12200         showLoadIndicator : true,
12201         /**
12202          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12203          * @type String
12204          */
12205         indicatorText : '<div class="loading-indicator">Loading...</div>'
12206    };
12207
12208 /**
12209  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12210  *Usage:
12211  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12212  * @param {String/HTMLElement/Roo.Element} el The element to update
12213  * @param {String} url The url
12214  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12215  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12216  * @static
12217  * @deprecated
12218  * @member Roo.UpdateManager
12219  */
12220 Roo.UpdateManager.updateElement = function(el, url, params, options){
12221     var um = Roo.get(el, true).getUpdateManager();
12222     Roo.apply(um, options);
12223     um.update(url, params, options ? options.callback : null);
12224 };
12225 // alias for backwards compat
12226 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12227 /**
12228  * @class Roo.UpdateManager.BasicRenderer
12229  * Default Content renderer. Updates the elements innerHTML with the responseText.
12230  */
12231 Roo.UpdateManager.BasicRenderer = function(){};
12232
12233 Roo.UpdateManager.BasicRenderer.prototype = {
12234     /**
12235      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12236      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12237      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12238      * @param {Roo.Element} el The element being rendered
12239      * @param {Object} response The YUI Connect response object
12240      * @param {UpdateManager} updateManager The calling update manager
12241      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12242      */
12243      render : function(el, response, updateManager, callback){
12244         el.update(response.responseText, updateManager.loadScripts, callback);
12245     }
12246 };
12247 /*
12248  * Based on:
12249  * Roo JS
12250  * (c)) Alan Knowles
12251  * Licence : LGPL
12252  */
12253
12254
12255 /**
12256  * @class Roo.DomTemplate
12257  * @extends Roo.Template
12258  * An effort at a dom based template engine..
12259  *
12260  * Similar to XTemplate, except it uses dom parsing to create the template..
12261  *
12262  * Supported features:
12263  *
12264  *  Tags:
12265
12266 <pre><code>
12267       {a_variable} - output encoded.
12268       {a_variable.format:("Y-m-d")} - call a method on the variable
12269       {a_variable:raw} - unencoded output
12270       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12271       {a_variable:this.method_on_template(...)} - call a method on the template object.
12272  
12273 </code></pre>
12274  *  The tpl tag:
12275 <pre><code>
12276         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12277         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12278         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12279         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12280   
12281 </code></pre>
12282  *      
12283  */
12284 Roo.DomTemplate = function()
12285 {
12286      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12287      if (this.html) {
12288         this.compile();
12289      }
12290 };
12291
12292
12293 Roo.extend(Roo.DomTemplate, Roo.Template, {
12294     /**
12295      * id counter for sub templates.
12296      */
12297     id : 0,
12298     /**
12299      * flag to indicate if dom parser is inside a pre,
12300      * it will strip whitespace if not.
12301      */
12302     inPre : false,
12303     
12304     /**
12305      * The various sub templates
12306      */
12307     tpls : false,
12308     
12309     
12310     
12311     /**
12312      *
12313      * basic tag replacing syntax
12314      * WORD:WORD()
12315      *
12316      * // you can fake an object call by doing this
12317      *  x.t:(test,tesT) 
12318      * 
12319      */
12320     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12321     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12322     
12323     iterChild : function (node, method) {
12324         
12325         var oldPre = this.inPre;
12326         if (node.tagName == 'PRE') {
12327             this.inPre = true;
12328         }
12329         for( var i = 0; i < node.childNodes.length; i++) {
12330             method.call(this, node.childNodes[i]);
12331         }
12332         this.inPre = oldPre;
12333     },
12334     
12335     
12336     
12337     /**
12338      * compile the template
12339      *
12340      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12341      *
12342      */
12343     compile: function()
12344     {
12345         var s = this.html;
12346         
12347         // covert the html into DOM...
12348         var doc = false;
12349         var div =false;
12350         try {
12351             doc = document.implementation.createHTMLDocument("");
12352             doc.documentElement.innerHTML =   this.html  ;
12353             div = doc.documentElement;
12354         } catch (e) {
12355             // old IE... - nasty -- it causes all sorts of issues.. with
12356             // images getting pulled from server..
12357             div = document.createElement('div');
12358             div.innerHTML = this.html;
12359         }
12360         //doc.documentElement.innerHTML = htmlBody
12361          
12362         
12363         
12364         this.tpls = [];
12365         var _t = this;
12366         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12367         
12368         var tpls = this.tpls;
12369         
12370         // create a top level template from the snippet..
12371         
12372         //Roo.log(div.innerHTML);
12373         
12374         var tpl = {
12375             uid : 'master',
12376             id : this.id++,
12377             attr : false,
12378             value : false,
12379             body : div.innerHTML,
12380             
12381             forCall : false,
12382             execCall : false,
12383             dom : div,
12384             isTop : true
12385             
12386         };
12387         tpls.unshift(tpl);
12388         
12389         
12390         // compile them...
12391         this.tpls = [];
12392         Roo.each(tpls, function(tp){
12393             this.compileTpl(tp);
12394             this.tpls[tp.id] = tp;
12395         }, this);
12396         
12397         this.master = tpls[0];
12398         return this;
12399         
12400         
12401     },
12402     
12403     compileNode : function(node, istop) {
12404         // test for
12405         //Roo.log(node);
12406         
12407         
12408         // skip anything not a tag..
12409         if (node.nodeType != 1) {
12410             if (node.nodeType == 3 && !this.inPre) {
12411                 // reduce white space..
12412                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12413                 
12414             }
12415             return;
12416         }
12417         
12418         var tpl = {
12419             uid : false,
12420             id : false,
12421             attr : false,
12422             value : false,
12423             body : '',
12424             
12425             forCall : false,
12426             execCall : false,
12427             dom : false,
12428             isTop : istop
12429             
12430             
12431         };
12432         
12433         
12434         switch(true) {
12435             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12436             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12437             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12438             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12439             // no default..
12440         }
12441         
12442         
12443         if (!tpl.attr) {
12444             // just itterate children..
12445             this.iterChild(node,this.compileNode);
12446             return;
12447         }
12448         tpl.uid = this.id++;
12449         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12450         node.removeAttribute('roo-'+ tpl.attr);
12451         if (tpl.attr != 'name') {
12452             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12453             node.parentNode.replaceChild(placeholder,  node);
12454         } else {
12455             
12456             var placeholder =  document.createElement('span');
12457             placeholder.className = 'roo-tpl-' + tpl.value;
12458             node.parentNode.replaceChild(placeholder,  node);
12459         }
12460         
12461         // parent now sees '{domtplXXXX}
12462         this.iterChild(node,this.compileNode);
12463         
12464         // we should now have node body...
12465         var div = document.createElement('div');
12466         div.appendChild(node);
12467         tpl.dom = node;
12468         // this has the unfortunate side effect of converting tagged attributes
12469         // eg. href="{...}" into %7C...%7D
12470         // this has been fixed by searching for those combo's although it's a bit hacky..
12471         
12472         
12473         tpl.body = div.innerHTML;
12474         
12475         
12476          
12477         tpl.id = tpl.uid;
12478         switch(tpl.attr) {
12479             case 'for' :
12480                 switch (tpl.value) {
12481                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12482                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12483                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12484                 }
12485                 break;
12486             
12487             case 'exec':
12488                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12489                 break;
12490             
12491             case 'if':     
12492                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12493                 break;
12494             
12495             case 'name':
12496                 tpl.id  = tpl.value; // replace non characters???
12497                 break;
12498             
12499         }
12500         
12501         
12502         this.tpls.push(tpl);
12503         
12504         
12505         
12506     },
12507     
12508     
12509     
12510     
12511     /**
12512      * Compile a segment of the template into a 'sub-template'
12513      *
12514      * 
12515      * 
12516      *
12517      */
12518     compileTpl : function(tpl)
12519     {
12520         var fm = Roo.util.Format;
12521         var useF = this.disableFormats !== true;
12522         
12523         var sep = Roo.isGecko ? "+\n" : ",\n";
12524         
12525         var undef = function(str) {
12526             Roo.debug && Roo.log("Property not found :"  + str);
12527             return '';
12528         };
12529           
12530         //Roo.log(tpl.body);
12531         
12532         
12533         
12534         var fn = function(m, lbrace, name, format, args)
12535         {
12536             //Roo.log("ARGS");
12537             //Roo.log(arguments);
12538             args = args ? args.replace(/\\'/g,"'") : args;
12539             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12540             if (typeof(format) == 'undefined') {
12541                 format =  'htmlEncode'; 
12542             }
12543             if (format == 'raw' ) {
12544                 format = false;
12545             }
12546             
12547             if(name.substr(0, 6) == 'domtpl'){
12548                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12549             }
12550             
12551             // build an array of options to determine if value is undefined..
12552             
12553             // basically get 'xxxx.yyyy' then do
12554             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12555             //    (function () { Roo.log("Property not found"); return ''; })() :
12556             //    ......
12557             
12558             var udef_ar = [];
12559             var lookfor = '';
12560             Roo.each(name.split('.'), function(st) {
12561                 lookfor += (lookfor.length ? '.': '') + st;
12562                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12563             });
12564             
12565             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12566             
12567             
12568             if(format && useF){
12569                 
12570                 args = args ? ',' + args : "";
12571                  
12572                 if(format.substr(0, 5) != "this."){
12573                     format = "fm." + format + '(';
12574                 }else{
12575                     format = 'this.call("'+ format.substr(5) + '", ';
12576                     args = ", values";
12577                 }
12578                 
12579                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12580             }
12581              
12582             if (args && args.length) {
12583                 // called with xxyx.yuu:(test,test)
12584                 // change to ()
12585                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12586             }
12587             // raw.. - :raw modifier..
12588             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12589             
12590         };
12591         var body;
12592         // branched to use + in gecko and [].join() in others
12593         if(Roo.isGecko){
12594             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12595                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12596                     "';};};";
12597         }else{
12598             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12599             body.push(tpl.body.replace(/(\r\n|\n)/g,
12600                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12601             body.push("'].join('');};};");
12602             body = body.join('');
12603         }
12604         
12605         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12606        
12607         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12608         eval(body);
12609         
12610         return this;
12611     },
12612      
12613     /**
12614      * same as applyTemplate, except it's done to one of the subTemplates
12615      * when using named templates, you can do:
12616      *
12617      * var str = pl.applySubTemplate('your-name', values);
12618      *
12619      * 
12620      * @param {Number} id of the template
12621      * @param {Object} values to apply to template
12622      * @param {Object} parent (normaly the instance of this object)
12623      */
12624     applySubTemplate : function(id, values, parent)
12625     {
12626         
12627         
12628         var t = this.tpls[id];
12629         
12630         
12631         try { 
12632             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12633                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12634                 return '';
12635             }
12636         } catch(e) {
12637             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12638             Roo.log(values);
12639           
12640             return '';
12641         }
12642         try { 
12643             
12644             if(t.execCall && t.execCall.call(this, values, parent)){
12645                 return '';
12646             }
12647         } catch(e) {
12648             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12649             Roo.log(values);
12650             return '';
12651         }
12652         
12653         try {
12654             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12655             parent = t.target ? values : parent;
12656             if(t.forCall && vs instanceof Array){
12657                 var buf = [];
12658                 for(var i = 0, len = vs.length; i < len; i++){
12659                     try {
12660                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12661                     } catch (e) {
12662                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12663                         Roo.log(e.body);
12664                         //Roo.log(t.compiled);
12665                         Roo.log(vs[i]);
12666                     }   
12667                 }
12668                 return buf.join('');
12669             }
12670         } catch (e) {
12671             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12672             Roo.log(values);
12673             return '';
12674         }
12675         try {
12676             return t.compiled.call(this, vs, parent);
12677         } catch (e) {
12678             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12679             Roo.log(e.body);
12680             //Roo.log(t.compiled);
12681             Roo.log(values);
12682             return '';
12683         }
12684     },
12685
12686    
12687
12688     applyTemplate : function(values){
12689         return this.master.compiled.call(this, values, {});
12690         //var s = this.subs;
12691     },
12692
12693     apply : function(){
12694         return this.applyTemplate.apply(this, arguments);
12695     }
12696
12697  });
12698
12699 Roo.DomTemplate.from = function(el){
12700     el = Roo.getDom(el);
12701     return new Roo.Domtemplate(el.value || el.innerHTML);
12702 };/*
12703  * Based on:
12704  * Ext JS Library 1.1.1
12705  * Copyright(c) 2006-2007, Ext JS, LLC.
12706  *
12707  * Originally Released Under LGPL - original licence link has changed is not relivant.
12708  *
12709  * Fork - LGPL
12710  * <script type="text/javascript">
12711  */
12712
12713 /**
12714  * @class Roo.util.DelayedTask
12715  * Provides a convenient method of performing setTimeout where a new
12716  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12717  * You can use this class to buffer
12718  * the keypress events for a certain number of milliseconds, and perform only if they stop
12719  * for that amount of time.
12720  * @constructor The parameters to this constructor serve as defaults and are not required.
12721  * @param {Function} fn (optional) The default function to timeout
12722  * @param {Object} scope (optional) The default scope of that timeout
12723  * @param {Array} args (optional) The default Array of arguments
12724  */
12725 Roo.util.DelayedTask = function(fn, scope, args){
12726     var id = null, d, t;
12727
12728     var call = function(){
12729         var now = new Date().getTime();
12730         if(now - t >= d){
12731             clearInterval(id);
12732             id = null;
12733             fn.apply(scope, args || []);
12734         }
12735     };
12736     /**
12737      * Cancels any pending timeout and queues a new one
12738      * @param {Number} delay The milliseconds to delay
12739      * @param {Function} newFn (optional) Overrides function passed to constructor
12740      * @param {Object} newScope (optional) Overrides scope passed to constructor
12741      * @param {Array} newArgs (optional) Overrides args passed to constructor
12742      */
12743     this.delay = function(delay, newFn, newScope, newArgs){
12744         if(id && delay != d){
12745             this.cancel();
12746         }
12747         d = delay;
12748         t = new Date().getTime();
12749         fn = newFn || fn;
12750         scope = newScope || scope;
12751         args = newArgs || args;
12752         if(!id){
12753             id = setInterval(call, d);
12754         }
12755     };
12756
12757     /**
12758      * Cancel the last queued timeout
12759      */
12760     this.cancel = function(){
12761         if(id){
12762             clearInterval(id);
12763             id = null;
12764         }
12765     };
12766 };/*
12767  * Based on:
12768  * Ext JS Library 1.1.1
12769  * Copyright(c) 2006-2007, Ext JS, LLC.
12770  *
12771  * Originally Released Under LGPL - original licence link has changed is not relivant.
12772  *
12773  * Fork - LGPL
12774  * <script type="text/javascript">
12775  */
12776  
12777  
12778 Roo.util.TaskRunner = function(interval){
12779     interval = interval || 10;
12780     var tasks = [], removeQueue = [];
12781     var id = 0;
12782     var running = false;
12783
12784     var stopThread = function(){
12785         running = false;
12786         clearInterval(id);
12787         id = 0;
12788     };
12789
12790     var startThread = function(){
12791         if(!running){
12792             running = true;
12793             id = setInterval(runTasks, interval);
12794         }
12795     };
12796
12797     var removeTask = function(task){
12798         removeQueue.push(task);
12799         if(task.onStop){
12800             task.onStop();
12801         }
12802     };
12803
12804     var runTasks = function(){
12805         if(removeQueue.length > 0){
12806             for(var i = 0, len = removeQueue.length; i < len; i++){
12807                 tasks.remove(removeQueue[i]);
12808             }
12809             removeQueue = [];
12810             if(tasks.length < 1){
12811                 stopThread();
12812                 return;
12813             }
12814         }
12815         var now = new Date().getTime();
12816         for(var i = 0, len = tasks.length; i < len; ++i){
12817             var t = tasks[i];
12818             var itime = now - t.taskRunTime;
12819             if(t.interval <= itime){
12820                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12821                 t.taskRunTime = now;
12822                 if(rt === false || t.taskRunCount === t.repeat){
12823                     removeTask(t);
12824                     return;
12825                 }
12826             }
12827             if(t.duration && t.duration <= (now - t.taskStartTime)){
12828                 removeTask(t);
12829             }
12830         }
12831     };
12832
12833     /**
12834      * Queues a new task.
12835      * @param {Object} task
12836      */
12837     this.start = function(task){
12838         tasks.push(task);
12839         task.taskStartTime = new Date().getTime();
12840         task.taskRunTime = 0;
12841         task.taskRunCount = 0;
12842         startThread();
12843         return task;
12844     };
12845
12846     this.stop = function(task){
12847         removeTask(task);
12848         return task;
12849     };
12850
12851     this.stopAll = function(){
12852         stopThread();
12853         for(var i = 0, len = tasks.length; i < len; i++){
12854             if(tasks[i].onStop){
12855                 tasks[i].onStop();
12856             }
12857         }
12858         tasks = [];
12859         removeQueue = [];
12860     };
12861 };
12862
12863 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12864  * Based on:
12865  * Ext JS Library 1.1.1
12866  * Copyright(c) 2006-2007, Ext JS, LLC.
12867  *
12868  * Originally Released Under LGPL - original licence link has changed is not relivant.
12869  *
12870  * Fork - LGPL
12871  * <script type="text/javascript">
12872  */
12873
12874  
12875 /**
12876  * @class Roo.util.MixedCollection
12877  * @extends Roo.util.Observable
12878  * A Collection class that maintains both numeric indexes and keys and exposes events.
12879  * @constructor
12880  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12881  * collection (defaults to false)
12882  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12883  * and return the key value for that item.  This is used when available to look up the key on items that
12884  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12885  * equivalent to providing an implementation for the {@link #getKey} method.
12886  */
12887 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12888     this.items = [];
12889     this.map = {};
12890     this.keys = [];
12891     this.length = 0;
12892     this.addEvents({
12893         /**
12894          * @event clear
12895          * Fires when the collection is cleared.
12896          */
12897         "clear" : true,
12898         /**
12899          * @event add
12900          * Fires when an item is added to the collection.
12901          * @param {Number} index The index at which the item was added.
12902          * @param {Object} o The item added.
12903          * @param {String} key The key associated with the added item.
12904          */
12905         "add" : true,
12906         /**
12907          * @event replace
12908          * Fires when an item is replaced in the collection.
12909          * @param {String} key he key associated with the new added.
12910          * @param {Object} old The item being replaced.
12911          * @param {Object} new The new item.
12912          */
12913         "replace" : true,
12914         /**
12915          * @event remove
12916          * Fires when an item is removed from the collection.
12917          * @param {Object} o The item being removed.
12918          * @param {String} key (optional) The key associated with the removed item.
12919          */
12920         "remove" : true,
12921         "sort" : true
12922     });
12923     this.allowFunctions = allowFunctions === true;
12924     if(keyFn){
12925         this.getKey = keyFn;
12926     }
12927     Roo.util.MixedCollection.superclass.constructor.call(this);
12928 };
12929
12930 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12931     allowFunctions : false,
12932     
12933 /**
12934  * Adds an item to the collection.
12935  * @param {String} key The key to associate with the item
12936  * @param {Object} o The item to add.
12937  * @return {Object} The item added.
12938  */
12939     add : function(key, o){
12940         if(arguments.length == 1){
12941             o = arguments[0];
12942             key = this.getKey(o);
12943         }
12944         if(typeof key == "undefined" || key === null){
12945             this.length++;
12946             this.items.push(o);
12947             this.keys.push(null);
12948         }else{
12949             var old = this.map[key];
12950             if(old){
12951                 return this.replace(key, o);
12952             }
12953             this.length++;
12954             this.items.push(o);
12955             this.map[key] = o;
12956             this.keys.push(key);
12957         }
12958         this.fireEvent("add", this.length-1, o, key);
12959         return o;
12960     },
12961        
12962 /**
12963   * MixedCollection has a generic way to fetch keys if you implement getKey.
12964 <pre><code>
12965 // normal way
12966 var mc = new Roo.util.MixedCollection();
12967 mc.add(someEl.dom.id, someEl);
12968 mc.add(otherEl.dom.id, otherEl);
12969 //and so on
12970
12971 // using getKey
12972 var mc = new Roo.util.MixedCollection();
12973 mc.getKey = function(el){
12974    return el.dom.id;
12975 };
12976 mc.add(someEl);
12977 mc.add(otherEl);
12978
12979 // or via the constructor
12980 var mc = new Roo.util.MixedCollection(false, function(el){
12981    return el.dom.id;
12982 });
12983 mc.add(someEl);
12984 mc.add(otherEl);
12985 </code></pre>
12986  * @param o {Object} The item for which to find the key.
12987  * @return {Object} The key for the passed item.
12988  */
12989     getKey : function(o){
12990          return o.id; 
12991     },
12992    
12993 /**
12994  * Replaces an item in the collection.
12995  * @param {String} key The key associated with the item to replace, or the item to replace.
12996  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12997  * @return {Object}  The new item.
12998  */
12999     replace : function(key, o){
13000         if(arguments.length == 1){
13001             o = arguments[0];
13002             key = this.getKey(o);
13003         }
13004         var old = this.item(key);
13005         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13006              return this.add(key, o);
13007         }
13008         var index = this.indexOfKey(key);
13009         this.items[index] = o;
13010         this.map[key] = o;
13011         this.fireEvent("replace", key, old, o);
13012         return o;
13013     },
13014    
13015 /**
13016  * Adds all elements of an Array or an Object to the collection.
13017  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13018  * an Array of values, each of which are added to the collection.
13019  */
13020     addAll : function(objs){
13021         if(arguments.length > 1 || objs instanceof Array){
13022             var args = arguments.length > 1 ? arguments : objs;
13023             for(var i = 0, len = args.length; i < len; i++){
13024                 this.add(args[i]);
13025             }
13026         }else{
13027             for(var key in objs){
13028                 if(this.allowFunctions || typeof objs[key] != "function"){
13029                     this.add(key, objs[key]);
13030                 }
13031             }
13032         }
13033     },
13034    
13035 /**
13036  * Executes the specified function once for every item in the collection, passing each
13037  * item as the first and only parameter. returning false from the function will stop the iteration.
13038  * @param {Function} fn The function to execute for each item.
13039  * @param {Object} scope (optional) The scope in which to execute the function.
13040  */
13041     each : function(fn, scope){
13042         var items = [].concat(this.items); // each safe for removal
13043         for(var i = 0, len = items.length; i < len; i++){
13044             if(fn.call(scope || items[i], items[i], i, len) === false){
13045                 break;
13046             }
13047         }
13048     },
13049    
13050 /**
13051  * Executes the specified function once for every key in the collection, passing each
13052  * key, and its associated item as the first two parameters.
13053  * @param {Function} fn The function to execute for each item.
13054  * @param {Object} scope (optional) The scope in which to execute the function.
13055  */
13056     eachKey : function(fn, scope){
13057         for(var i = 0, len = this.keys.length; i < len; i++){
13058             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13059         }
13060     },
13061    
13062 /**
13063  * Returns the first item in the collection which elicits a true return value from the
13064  * passed selection function.
13065  * @param {Function} fn The selection function to execute for each item.
13066  * @param {Object} scope (optional) The scope in which to execute the function.
13067  * @return {Object} The first item in the collection which returned true from the selection function.
13068  */
13069     find : function(fn, scope){
13070         for(var i = 0, len = this.items.length; i < len; i++){
13071             if(fn.call(scope || window, this.items[i], this.keys[i])){
13072                 return this.items[i];
13073             }
13074         }
13075         return null;
13076     },
13077    
13078 /**
13079  * Inserts an item at the specified index in the collection.
13080  * @param {Number} index The index to insert the item at.
13081  * @param {String} key The key to associate with the new item, or the item itself.
13082  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13083  * @return {Object} The item inserted.
13084  */
13085     insert : function(index, key, o){
13086         if(arguments.length == 2){
13087             o = arguments[1];
13088             key = this.getKey(o);
13089         }
13090         if(index >= this.length){
13091             return this.add(key, o);
13092         }
13093         this.length++;
13094         this.items.splice(index, 0, o);
13095         if(typeof key != "undefined" && key != null){
13096             this.map[key] = o;
13097         }
13098         this.keys.splice(index, 0, key);
13099         this.fireEvent("add", index, o, key);
13100         return o;
13101     },
13102    
13103 /**
13104  * Removed an item from the collection.
13105  * @param {Object} o The item to remove.
13106  * @return {Object} The item removed.
13107  */
13108     remove : function(o){
13109         return this.removeAt(this.indexOf(o));
13110     },
13111    
13112 /**
13113  * Remove an item from a specified index in the collection.
13114  * @param {Number} index The index within the collection of the item to remove.
13115  */
13116     removeAt : function(index){
13117         if(index < this.length && index >= 0){
13118             this.length--;
13119             var o = this.items[index];
13120             this.items.splice(index, 1);
13121             var key = this.keys[index];
13122             if(typeof key != "undefined"){
13123                 delete this.map[key];
13124             }
13125             this.keys.splice(index, 1);
13126             this.fireEvent("remove", o, key);
13127         }
13128     },
13129    
13130 /**
13131  * Removed an item associated with the passed key fom the collection.
13132  * @param {String} key The key of the item to remove.
13133  */
13134     removeKey : function(key){
13135         return this.removeAt(this.indexOfKey(key));
13136     },
13137    
13138 /**
13139  * Returns the number of items in the collection.
13140  * @return {Number} the number of items in the collection.
13141  */
13142     getCount : function(){
13143         return this.length; 
13144     },
13145    
13146 /**
13147  * Returns index within the collection of the passed Object.
13148  * @param {Object} o The item to find the index of.
13149  * @return {Number} index of the item.
13150  */
13151     indexOf : function(o){
13152         if(!this.items.indexOf){
13153             for(var i = 0, len = this.items.length; i < len; i++){
13154                 if(this.items[i] == o) {
13155                     return i;
13156                 }
13157             }
13158             return -1;
13159         }else{
13160             return this.items.indexOf(o);
13161         }
13162     },
13163    
13164 /**
13165  * Returns index within the collection of the passed key.
13166  * @param {String} key The key to find the index of.
13167  * @return {Number} index of the key.
13168  */
13169     indexOfKey : function(key){
13170         if(!this.keys.indexOf){
13171             for(var i = 0, len = this.keys.length; i < len; i++){
13172                 if(this.keys[i] == key) {
13173                     return i;
13174                 }
13175             }
13176             return -1;
13177         }else{
13178             return this.keys.indexOf(key);
13179         }
13180     },
13181    
13182 /**
13183  * Returns the item associated with the passed key OR index. Key has priority over index.
13184  * @param {String/Number} key The key or index of the item.
13185  * @return {Object} The item associated with the passed key.
13186  */
13187     item : function(key){
13188         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13189         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13190     },
13191     
13192 /**
13193  * Returns the item at the specified index.
13194  * @param {Number} index The index of the item.
13195  * @return {Object}
13196  */
13197     itemAt : function(index){
13198         return this.items[index];
13199     },
13200     
13201 /**
13202  * Returns the item associated with the passed key.
13203  * @param {String/Number} key The key of the item.
13204  * @return {Object} The item associated with the passed key.
13205  */
13206     key : function(key){
13207         return this.map[key];
13208     },
13209    
13210 /**
13211  * Returns true if the collection contains the passed Object as an item.
13212  * @param {Object} o  The Object to look for in the collection.
13213  * @return {Boolean} True if the collection contains the Object as an item.
13214  */
13215     contains : function(o){
13216         return this.indexOf(o) != -1;
13217     },
13218    
13219 /**
13220  * Returns true if the collection contains the passed Object as a key.
13221  * @param {String} key The key to look for in the collection.
13222  * @return {Boolean} True if the collection contains the Object as a key.
13223  */
13224     containsKey : function(key){
13225         return typeof this.map[key] != "undefined";
13226     },
13227    
13228 /**
13229  * Removes all items from the collection.
13230  */
13231     clear : function(){
13232         this.length = 0;
13233         this.items = [];
13234         this.keys = [];
13235         this.map = {};
13236         this.fireEvent("clear");
13237     },
13238    
13239 /**
13240  * Returns the first item in the collection.
13241  * @return {Object} the first item in the collection..
13242  */
13243     first : function(){
13244         return this.items[0]; 
13245     },
13246    
13247 /**
13248  * Returns the last item in the collection.
13249  * @return {Object} the last item in the collection..
13250  */
13251     last : function(){
13252         return this.items[this.length-1];   
13253     },
13254     
13255     _sort : function(property, dir, fn){
13256         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13257         fn = fn || function(a, b){
13258             return a-b;
13259         };
13260         var c = [], k = this.keys, items = this.items;
13261         for(var i = 0, len = items.length; i < len; i++){
13262             c[c.length] = {key: k[i], value: items[i], index: i};
13263         }
13264         c.sort(function(a, b){
13265             var v = fn(a[property], b[property]) * dsc;
13266             if(v == 0){
13267                 v = (a.index < b.index ? -1 : 1);
13268             }
13269             return v;
13270         });
13271         for(var i = 0, len = c.length; i < len; i++){
13272             items[i] = c[i].value;
13273             k[i] = c[i].key;
13274         }
13275         this.fireEvent("sort", this);
13276     },
13277     
13278     /**
13279      * Sorts this collection with the passed comparison function
13280      * @param {String} direction (optional) "ASC" or "DESC"
13281      * @param {Function} fn (optional) comparison function
13282      */
13283     sort : function(dir, fn){
13284         this._sort("value", dir, fn);
13285     },
13286     
13287     /**
13288      * Sorts this collection by keys
13289      * @param {String} direction (optional) "ASC" or "DESC"
13290      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13291      */
13292     keySort : function(dir, fn){
13293         this._sort("key", dir, fn || function(a, b){
13294             return String(a).toUpperCase()-String(b).toUpperCase();
13295         });
13296     },
13297     
13298     /**
13299      * Returns a range of items in this collection
13300      * @param {Number} startIndex (optional) defaults to 0
13301      * @param {Number} endIndex (optional) default to the last item
13302      * @return {Array} An array of items
13303      */
13304     getRange : function(start, end){
13305         var items = this.items;
13306         if(items.length < 1){
13307             return [];
13308         }
13309         start = start || 0;
13310         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13311         var r = [];
13312         if(start <= end){
13313             for(var i = start; i <= end; i++) {
13314                     r[r.length] = items[i];
13315             }
13316         }else{
13317             for(var i = start; i >= end; i--) {
13318                     r[r.length] = items[i];
13319             }
13320         }
13321         return r;
13322     },
13323         
13324     /**
13325      * Filter the <i>objects</i> in this collection by a specific property. 
13326      * Returns a new collection that has been filtered.
13327      * @param {String} property A property on your objects
13328      * @param {String/RegExp} value Either string that the property values 
13329      * should start with or a RegExp to test against the property
13330      * @return {MixedCollection} The new filtered collection
13331      */
13332     filter : function(property, value){
13333         if(!value.exec){ // not a regex
13334             value = String(value);
13335             if(value.length == 0){
13336                 return this.clone();
13337             }
13338             value = new RegExp("^" + Roo.escapeRe(value), "i");
13339         }
13340         return this.filterBy(function(o){
13341             return o && value.test(o[property]);
13342         });
13343         },
13344     
13345     /**
13346      * Filter by a function. * Returns a new collection that has been filtered.
13347      * The passed function will be called with each 
13348      * object in the collection. If the function returns true, the value is included 
13349      * otherwise it is filtered.
13350      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13351      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13352      * @return {MixedCollection} The new filtered collection
13353      */
13354     filterBy : function(fn, scope){
13355         var r = new Roo.util.MixedCollection();
13356         r.getKey = this.getKey;
13357         var k = this.keys, it = this.items;
13358         for(var i = 0, len = it.length; i < len; i++){
13359             if(fn.call(scope||this, it[i], k[i])){
13360                                 r.add(k[i], it[i]);
13361                         }
13362         }
13363         return r;
13364     },
13365     
13366     /**
13367      * Creates a duplicate of this collection
13368      * @return {MixedCollection}
13369      */
13370     clone : function(){
13371         var r = new Roo.util.MixedCollection();
13372         var k = this.keys, it = this.items;
13373         for(var i = 0, len = it.length; i < len; i++){
13374             r.add(k[i], it[i]);
13375         }
13376         r.getKey = this.getKey;
13377         return r;
13378     }
13379 });
13380 /**
13381  * Returns the item associated with the passed key or index.
13382  * @method
13383  * @param {String/Number} key The key or index of the item.
13384  * @return {Object} The item associated with the passed key.
13385  */
13386 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13387  * Based on:
13388  * Ext JS Library 1.1.1
13389  * Copyright(c) 2006-2007, Ext JS, LLC.
13390  *
13391  * Originally Released Under LGPL - original licence link has changed is not relivant.
13392  *
13393  * Fork - LGPL
13394  * <script type="text/javascript">
13395  */
13396 /**
13397  * @class Roo.util.JSON
13398  * Modified version of Douglas Crockford"s json.js that doesn"t
13399  * mess with the Object prototype 
13400  * http://www.json.org/js.html
13401  * @singleton
13402  */
13403 Roo.util.JSON = new (function(){
13404     var useHasOwn = {}.hasOwnProperty ? true : false;
13405     
13406     // crashes Safari in some instances
13407     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13408     
13409     var pad = function(n) {
13410         return n < 10 ? "0" + n : n;
13411     };
13412     
13413     var m = {
13414         "\b": '\\b',
13415         "\t": '\\t',
13416         "\n": '\\n',
13417         "\f": '\\f',
13418         "\r": '\\r',
13419         '"' : '\\"',
13420         "\\": '\\\\'
13421     };
13422
13423     var encodeString = function(s){
13424         if (/["\\\x00-\x1f]/.test(s)) {
13425             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13426                 var c = m[b];
13427                 if(c){
13428                     return c;
13429                 }
13430                 c = b.charCodeAt();
13431                 return "\\u00" +
13432                     Math.floor(c / 16).toString(16) +
13433                     (c % 16).toString(16);
13434             }) + '"';
13435         }
13436         return '"' + s + '"';
13437     };
13438     
13439     var encodeArray = function(o){
13440         var a = ["["], b, i, l = o.length, v;
13441             for (i = 0; i < l; i += 1) {
13442                 v = o[i];
13443                 switch (typeof v) {
13444                     case "undefined":
13445                     case "function":
13446                     case "unknown":
13447                         break;
13448                     default:
13449                         if (b) {
13450                             a.push(',');
13451                         }
13452                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13453                         b = true;
13454                 }
13455             }
13456             a.push("]");
13457             return a.join("");
13458     };
13459     
13460     var encodeDate = function(o){
13461         return '"' + o.getFullYear() + "-" +
13462                 pad(o.getMonth() + 1) + "-" +
13463                 pad(o.getDate()) + "T" +
13464                 pad(o.getHours()) + ":" +
13465                 pad(o.getMinutes()) + ":" +
13466                 pad(o.getSeconds()) + '"';
13467     };
13468     
13469     /**
13470      * Encodes an Object, Array or other value
13471      * @param {Mixed} o The variable to encode
13472      * @return {String} The JSON string
13473      */
13474     this.encode = function(o)
13475     {
13476         // should this be extended to fully wrap stringify..
13477         
13478         if(typeof o == "undefined" || o === null){
13479             return "null";
13480         }else if(o instanceof Array){
13481             return encodeArray(o);
13482         }else if(o instanceof Date){
13483             return encodeDate(o);
13484         }else if(typeof o == "string"){
13485             return encodeString(o);
13486         }else if(typeof o == "number"){
13487             return isFinite(o) ? String(o) : "null";
13488         }else if(typeof o == "boolean"){
13489             return String(o);
13490         }else {
13491             var a = ["{"], b, i, v;
13492             for (i in o) {
13493                 if(!useHasOwn || o.hasOwnProperty(i)) {
13494                     v = o[i];
13495                     switch (typeof v) {
13496                     case "undefined":
13497                     case "function":
13498                     case "unknown":
13499                         break;
13500                     default:
13501                         if(b){
13502                             a.push(',');
13503                         }
13504                         a.push(this.encode(i), ":",
13505                                 v === null ? "null" : this.encode(v));
13506                         b = true;
13507                     }
13508                 }
13509             }
13510             a.push("}");
13511             return a.join("");
13512         }
13513     };
13514     
13515     /**
13516      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13517      * @param {String} json The JSON string
13518      * @return {Object} The resulting object
13519      */
13520     this.decode = function(json){
13521         
13522         return  /** eval:var:json */ eval("(" + json + ')');
13523     };
13524 })();
13525 /** 
13526  * Shorthand for {@link Roo.util.JSON#encode}
13527  * @member Roo encode 
13528  * @method */
13529 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13530 /** 
13531  * Shorthand for {@link Roo.util.JSON#decode}
13532  * @member Roo decode 
13533  * @method */
13534 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13535 /*
13536  * Based on:
13537  * Ext JS Library 1.1.1
13538  * Copyright(c) 2006-2007, Ext JS, LLC.
13539  *
13540  * Originally Released Under LGPL - original licence link has changed is not relivant.
13541  *
13542  * Fork - LGPL
13543  * <script type="text/javascript">
13544  */
13545  
13546 /**
13547  * @class Roo.util.Format
13548  * Reusable data formatting functions
13549  * @singleton
13550  */
13551 Roo.util.Format = function(){
13552     var trimRe = /^\s+|\s+$/g;
13553     return {
13554         /**
13555          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13556          * @param {String} value The string to truncate
13557          * @param {Number} length The maximum length to allow before truncating
13558          * @return {String} The converted text
13559          */
13560         ellipsis : function(value, len){
13561             if(value && value.length > len){
13562                 return value.substr(0, len-3)+"...";
13563             }
13564             return value;
13565         },
13566
13567         /**
13568          * Checks a reference and converts it to empty string if it is undefined
13569          * @param {Mixed} value Reference to check
13570          * @return {Mixed} Empty string if converted, otherwise the original value
13571          */
13572         undef : function(value){
13573             return typeof value != "undefined" ? value : "";
13574         },
13575
13576         /**
13577          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13578          * @param {String} value The string to encode
13579          * @return {String} The encoded text
13580          */
13581         htmlEncode : function(value){
13582             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13583         },
13584
13585         /**
13586          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13587          * @param {String} value The string to decode
13588          * @return {String} The decoded text
13589          */
13590         htmlDecode : function(value){
13591             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13592         },
13593
13594         /**
13595          * Trims any whitespace from either side of a string
13596          * @param {String} value The text to trim
13597          * @return {String} The trimmed text
13598          */
13599         trim : function(value){
13600             return String(value).replace(trimRe, "");
13601         },
13602
13603         /**
13604          * Returns a substring from within an original string
13605          * @param {String} value The original text
13606          * @param {Number} start The start index of the substring
13607          * @param {Number} length The length of the substring
13608          * @return {String} The substring
13609          */
13610         substr : function(value, start, length){
13611             return String(value).substr(start, length);
13612         },
13613
13614         /**
13615          * Converts a string to all lower case letters
13616          * @param {String} value The text to convert
13617          * @return {String} The converted text
13618          */
13619         lowercase : function(value){
13620             return String(value).toLowerCase();
13621         },
13622
13623         /**
13624          * Converts a string to all upper case letters
13625          * @param {String} value The text to convert
13626          * @return {String} The converted text
13627          */
13628         uppercase : function(value){
13629             return String(value).toUpperCase();
13630         },
13631
13632         /**
13633          * Converts the first character only of a string to upper case
13634          * @param {String} value The text to convert
13635          * @return {String} The converted text
13636          */
13637         capitalize : function(value){
13638             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13639         },
13640
13641         // private
13642         call : function(value, fn){
13643             if(arguments.length > 2){
13644                 var args = Array.prototype.slice.call(arguments, 2);
13645                 args.unshift(value);
13646                  
13647                 return /** eval:var:value */  eval(fn).apply(window, args);
13648             }else{
13649                 /** eval:var:value */
13650                 return /** eval:var:value */ eval(fn).call(window, value);
13651             }
13652         },
13653
13654        
13655         /**
13656          * safer version of Math.toFixed..??/
13657          * @param {Number/String} value The numeric value to format
13658          * @param {Number/String} value Decimal places 
13659          * @return {String} The formatted currency string
13660          */
13661         toFixed : function(v, n)
13662         {
13663             // why not use to fixed - precision is buggered???
13664             if (!n) {
13665                 return Math.round(v-0);
13666             }
13667             var fact = Math.pow(10,n+1);
13668             v = (Math.round((v-0)*fact))/fact;
13669             var z = (''+fact).substring(2);
13670             if (v == Math.floor(v)) {
13671                 return Math.floor(v) + '.' + z;
13672             }
13673             
13674             // now just padd decimals..
13675             var ps = String(v).split('.');
13676             var fd = (ps[1] + z);
13677             var r = fd.substring(0,n); 
13678             var rm = fd.substring(n); 
13679             if (rm < 5) {
13680                 return ps[0] + '.' + r;
13681             }
13682             r*=1; // turn it into a number;
13683             r++;
13684             if (String(r).length != n) {
13685                 ps[0]*=1;
13686                 ps[0]++;
13687                 r = String(r).substring(1); // chop the end off.
13688             }
13689             
13690             return ps[0] + '.' + r;
13691              
13692         },
13693         
13694         /**
13695          * Format a number as US currency
13696          * @param {Number/String} value The numeric value to format
13697          * @return {String} The formatted currency string
13698          */
13699         usMoney : function(v){
13700             return '$' + Roo.util.Format.number(v);
13701         },
13702         
13703         /**
13704          * Format a number
13705          * eventually this should probably emulate php's number_format
13706          * @param {Number/String} value The numeric value to format
13707          * @param {Number} decimals number of decimal places
13708          * @return {String} The formatted currency string
13709          */
13710         number : function(v,decimals)
13711         {
13712             // multiply and round.
13713             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13714             var mul = Math.pow(10, decimals);
13715             var zero = String(mul).substring(1);
13716             v = (Math.round((v-0)*mul))/mul;
13717             
13718             // if it's '0' number.. then
13719             
13720             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13721             v = String(v);
13722             var ps = v.split('.');
13723             var whole = ps[0];
13724             
13725             
13726             var r = /(\d+)(\d{3})/;
13727             // add comma's
13728             while (r.test(whole)) {
13729                 whole = whole.replace(r, '$1' + ',' + '$2');
13730             }
13731             
13732             
13733             var sub = ps[1] ?
13734                     // has decimals..
13735                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13736                     // does not have decimals
13737                     (decimals ? ('.' + zero) : '');
13738             
13739             
13740             return whole + sub ;
13741         },
13742         
13743         /**
13744          * Parse a value into a formatted date using the specified format pattern.
13745          * @param {Mixed} value The value to format
13746          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13747          * @return {String} The formatted date string
13748          */
13749         date : function(v, format){
13750             if(!v){
13751                 return "";
13752             }
13753             if(!(v instanceof Date)){
13754                 v = new Date(Date.parse(v));
13755             }
13756             return v.dateFormat(format || Roo.util.Format.defaults.date);
13757         },
13758
13759         /**
13760          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13761          * @param {String} format Any valid date format string
13762          * @return {Function} The date formatting function
13763          */
13764         dateRenderer : function(format){
13765             return function(v){
13766                 return Roo.util.Format.date(v, format);  
13767             };
13768         },
13769
13770         // private
13771         stripTagsRE : /<\/?[^>]+>/gi,
13772         
13773         /**
13774          * Strips all HTML tags
13775          * @param {Mixed} value The text from which to strip tags
13776          * @return {String} The stripped text
13777          */
13778         stripTags : function(v){
13779             return !v ? v : String(v).replace(this.stripTagsRE, "");
13780         }
13781     };
13782 }();
13783 Roo.util.Format.defaults = {
13784     date : 'd/M/Y'
13785 };/*
13786  * Based on:
13787  * Ext JS Library 1.1.1
13788  * Copyright(c) 2006-2007, Ext JS, LLC.
13789  *
13790  * Originally Released Under LGPL - original licence link has changed is not relivant.
13791  *
13792  * Fork - LGPL
13793  * <script type="text/javascript">
13794  */
13795
13796
13797  
13798
13799 /**
13800  * @class Roo.MasterTemplate
13801  * @extends Roo.Template
13802  * Provides a template that can have child templates. The syntax is:
13803 <pre><code>
13804 var t = new Roo.MasterTemplate(
13805         '&lt;select name="{name}"&gt;',
13806                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13807         '&lt;/select&gt;'
13808 );
13809 t.add('options', {value: 'foo', text: 'bar'});
13810 // or you can add multiple child elements in one shot
13811 t.addAll('options', [
13812     {value: 'foo', text: 'bar'},
13813     {value: 'foo2', text: 'bar2'},
13814     {value: 'foo3', text: 'bar3'}
13815 ]);
13816 // then append, applying the master template values
13817 t.append('my-form', {name: 'my-select'});
13818 </code></pre>
13819 * A name attribute for the child template is not required if you have only one child
13820 * template or you want to refer to them by index.
13821  */
13822 Roo.MasterTemplate = function(){
13823     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13824     this.originalHtml = this.html;
13825     var st = {};
13826     var m, re = this.subTemplateRe;
13827     re.lastIndex = 0;
13828     var subIndex = 0;
13829     while(m = re.exec(this.html)){
13830         var name = m[1], content = m[2];
13831         st[subIndex] = {
13832             name: name,
13833             index: subIndex,
13834             buffer: [],
13835             tpl : new Roo.Template(content)
13836         };
13837         if(name){
13838             st[name] = st[subIndex];
13839         }
13840         st[subIndex].tpl.compile();
13841         st[subIndex].tpl.call = this.call.createDelegate(this);
13842         subIndex++;
13843     }
13844     this.subCount = subIndex;
13845     this.subs = st;
13846 };
13847 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13848     /**
13849     * The regular expression used to match sub templates
13850     * @type RegExp
13851     * @property
13852     */
13853     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13854
13855     /**
13856      * Applies the passed values to a child template.
13857      * @param {String/Number} name (optional) The name or index of the child template
13858      * @param {Array/Object} values The values to be applied to the template
13859      * @return {MasterTemplate} this
13860      */
13861      add : function(name, values){
13862         if(arguments.length == 1){
13863             values = arguments[0];
13864             name = 0;
13865         }
13866         var s = this.subs[name];
13867         s.buffer[s.buffer.length] = s.tpl.apply(values);
13868         return this;
13869     },
13870
13871     /**
13872      * Applies all the passed values to a child template.
13873      * @param {String/Number} name (optional) The name or index of the child template
13874      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13875      * @param {Boolean} reset (optional) True to reset the template first
13876      * @return {MasterTemplate} this
13877      */
13878     fill : function(name, values, reset){
13879         var a = arguments;
13880         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13881             values = a[0];
13882             name = 0;
13883             reset = a[1];
13884         }
13885         if(reset){
13886             this.reset();
13887         }
13888         for(var i = 0, len = values.length; i < len; i++){
13889             this.add(name, values[i]);
13890         }
13891         return this;
13892     },
13893
13894     /**
13895      * Resets the template for reuse
13896      * @return {MasterTemplate} this
13897      */
13898      reset : function(){
13899         var s = this.subs;
13900         for(var i = 0; i < this.subCount; i++){
13901             s[i].buffer = [];
13902         }
13903         return this;
13904     },
13905
13906     applyTemplate : function(values){
13907         var s = this.subs;
13908         var replaceIndex = -1;
13909         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13910             return s[++replaceIndex].buffer.join("");
13911         });
13912         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13913     },
13914
13915     apply : function(){
13916         return this.applyTemplate.apply(this, arguments);
13917     },
13918
13919     compile : function(){return this;}
13920 });
13921
13922 /**
13923  * Alias for fill().
13924  * @method
13925  */
13926 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13927  /**
13928  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13929  * var tpl = Roo.MasterTemplate.from('element-id');
13930  * @param {String/HTMLElement} el
13931  * @param {Object} config
13932  * @static
13933  */
13934 Roo.MasterTemplate.from = function(el, config){
13935     el = Roo.getDom(el);
13936     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13937 };/*
13938  * Based on:
13939  * Ext JS Library 1.1.1
13940  * Copyright(c) 2006-2007, Ext JS, LLC.
13941  *
13942  * Originally Released Under LGPL - original licence link has changed is not relivant.
13943  *
13944  * Fork - LGPL
13945  * <script type="text/javascript">
13946  */
13947
13948  
13949 /**
13950  * @class Roo.util.CSS
13951  * Utility class for manipulating CSS rules
13952  * @singleton
13953  */
13954 Roo.util.CSS = function(){
13955         var rules = null;
13956         var doc = document;
13957
13958     var camelRe = /(-[a-z])/gi;
13959     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13960
13961    return {
13962    /**
13963     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13964     * tag and appended to the HEAD of the document.
13965     * @param {String|Object} cssText The text containing the css rules
13966     * @param {String} id An id to add to the stylesheet for later removal
13967     * @return {StyleSheet}
13968     */
13969     createStyleSheet : function(cssText, id){
13970         var ss;
13971         var head = doc.getElementsByTagName("head")[0];
13972         var nrules = doc.createElement("style");
13973         nrules.setAttribute("type", "text/css");
13974         if(id){
13975             nrules.setAttribute("id", id);
13976         }
13977         if (typeof(cssText) != 'string') {
13978             // support object maps..
13979             // not sure if this a good idea.. 
13980             // perhaps it should be merged with the general css handling
13981             // and handle js style props.
13982             var cssTextNew = [];
13983             for(var n in cssText) {
13984                 var citems = [];
13985                 for(var k in cssText[n]) {
13986                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13987                 }
13988                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13989                 
13990             }
13991             cssText = cssTextNew.join("\n");
13992             
13993         }
13994        
13995        
13996        if(Roo.isIE){
13997            head.appendChild(nrules);
13998            ss = nrules.styleSheet;
13999            ss.cssText = cssText;
14000        }else{
14001            try{
14002                 nrules.appendChild(doc.createTextNode(cssText));
14003            }catch(e){
14004                nrules.cssText = cssText; 
14005            }
14006            head.appendChild(nrules);
14007            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14008        }
14009        this.cacheStyleSheet(ss);
14010        return ss;
14011    },
14012
14013    /**
14014     * Removes a style or link tag by id
14015     * @param {String} id The id of the tag
14016     */
14017    removeStyleSheet : function(id){
14018        var existing = doc.getElementById(id);
14019        if(existing){
14020            existing.parentNode.removeChild(existing);
14021        }
14022    },
14023
14024    /**
14025     * Dynamically swaps an existing stylesheet reference for a new one
14026     * @param {String} id The id of an existing link tag to remove
14027     * @param {String} url The href of the new stylesheet to include
14028     */
14029    swapStyleSheet : function(id, url){
14030        this.removeStyleSheet(id);
14031        var ss = doc.createElement("link");
14032        ss.setAttribute("rel", "stylesheet");
14033        ss.setAttribute("type", "text/css");
14034        ss.setAttribute("id", id);
14035        ss.setAttribute("href", url);
14036        doc.getElementsByTagName("head")[0].appendChild(ss);
14037    },
14038    
14039    /**
14040     * Refresh the rule cache if you have dynamically added stylesheets
14041     * @return {Object} An object (hash) of rules indexed by selector
14042     */
14043    refreshCache : function(){
14044        return this.getRules(true);
14045    },
14046
14047    // private
14048    cacheStyleSheet : function(stylesheet){
14049        if(!rules){
14050            rules = {};
14051        }
14052        try{// try catch for cross domain access issue
14053            var ssRules = stylesheet.cssRules || stylesheet.rules;
14054            for(var j = ssRules.length-1; j >= 0; --j){
14055                rules[ssRules[j].selectorText] = ssRules[j];
14056            }
14057        }catch(e){}
14058    },
14059    
14060    /**
14061     * Gets all css rules for the document
14062     * @param {Boolean} refreshCache true to refresh the internal cache
14063     * @return {Object} An object (hash) of rules indexed by selector
14064     */
14065    getRules : function(refreshCache){
14066                 if(rules == null || refreshCache){
14067                         rules = {};
14068                         var ds = doc.styleSheets;
14069                         for(var i =0, len = ds.length; i < len; i++){
14070                             try{
14071                         this.cacheStyleSheet(ds[i]);
14072                     }catch(e){} 
14073                 }
14074                 }
14075                 return rules;
14076         },
14077         
14078         /**
14079     * Gets an an individual CSS rule by selector(s)
14080     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14081     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14082     * @return {CSSRule} The CSS rule or null if one is not found
14083     */
14084    getRule : function(selector, refreshCache){
14085                 var rs = this.getRules(refreshCache);
14086                 if(!(selector instanceof Array)){
14087                     return rs[selector];
14088                 }
14089                 for(var i = 0; i < selector.length; i++){
14090                         if(rs[selector[i]]){
14091                                 return rs[selector[i]];
14092                         }
14093                 }
14094                 return null;
14095         },
14096         
14097         
14098         /**
14099     * Updates a rule property
14100     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14101     * @param {String} property The css property
14102     * @param {String} value The new value for the property
14103     * @return {Boolean} true If a rule was found and updated
14104     */
14105    updateRule : function(selector, property, value){
14106                 if(!(selector instanceof Array)){
14107                         var rule = this.getRule(selector);
14108                         if(rule){
14109                                 rule.style[property.replace(camelRe, camelFn)] = value;
14110                                 return true;
14111                         }
14112                 }else{
14113                         for(var i = 0; i < selector.length; i++){
14114                                 if(this.updateRule(selector[i], property, value)){
14115                                         return true;
14116                                 }
14117                         }
14118                 }
14119                 return false;
14120         }
14121    };   
14122 }();/*
14123  * Based on:
14124  * Ext JS Library 1.1.1
14125  * Copyright(c) 2006-2007, Ext JS, LLC.
14126  *
14127  * Originally Released Under LGPL - original licence link has changed is not relivant.
14128  *
14129  * Fork - LGPL
14130  * <script type="text/javascript">
14131  */
14132
14133  
14134
14135 /**
14136  * @class Roo.util.ClickRepeater
14137  * @extends Roo.util.Observable
14138  * 
14139  * A wrapper class which can be applied to any element. Fires a "click" event while the
14140  * mouse is pressed. The interval between firings may be specified in the config but
14141  * defaults to 10 milliseconds.
14142  * 
14143  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14144  * 
14145  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14146  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14147  * Similar to an autorepeat key delay.
14148  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14149  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14150  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14151  *           "interval" and "delay" are ignored. "immediate" is honored.
14152  * @cfg {Boolean} preventDefault True to prevent the default click event
14153  * @cfg {Boolean} stopDefault True to stop the default click event
14154  * 
14155  * @history
14156  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14157  *     2007-02-02 jvs Renamed to ClickRepeater
14158  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14159  *
14160  *  @constructor
14161  * @param {String/HTMLElement/Element} el The element to listen on
14162  * @param {Object} config
14163  **/
14164 Roo.util.ClickRepeater = function(el, config)
14165 {
14166     this.el = Roo.get(el);
14167     this.el.unselectable();
14168
14169     Roo.apply(this, config);
14170
14171     this.addEvents({
14172     /**
14173      * @event mousedown
14174      * Fires when the mouse button is depressed.
14175      * @param {Roo.util.ClickRepeater} this
14176      */
14177         "mousedown" : true,
14178     /**
14179      * @event click
14180      * Fires on a specified interval during the time the element is pressed.
14181      * @param {Roo.util.ClickRepeater} this
14182      */
14183         "click" : true,
14184     /**
14185      * @event mouseup
14186      * Fires when the mouse key is released.
14187      * @param {Roo.util.ClickRepeater} this
14188      */
14189         "mouseup" : true
14190     });
14191
14192     this.el.on("mousedown", this.handleMouseDown, this);
14193     if(this.preventDefault || this.stopDefault){
14194         this.el.on("click", function(e){
14195             if(this.preventDefault){
14196                 e.preventDefault();
14197             }
14198             if(this.stopDefault){
14199                 e.stopEvent();
14200             }
14201         }, this);
14202     }
14203
14204     // allow inline handler
14205     if(this.handler){
14206         this.on("click", this.handler,  this.scope || this);
14207     }
14208
14209     Roo.util.ClickRepeater.superclass.constructor.call(this);
14210 };
14211
14212 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14213     interval : 20,
14214     delay: 250,
14215     preventDefault : true,
14216     stopDefault : false,
14217     timer : 0,
14218
14219     // private
14220     handleMouseDown : function(){
14221         clearTimeout(this.timer);
14222         this.el.blur();
14223         if(this.pressClass){
14224             this.el.addClass(this.pressClass);
14225         }
14226         this.mousedownTime = new Date();
14227
14228         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14229         this.el.on("mouseout", this.handleMouseOut, this);
14230
14231         this.fireEvent("mousedown", this);
14232         this.fireEvent("click", this);
14233         
14234         this.timer = this.click.defer(this.delay || this.interval, this);
14235     },
14236
14237     // private
14238     click : function(){
14239         this.fireEvent("click", this);
14240         this.timer = this.click.defer(this.getInterval(), this);
14241     },
14242
14243     // private
14244     getInterval: function(){
14245         if(!this.accelerate){
14246             return this.interval;
14247         }
14248         var pressTime = this.mousedownTime.getElapsed();
14249         if(pressTime < 500){
14250             return 400;
14251         }else if(pressTime < 1700){
14252             return 320;
14253         }else if(pressTime < 2600){
14254             return 250;
14255         }else if(pressTime < 3500){
14256             return 180;
14257         }else if(pressTime < 4400){
14258             return 140;
14259         }else if(pressTime < 5300){
14260             return 80;
14261         }else if(pressTime < 6200){
14262             return 50;
14263         }else{
14264             return 10;
14265         }
14266     },
14267
14268     // private
14269     handleMouseOut : function(){
14270         clearTimeout(this.timer);
14271         if(this.pressClass){
14272             this.el.removeClass(this.pressClass);
14273         }
14274         this.el.on("mouseover", this.handleMouseReturn, this);
14275     },
14276
14277     // private
14278     handleMouseReturn : function(){
14279         this.el.un("mouseover", this.handleMouseReturn);
14280         if(this.pressClass){
14281             this.el.addClass(this.pressClass);
14282         }
14283         this.click();
14284     },
14285
14286     // private
14287     handleMouseUp : function(){
14288         clearTimeout(this.timer);
14289         this.el.un("mouseover", this.handleMouseReturn);
14290         this.el.un("mouseout", this.handleMouseOut);
14291         Roo.get(document).un("mouseup", this.handleMouseUp);
14292         this.el.removeClass(this.pressClass);
14293         this.fireEvent("mouseup", this);
14294     }
14295 });/*
14296  * Based on:
14297  * Ext JS Library 1.1.1
14298  * Copyright(c) 2006-2007, Ext JS, LLC.
14299  *
14300  * Originally Released Under LGPL - original licence link has changed is not relivant.
14301  *
14302  * Fork - LGPL
14303  * <script type="text/javascript">
14304  */
14305
14306  
14307 /**
14308  * @class Roo.KeyNav
14309  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14310  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14311  * way to implement custom navigation schemes for any UI component.</p>
14312  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14313  * pageUp, pageDown, del, home, end.  Usage:</p>
14314  <pre><code>
14315 var nav = new Roo.KeyNav("my-element", {
14316     "left" : function(e){
14317         this.moveLeft(e.ctrlKey);
14318     },
14319     "right" : function(e){
14320         this.moveRight(e.ctrlKey);
14321     },
14322     "enter" : function(e){
14323         this.save();
14324     },
14325     scope : this
14326 });
14327 </code></pre>
14328  * @constructor
14329  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14330  * @param {Object} config The config
14331  */
14332 Roo.KeyNav = function(el, config){
14333     this.el = Roo.get(el);
14334     Roo.apply(this, config);
14335     if(!this.disabled){
14336         this.disabled = true;
14337         this.enable();
14338     }
14339 };
14340
14341 Roo.KeyNav.prototype = {
14342     /**
14343      * @cfg {Boolean} disabled
14344      * True to disable this KeyNav instance (defaults to false)
14345      */
14346     disabled : false,
14347     /**
14348      * @cfg {String} defaultEventAction
14349      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14350      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14351      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14352      */
14353     defaultEventAction: "stopEvent",
14354     /**
14355      * @cfg {Boolean} forceKeyDown
14356      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14357      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14358      * handle keydown instead of keypress.
14359      */
14360     forceKeyDown : false,
14361
14362     // private
14363     prepareEvent : function(e){
14364         var k = e.getKey();
14365         var h = this.keyToHandler[k];
14366         //if(h && this[h]){
14367         //    e.stopPropagation();
14368         //}
14369         if(Roo.isSafari && h && k >= 37 && k <= 40){
14370             e.stopEvent();
14371         }
14372     },
14373
14374     // private
14375     relay : function(e){
14376         var k = e.getKey();
14377         var h = this.keyToHandler[k];
14378         if(h && this[h]){
14379             if(this.doRelay(e, this[h], h) !== true){
14380                 e[this.defaultEventAction]();
14381             }
14382         }
14383     },
14384
14385     // private
14386     doRelay : function(e, h, hname){
14387         return h.call(this.scope || this, e);
14388     },
14389
14390     // possible handlers
14391     enter : false,
14392     left : false,
14393     right : false,
14394     up : false,
14395     down : false,
14396     tab : false,
14397     esc : false,
14398     pageUp : false,
14399     pageDown : false,
14400     del : false,
14401     home : false,
14402     end : false,
14403
14404     // quick lookup hash
14405     keyToHandler : {
14406         37 : "left",
14407         39 : "right",
14408         38 : "up",
14409         40 : "down",
14410         33 : "pageUp",
14411         34 : "pageDown",
14412         46 : "del",
14413         36 : "home",
14414         35 : "end",
14415         13 : "enter",
14416         27 : "esc",
14417         9  : "tab"
14418     },
14419
14420         /**
14421          * Enable this KeyNav
14422          */
14423         enable: function(){
14424                 if(this.disabled){
14425             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14426             // the EventObject will normalize Safari automatically
14427             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14428                 this.el.on("keydown", this.relay,  this);
14429             }else{
14430                 this.el.on("keydown", this.prepareEvent,  this);
14431                 this.el.on("keypress", this.relay,  this);
14432             }
14433                     this.disabled = false;
14434                 }
14435         },
14436
14437         /**
14438          * Disable this KeyNav
14439          */
14440         disable: function(){
14441                 if(!this.disabled){
14442                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14443                 this.el.un("keydown", this.relay);
14444             }else{
14445                 this.el.un("keydown", this.prepareEvent);
14446                 this.el.un("keypress", this.relay);
14447             }
14448                     this.disabled = true;
14449                 }
14450         }
14451 };/*
14452  * Based on:
14453  * Ext JS Library 1.1.1
14454  * Copyright(c) 2006-2007, Ext JS, LLC.
14455  *
14456  * Originally Released Under LGPL - original licence link has changed is not relivant.
14457  *
14458  * Fork - LGPL
14459  * <script type="text/javascript">
14460  */
14461
14462  
14463 /**
14464  * @class Roo.KeyMap
14465  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14466  * The constructor accepts the same config object as defined by {@link #addBinding}.
14467  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14468  * combination it will call the function with this signature (if the match is a multi-key
14469  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14470  * A KeyMap can also handle a string representation of keys.<br />
14471  * Usage:
14472  <pre><code>
14473 // map one key by key code
14474 var map = new Roo.KeyMap("my-element", {
14475     key: 13, // or Roo.EventObject.ENTER
14476     fn: myHandler,
14477     scope: myObject
14478 });
14479
14480 // map multiple keys to one action by string
14481 var map = new Roo.KeyMap("my-element", {
14482     key: "a\r\n\t",
14483     fn: myHandler,
14484     scope: myObject
14485 });
14486
14487 // map multiple keys to multiple actions by strings and array of codes
14488 var map = new Roo.KeyMap("my-element", [
14489     {
14490         key: [10,13],
14491         fn: function(){ alert("Return was pressed"); }
14492     }, {
14493         key: "abc",
14494         fn: function(){ alert('a, b or c was pressed'); }
14495     }, {
14496         key: "\t",
14497         ctrl:true,
14498         shift:true,
14499         fn: function(){ alert('Control + shift + tab was pressed.'); }
14500     }
14501 ]);
14502 </code></pre>
14503  * <b>Note: A KeyMap starts enabled</b>
14504  * @constructor
14505  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14506  * @param {Object} config The config (see {@link #addBinding})
14507  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14508  */
14509 Roo.KeyMap = function(el, config, eventName){
14510     this.el  = Roo.get(el);
14511     this.eventName = eventName || "keydown";
14512     this.bindings = [];
14513     if(config){
14514         this.addBinding(config);
14515     }
14516     this.enable();
14517 };
14518
14519 Roo.KeyMap.prototype = {
14520     /**
14521      * True to stop the event from bubbling and prevent the default browser action if the
14522      * key was handled by the KeyMap (defaults to false)
14523      * @type Boolean
14524      */
14525     stopEvent : false,
14526
14527     /**
14528      * Add a new binding to this KeyMap. The following config object properties are supported:
14529      * <pre>
14530 Property    Type             Description
14531 ----------  ---------------  ----------------------------------------------------------------------
14532 key         String/Array     A single keycode or an array of keycodes to handle
14533 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14534 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14535 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14536 fn          Function         The function to call when KeyMap finds the expected key combination
14537 scope       Object           The scope of the callback function
14538 </pre>
14539      *
14540      * Usage:
14541      * <pre><code>
14542 // Create a KeyMap
14543 var map = new Roo.KeyMap(document, {
14544     key: Roo.EventObject.ENTER,
14545     fn: handleKey,
14546     scope: this
14547 });
14548
14549 //Add a new binding to the existing KeyMap later
14550 map.addBinding({
14551     key: 'abc',
14552     shift: true,
14553     fn: handleKey,
14554     scope: this
14555 });
14556 </code></pre>
14557      * @param {Object/Array} config A single KeyMap config or an array of configs
14558      */
14559         addBinding : function(config){
14560         if(config instanceof Array){
14561             for(var i = 0, len = config.length; i < len; i++){
14562                 this.addBinding(config[i]);
14563             }
14564             return;
14565         }
14566         var keyCode = config.key,
14567             shift = config.shift, 
14568             ctrl = config.ctrl, 
14569             alt = config.alt,
14570             fn = config.fn,
14571             scope = config.scope;
14572         if(typeof keyCode == "string"){
14573             var ks = [];
14574             var keyString = keyCode.toUpperCase();
14575             for(var j = 0, len = keyString.length; j < len; j++){
14576                 ks.push(keyString.charCodeAt(j));
14577             }
14578             keyCode = ks;
14579         }
14580         var keyArray = keyCode instanceof Array;
14581         var handler = function(e){
14582             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14583                 var k = e.getKey();
14584                 if(keyArray){
14585                     for(var i = 0, len = keyCode.length; i < len; i++){
14586                         if(keyCode[i] == k){
14587                           if(this.stopEvent){
14588                               e.stopEvent();
14589                           }
14590                           fn.call(scope || window, k, e);
14591                           return;
14592                         }
14593                     }
14594                 }else{
14595                     if(k == keyCode){
14596                         if(this.stopEvent){
14597                            e.stopEvent();
14598                         }
14599                         fn.call(scope || window, k, e);
14600                     }
14601                 }
14602             }
14603         };
14604         this.bindings.push(handler);  
14605         },
14606
14607     /**
14608      * Shorthand for adding a single key listener
14609      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14610      * following options:
14611      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14612      * @param {Function} fn The function to call
14613      * @param {Object} scope (optional) The scope of the function
14614      */
14615     on : function(key, fn, scope){
14616         var keyCode, shift, ctrl, alt;
14617         if(typeof key == "object" && !(key instanceof Array)){
14618             keyCode = key.key;
14619             shift = key.shift;
14620             ctrl = key.ctrl;
14621             alt = key.alt;
14622         }else{
14623             keyCode = key;
14624         }
14625         this.addBinding({
14626             key: keyCode,
14627             shift: shift,
14628             ctrl: ctrl,
14629             alt: alt,
14630             fn: fn,
14631             scope: scope
14632         })
14633     },
14634
14635     // private
14636     handleKeyDown : function(e){
14637             if(this.enabled){ //just in case
14638             var b = this.bindings;
14639             for(var i = 0, len = b.length; i < len; i++){
14640                 b[i].call(this, e);
14641             }
14642             }
14643         },
14644         
14645         /**
14646          * Returns true if this KeyMap is enabled
14647          * @return {Boolean} 
14648          */
14649         isEnabled : function(){
14650             return this.enabled;  
14651         },
14652         
14653         /**
14654          * Enables this KeyMap
14655          */
14656         enable: function(){
14657                 if(!this.enabled){
14658                     this.el.on(this.eventName, this.handleKeyDown, this);
14659                     this.enabled = true;
14660                 }
14661         },
14662
14663         /**
14664          * Disable this KeyMap
14665          */
14666         disable: function(){
14667                 if(this.enabled){
14668                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14669                     this.enabled = false;
14670                 }
14671         }
14672 };/*
14673  * Based on:
14674  * Ext JS Library 1.1.1
14675  * Copyright(c) 2006-2007, Ext JS, LLC.
14676  *
14677  * Originally Released Under LGPL - original licence link has changed is not relivant.
14678  *
14679  * Fork - LGPL
14680  * <script type="text/javascript">
14681  */
14682
14683  
14684 /**
14685  * @class Roo.util.TextMetrics
14686  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14687  * wide, in pixels, a given block of text will be.
14688  * @singleton
14689  */
14690 Roo.util.TextMetrics = function(){
14691     var shared;
14692     return {
14693         /**
14694          * Measures the size of the specified text
14695          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14696          * that can affect the size of the rendered text
14697          * @param {String} text The text to measure
14698          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14699          * in order to accurately measure the text height
14700          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14701          */
14702         measure : function(el, text, fixedWidth){
14703             if(!shared){
14704                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14705             }
14706             shared.bind(el);
14707             shared.setFixedWidth(fixedWidth || 'auto');
14708             return shared.getSize(text);
14709         },
14710
14711         /**
14712          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14713          * the overhead of multiple calls to initialize the style properties on each measurement.
14714          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14715          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14716          * in order to accurately measure the text height
14717          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14718          */
14719         createInstance : function(el, fixedWidth){
14720             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14721         }
14722     };
14723 }();
14724
14725  
14726
14727 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14728     var ml = new Roo.Element(document.createElement('div'));
14729     document.body.appendChild(ml.dom);
14730     ml.position('absolute');
14731     ml.setLeftTop(-1000, -1000);
14732     ml.hide();
14733
14734     if(fixedWidth){
14735         ml.setWidth(fixedWidth);
14736     }
14737      
14738     var instance = {
14739         /**
14740          * Returns the size of the specified text based on the internal element's style and width properties
14741          * @memberOf Roo.util.TextMetrics.Instance#
14742          * @param {String} text The text to measure
14743          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14744          */
14745         getSize : function(text){
14746             ml.update(text);
14747             var s = ml.getSize();
14748             ml.update('');
14749             return s;
14750         },
14751
14752         /**
14753          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14754          * that can affect the size of the rendered text
14755          * @memberOf Roo.util.TextMetrics.Instance#
14756          * @param {String/HTMLElement} el The element, dom node or id
14757          */
14758         bind : function(el){
14759             ml.setStyle(
14760                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14761             );
14762         },
14763
14764         /**
14765          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14766          * to set a fixed width in order to accurately measure the text height.
14767          * @memberOf Roo.util.TextMetrics.Instance#
14768          * @param {Number} width The width to set on the element
14769          */
14770         setFixedWidth : function(width){
14771             ml.setWidth(width);
14772         },
14773
14774         /**
14775          * Returns the measured width of the specified text
14776          * @memberOf Roo.util.TextMetrics.Instance#
14777          * @param {String} text The text to measure
14778          * @return {Number} width The width in pixels
14779          */
14780         getWidth : function(text){
14781             ml.dom.style.width = 'auto';
14782             return this.getSize(text).width;
14783         },
14784
14785         /**
14786          * Returns the measured height of the specified text.  For multiline text, be sure to call
14787          * {@link #setFixedWidth} if necessary.
14788          * @memberOf Roo.util.TextMetrics.Instance#
14789          * @param {String} text The text to measure
14790          * @return {Number} height The height in pixels
14791          */
14792         getHeight : function(text){
14793             return this.getSize(text).height;
14794         }
14795     };
14796
14797     instance.bind(bindTo);
14798
14799     return instance;
14800 };
14801
14802 // backwards compat
14803 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14804  * Based on:
14805  * Ext JS Library 1.1.1
14806  * Copyright(c) 2006-2007, Ext JS, LLC.
14807  *
14808  * Originally Released Under LGPL - original licence link has changed is not relivant.
14809  *
14810  * Fork - LGPL
14811  * <script type="text/javascript">
14812  */
14813
14814 /**
14815  * @class Roo.state.Provider
14816  * Abstract base class for state provider implementations. This class provides methods
14817  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14818  * Provider interface.
14819  */
14820 Roo.state.Provider = function(){
14821     /**
14822      * @event statechange
14823      * Fires when a state change occurs.
14824      * @param {Provider} this This state provider
14825      * @param {String} key The state key which was changed
14826      * @param {String} value The encoded value for the state
14827      */
14828     this.addEvents({
14829         "statechange": true
14830     });
14831     this.state = {};
14832     Roo.state.Provider.superclass.constructor.call(this);
14833 };
14834 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14835     /**
14836      * Returns the current value for a key
14837      * @param {String} name The key name
14838      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14839      * @return {Mixed} The state data
14840      */
14841     get : function(name, defaultValue){
14842         return typeof this.state[name] == "undefined" ?
14843             defaultValue : this.state[name];
14844     },
14845     
14846     /**
14847      * Clears a value from the state
14848      * @param {String} name The key name
14849      */
14850     clear : function(name){
14851         delete this.state[name];
14852         this.fireEvent("statechange", this, name, null);
14853     },
14854     
14855     /**
14856      * Sets the value for a key
14857      * @param {String} name The key name
14858      * @param {Mixed} value The value to set
14859      */
14860     set : function(name, value){
14861         this.state[name] = value;
14862         this.fireEvent("statechange", this, name, value);
14863     },
14864     
14865     /**
14866      * Decodes a string previously encoded with {@link #encodeValue}.
14867      * @param {String} value The value to decode
14868      * @return {Mixed} The decoded value
14869      */
14870     decodeValue : function(cookie){
14871         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14872         var matches = re.exec(unescape(cookie));
14873         if(!matches || !matches[1]) {
14874             return; // non state cookie
14875         }
14876         var type = matches[1];
14877         var v = matches[2];
14878         switch(type){
14879             case "n":
14880                 return parseFloat(v);
14881             case "d":
14882                 return new Date(Date.parse(v));
14883             case "b":
14884                 return (v == "1");
14885             case "a":
14886                 var all = [];
14887                 var values = v.split("^");
14888                 for(var i = 0, len = values.length; i < len; i++){
14889                     all.push(this.decodeValue(values[i]));
14890                 }
14891                 return all;
14892            case "o":
14893                 var all = {};
14894                 var values = v.split("^");
14895                 for(var i = 0, len = values.length; i < len; i++){
14896                     var kv = values[i].split("=");
14897                     all[kv[0]] = this.decodeValue(kv[1]);
14898                 }
14899                 return all;
14900            default:
14901                 return v;
14902         }
14903     },
14904     
14905     /**
14906      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14907      * @param {Mixed} value The value to encode
14908      * @return {String} The encoded value
14909      */
14910     encodeValue : function(v){
14911         var enc;
14912         if(typeof v == "number"){
14913             enc = "n:" + v;
14914         }else if(typeof v == "boolean"){
14915             enc = "b:" + (v ? "1" : "0");
14916         }else if(v instanceof Date){
14917             enc = "d:" + v.toGMTString();
14918         }else if(v instanceof Array){
14919             var flat = "";
14920             for(var i = 0, len = v.length; i < len; i++){
14921                 flat += this.encodeValue(v[i]);
14922                 if(i != len-1) {
14923                     flat += "^";
14924                 }
14925             }
14926             enc = "a:" + flat;
14927         }else if(typeof v == "object"){
14928             var flat = "";
14929             for(var key in v){
14930                 if(typeof v[key] != "function"){
14931                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14932                 }
14933             }
14934             enc = "o:" + flat.substring(0, flat.length-1);
14935         }else{
14936             enc = "s:" + v;
14937         }
14938         return escape(enc);        
14939     }
14940 });
14941
14942 /*
14943  * Based on:
14944  * Ext JS Library 1.1.1
14945  * Copyright(c) 2006-2007, Ext JS, LLC.
14946  *
14947  * Originally Released Under LGPL - original licence link has changed is not relivant.
14948  *
14949  * Fork - LGPL
14950  * <script type="text/javascript">
14951  */
14952 /**
14953  * @class Roo.state.Manager
14954  * This is the global state manager. By default all components that are "state aware" check this class
14955  * for state information if you don't pass them a custom state provider. In order for this class
14956  * to be useful, it must be initialized with a provider when your application initializes.
14957  <pre><code>
14958 // in your initialization function
14959 init : function(){
14960    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14961    ...
14962    // supposed you have a {@link Roo.BorderLayout}
14963    var layout = new Roo.BorderLayout(...);
14964    layout.restoreState();
14965    // or a {Roo.BasicDialog}
14966    var dialog = new Roo.BasicDialog(...);
14967    dialog.restoreState();
14968  </code></pre>
14969  * @singleton
14970  */
14971 Roo.state.Manager = function(){
14972     var provider = new Roo.state.Provider();
14973     
14974     return {
14975         /**
14976          * Configures the default state provider for your application
14977          * @param {Provider} stateProvider The state provider to set
14978          */
14979         setProvider : function(stateProvider){
14980             provider = stateProvider;
14981         },
14982         
14983         /**
14984          * Returns the current value for a key
14985          * @param {String} name The key name
14986          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14987          * @return {Mixed} The state data
14988          */
14989         get : function(key, defaultValue){
14990             return provider.get(key, defaultValue);
14991         },
14992         
14993         /**
14994          * Sets the value for a key
14995          * @param {String} name The key name
14996          * @param {Mixed} value The state data
14997          */
14998          set : function(key, value){
14999             provider.set(key, value);
15000         },
15001         
15002         /**
15003          * Clears a value from the state
15004          * @param {String} name The key name
15005          */
15006         clear : function(key){
15007             provider.clear(key);
15008         },
15009         
15010         /**
15011          * Gets the currently configured state provider
15012          * @return {Provider} The state provider
15013          */
15014         getProvider : function(){
15015             return provider;
15016         }
15017     };
15018 }();
15019 /*
15020  * Based on:
15021  * Ext JS Library 1.1.1
15022  * Copyright(c) 2006-2007, Ext JS, LLC.
15023  *
15024  * Originally Released Under LGPL - original licence link has changed is not relivant.
15025  *
15026  * Fork - LGPL
15027  * <script type="text/javascript">
15028  */
15029 /**
15030  * @class Roo.state.CookieProvider
15031  * @extends Roo.state.Provider
15032  * The default Provider implementation which saves state via cookies.
15033  * <br />Usage:
15034  <pre><code>
15035    var cp = new Roo.state.CookieProvider({
15036        path: "/cgi-bin/",
15037        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15038        domain: "roojs.com"
15039    })
15040    Roo.state.Manager.setProvider(cp);
15041  </code></pre>
15042  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15043  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15044  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
15045  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15046  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15047  * domain the page is running on including the 'www' like 'www.roojs.com')
15048  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15049  * @constructor
15050  * Create a new CookieProvider
15051  * @param {Object} config The configuration object
15052  */
15053 Roo.state.CookieProvider = function(config){
15054     Roo.state.CookieProvider.superclass.constructor.call(this);
15055     this.path = "/";
15056     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15057     this.domain = null;
15058     this.secure = false;
15059     Roo.apply(this, config);
15060     this.state = this.readCookies();
15061 };
15062
15063 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15064     // private
15065     set : function(name, value){
15066         if(typeof value == "undefined" || value === null){
15067             this.clear(name);
15068             return;
15069         }
15070         this.setCookie(name, value);
15071         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15072     },
15073
15074     // private
15075     clear : function(name){
15076         this.clearCookie(name);
15077         Roo.state.CookieProvider.superclass.clear.call(this, name);
15078     },
15079
15080     // private
15081     readCookies : function(){
15082         var cookies = {};
15083         var c = document.cookie + ";";
15084         var re = /\s?(.*?)=(.*?);/g;
15085         var matches;
15086         while((matches = re.exec(c)) != null){
15087             var name = matches[1];
15088             var value = matches[2];
15089             if(name && name.substring(0,3) == "ys-"){
15090                 cookies[name.substr(3)] = this.decodeValue(value);
15091             }
15092         }
15093         return cookies;
15094     },
15095
15096     // private
15097     setCookie : function(name, value){
15098         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15099            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15100            ((this.path == null) ? "" : ("; path=" + this.path)) +
15101            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15102            ((this.secure == true) ? "; secure" : "");
15103     },
15104
15105     // private
15106     clearCookie : function(name){
15107         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15108            ((this.path == null) ? "" : ("; path=" + this.path)) +
15109            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15110            ((this.secure == true) ? "; secure" : "");
15111     }
15112 });/*
15113  * Based on:
15114  * Ext JS Library 1.1.1
15115  * Copyright(c) 2006-2007, Ext JS, LLC.
15116  *
15117  * Originally Released Under LGPL - original licence link has changed is not relivant.
15118  *
15119  * Fork - LGPL
15120  * <script type="text/javascript">
15121  */
15122  
15123
15124 /**
15125  * @class Roo.ComponentMgr
15126  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15127  * @singleton
15128  */
15129 Roo.ComponentMgr = function(){
15130     var all = new Roo.util.MixedCollection();
15131
15132     return {
15133         /**
15134          * Registers a component.
15135          * @param {Roo.Component} c The component
15136          */
15137         register : function(c){
15138             all.add(c);
15139         },
15140
15141         /**
15142          * Unregisters a component.
15143          * @param {Roo.Component} c The component
15144          */
15145         unregister : function(c){
15146             all.remove(c);
15147         },
15148
15149         /**
15150          * Returns a component by id
15151          * @param {String} id The component id
15152          */
15153         get : function(id){
15154             return all.get(id);
15155         },
15156
15157         /**
15158          * Registers a function that will be called when a specified component is added to ComponentMgr
15159          * @param {String} id The component id
15160          * @param {Funtction} fn The callback function
15161          * @param {Object} scope The scope of the callback
15162          */
15163         onAvailable : function(id, fn, scope){
15164             all.on("add", function(index, o){
15165                 if(o.id == id){
15166                     fn.call(scope || o, o);
15167                     all.un("add", fn, scope);
15168                 }
15169             });
15170         }
15171     };
15172 }();/*
15173  * Based on:
15174  * Ext JS Library 1.1.1
15175  * Copyright(c) 2006-2007, Ext JS, LLC.
15176  *
15177  * Originally Released Under LGPL - original licence link has changed is not relivant.
15178  *
15179  * Fork - LGPL
15180  * <script type="text/javascript">
15181  */
15182  
15183 /**
15184  * @class Roo.Component
15185  * @extends Roo.util.Observable
15186  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15187  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15188  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15189  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15190  * All visual components (widgets) that require rendering into a layout should subclass Component.
15191  * @constructor
15192  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15193  * 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
15194  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15195  */
15196 Roo.Component = function(config){
15197     config = config || {};
15198     if(config.tagName || config.dom || typeof config == "string"){ // element object
15199         config = {el: config, id: config.id || config};
15200     }
15201     this.initialConfig = config;
15202
15203     Roo.apply(this, config);
15204     this.addEvents({
15205         /**
15206          * @event disable
15207          * Fires after the component is disabled.
15208              * @param {Roo.Component} this
15209              */
15210         disable : true,
15211         /**
15212          * @event enable
15213          * Fires after the component is enabled.
15214              * @param {Roo.Component} this
15215              */
15216         enable : true,
15217         /**
15218          * @event beforeshow
15219          * Fires before the component is shown.  Return false to stop the show.
15220              * @param {Roo.Component} this
15221              */
15222         beforeshow : true,
15223         /**
15224          * @event show
15225          * Fires after the component is shown.
15226              * @param {Roo.Component} this
15227              */
15228         show : true,
15229         /**
15230          * @event beforehide
15231          * Fires before the component is hidden. Return false to stop the hide.
15232              * @param {Roo.Component} this
15233              */
15234         beforehide : true,
15235         /**
15236          * @event hide
15237          * Fires after the component is hidden.
15238              * @param {Roo.Component} this
15239              */
15240         hide : true,
15241         /**
15242          * @event beforerender
15243          * Fires before the component is rendered. Return false to stop the render.
15244              * @param {Roo.Component} this
15245              */
15246         beforerender : true,
15247         /**
15248          * @event render
15249          * Fires after the component is rendered.
15250              * @param {Roo.Component} this
15251              */
15252         render : true,
15253         /**
15254          * @event beforedestroy
15255          * Fires before the component is destroyed. Return false to stop the destroy.
15256              * @param {Roo.Component} this
15257              */
15258         beforedestroy : true,
15259         /**
15260          * @event destroy
15261          * Fires after the component is destroyed.
15262              * @param {Roo.Component} this
15263              */
15264         destroy : true
15265     });
15266     if(!this.id){
15267         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15268     }
15269     Roo.ComponentMgr.register(this);
15270     Roo.Component.superclass.constructor.call(this);
15271     this.initComponent();
15272     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15273         this.render(this.renderTo);
15274         delete this.renderTo;
15275     }
15276 };
15277
15278 /** @private */
15279 Roo.Component.AUTO_ID = 1000;
15280
15281 Roo.extend(Roo.Component, Roo.util.Observable, {
15282     /**
15283      * @scope Roo.Component.prototype
15284      * @type {Boolean}
15285      * true if this component is hidden. Read-only.
15286      */
15287     hidden : false,
15288     /**
15289      * @type {Boolean}
15290      * true if this component is disabled. Read-only.
15291      */
15292     disabled : false,
15293     /**
15294      * @type {Boolean}
15295      * true if this component has been rendered. Read-only.
15296      */
15297     rendered : false,
15298     
15299     /** @cfg {String} disableClass
15300      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15301      */
15302     disabledClass : "x-item-disabled",
15303         /** @cfg {Boolean} allowDomMove
15304          * Whether the component can move the Dom node when rendering (defaults to true).
15305          */
15306     allowDomMove : true,
15307     /** @cfg {String} hideMode (display|visibility)
15308      * How this component should hidden. Supported values are
15309      * "visibility" (css visibility), "offsets" (negative offset position) and
15310      * "display" (css display) - defaults to "display".
15311      */
15312     hideMode: 'display',
15313
15314     /** @private */
15315     ctype : "Roo.Component",
15316
15317     /**
15318      * @cfg {String} actionMode 
15319      * which property holds the element that used for  hide() / show() / disable() / enable()
15320      * default is 'el' 
15321      */
15322     actionMode : "el",
15323
15324     /** @private */
15325     getActionEl : function(){
15326         return this[this.actionMode];
15327     },
15328
15329     initComponent : Roo.emptyFn,
15330     /**
15331      * If this is a lazy rendering component, render it to its container element.
15332      * @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.
15333      */
15334     render : function(container, position){
15335         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15336             if(!container && this.el){
15337                 this.el = Roo.get(this.el);
15338                 container = this.el.dom.parentNode;
15339                 this.allowDomMove = false;
15340             }
15341             this.container = Roo.get(container);
15342             this.rendered = true;
15343             if(position !== undefined){
15344                 if(typeof position == 'number'){
15345                     position = this.container.dom.childNodes[position];
15346                 }else{
15347                     position = Roo.getDom(position);
15348                 }
15349             }
15350             this.onRender(this.container, position || null);
15351             if(this.cls){
15352                 this.el.addClass(this.cls);
15353                 delete this.cls;
15354             }
15355             if(this.style){
15356                 this.el.applyStyles(this.style);
15357                 delete this.style;
15358             }
15359             this.fireEvent("render", this);
15360             this.afterRender(this.container);
15361             if(this.hidden){
15362                 this.hide();
15363             }
15364             if(this.disabled){
15365                 this.disable();
15366             }
15367         }
15368         return this;
15369     },
15370
15371     /** @private */
15372     // default function is not really useful
15373     onRender : function(ct, position){
15374         if(this.el){
15375             this.el = Roo.get(this.el);
15376             if(this.allowDomMove !== false){
15377                 ct.dom.insertBefore(this.el.dom, position);
15378             }
15379         }
15380     },
15381
15382     /** @private */
15383     getAutoCreate : function(){
15384         var cfg = typeof this.autoCreate == "object" ?
15385                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15386         if(this.id && !cfg.id){
15387             cfg.id = this.id;
15388         }
15389         return cfg;
15390     },
15391
15392     /** @private */
15393     afterRender : Roo.emptyFn,
15394
15395     /**
15396      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15397      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15398      */
15399     destroy : function(){
15400         if(this.fireEvent("beforedestroy", this) !== false){
15401             this.purgeListeners();
15402             this.beforeDestroy();
15403             if(this.rendered){
15404                 this.el.removeAllListeners();
15405                 this.el.remove();
15406                 if(this.actionMode == "container"){
15407                     this.container.remove();
15408                 }
15409             }
15410             this.onDestroy();
15411             Roo.ComponentMgr.unregister(this);
15412             this.fireEvent("destroy", this);
15413         }
15414     },
15415
15416         /** @private */
15417     beforeDestroy : function(){
15418
15419     },
15420
15421         /** @private */
15422         onDestroy : function(){
15423
15424     },
15425
15426     /**
15427      * Returns the underlying {@link Roo.Element}.
15428      * @return {Roo.Element} The element
15429      */
15430     getEl : function(){
15431         return this.el;
15432     },
15433
15434     /**
15435      * Returns the id of this component.
15436      * @return {String}
15437      */
15438     getId : function(){
15439         return this.id;
15440     },
15441
15442     /**
15443      * Try to focus this component.
15444      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15445      * @return {Roo.Component} this
15446      */
15447     focus : function(selectText){
15448         if(this.rendered){
15449             this.el.focus();
15450             if(selectText === true){
15451                 this.el.dom.select();
15452             }
15453         }
15454         return this;
15455     },
15456
15457     /** @private */
15458     blur : function(){
15459         if(this.rendered){
15460             this.el.blur();
15461         }
15462         return this;
15463     },
15464
15465     /**
15466      * Disable this component.
15467      * @return {Roo.Component} this
15468      */
15469     disable : function(){
15470         if(this.rendered){
15471             this.onDisable();
15472         }
15473         this.disabled = true;
15474         this.fireEvent("disable", this);
15475         return this;
15476     },
15477
15478         // private
15479     onDisable : function(){
15480         this.getActionEl().addClass(this.disabledClass);
15481         this.el.dom.disabled = true;
15482     },
15483
15484     /**
15485      * Enable this component.
15486      * @return {Roo.Component} this
15487      */
15488     enable : function(){
15489         if(this.rendered){
15490             this.onEnable();
15491         }
15492         this.disabled = false;
15493         this.fireEvent("enable", this);
15494         return this;
15495     },
15496
15497         // private
15498     onEnable : function(){
15499         this.getActionEl().removeClass(this.disabledClass);
15500         this.el.dom.disabled = false;
15501     },
15502
15503     /**
15504      * Convenience function for setting disabled/enabled by boolean.
15505      * @param {Boolean} disabled
15506      */
15507     setDisabled : function(disabled){
15508         this[disabled ? "disable" : "enable"]();
15509     },
15510
15511     /**
15512      * Show this component.
15513      * @return {Roo.Component} this
15514      */
15515     show: function(){
15516         if(this.fireEvent("beforeshow", this) !== false){
15517             this.hidden = false;
15518             if(this.rendered){
15519                 this.onShow();
15520             }
15521             this.fireEvent("show", this);
15522         }
15523         return this;
15524     },
15525
15526     // private
15527     onShow : function(){
15528         var ae = this.getActionEl();
15529         if(this.hideMode == 'visibility'){
15530             ae.dom.style.visibility = "visible";
15531         }else if(this.hideMode == 'offsets'){
15532             ae.removeClass('x-hidden');
15533         }else{
15534             ae.dom.style.display = "";
15535         }
15536     },
15537
15538     /**
15539      * Hide this component.
15540      * @return {Roo.Component} this
15541      */
15542     hide: function(){
15543         if(this.fireEvent("beforehide", this) !== false){
15544             this.hidden = true;
15545             if(this.rendered){
15546                 this.onHide();
15547             }
15548             this.fireEvent("hide", this);
15549         }
15550         return this;
15551     },
15552
15553     // private
15554     onHide : function(){
15555         var ae = this.getActionEl();
15556         if(this.hideMode == 'visibility'){
15557             ae.dom.style.visibility = "hidden";
15558         }else if(this.hideMode == 'offsets'){
15559             ae.addClass('x-hidden');
15560         }else{
15561             ae.dom.style.display = "none";
15562         }
15563     },
15564
15565     /**
15566      * Convenience function to hide or show this component by boolean.
15567      * @param {Boolean} visible True to show, false to hide
15568      * @return {Roo.Component} this
15569      */
15570     setVisible: function(visible){
15571         if(visible) {
15572             this.show();
15573         }else{
15574             this.hide();
15575         }
15576         return this;
15577     },
15578
15579     /**
15580      * Returns true if this component is visible.
15581      */
15582     isVisible : function(){
15583         return this.getActionEl().isVisible();
15584     },
15585
15586     cloneConfig : function(overrides){
15587         overrides = overrides || {};
15588         var id = overrides.id || Roo.id();
15589         var cfg = Roo.applyIf(overrides, this.initialConfig);
15590         cfg.id = id; // prevent dup id
15591         return new this.constructor(cfg);
15592     }
15593 });/*
15594  * Based on:
15595  * Ext JS Library 1.1.1
15596  * Copyright(c) 2006-2007, Ext JS, LLC.
15597  *
15598  * Originally Released Under LGPL - original licence link has changed is not relivant.
15599  *
15600  * Fork - LGPL
15601  * <script type="text/javascript">
15602  */
15603
15604 /**
15605  * @class Roo.BoxComponent
15606  * @extends Roo.Component
15607  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15608  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15609  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15610  * layout containers.
15611  * @constructor
15612  * @param {Roo.Element/String/Object} config The configuration options.
15613  */
15614 Roo.BoxComponent = function(config){
15615     Roo.Component.call(this, config);
15616     this.addEvents({
15617         /**
15618          * @event resize
15619          * Fires after the component is resized.
15620              * @param {Roo.Component} this
15621              * @param {Number} adjWidth The box-adjusted width that was set
15622              * @param {Number} adjHeight The box-adjusted height that was set
15623              * @param {Number} rawWidth The width that was originally specified
15624              * @param {Number} rawHeight The height that was originally specified
15625              */
15626         resize : true,
15627         /**
15628          * @event move
15629          * Fires after the component is moved.
15630              * @param {Roo.Component} this
15631              * @param {Number} x The new x position
15632              * @param {Number} y The new y position
15633              */
15634         move : true
15635     });
15636 };
15637
15638 Roo.extend(Roo.BoxComponent, Roo.Component, {
15639     // private, set in afterRender to signify that the component has been rendered
15640     boxReady : false,
15641     // private, used to defer height settings to subclasses
15642     deferHeight: false,
15643     /** @cfg {Number} width
15644      * width (optional) size of component
15645      */
15646      /** @cfg {Number} height
15647      * height (optional) size of component
15648      */
15649      
15650     /**
15651      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15652      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15653      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15654      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15655      * @return {Roo.BoxComponent} this
15656      */
15657     setSize : function(w, h){
15658         // support for standard size objects
15659         if(typeof w == 'object'){
15660             h = w.height;
15661             w = w.width;
15662         }
15663         // not rendered
15664         if(!this.boxReady){
15665             this.width = w;
15666             this.height = h;
15667             return this;
15668         }
15669
15670         // prevent recalcs when not needed
15671         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15672             return this;
15673         }
15674         this.lastSize = {width: w, height: h};
15675
15676         var adj = this.adjustSize(w, h);
15677         var aw = adj.width, ah = adj.height;
15678         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15679             var rz = this.getResizeEl();
15680             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15681                 rz.setSize(aw, ah);
15682             }else if(!this.deferHeight && ah !== undefined){
15683                 rz.setHeight(ah);
15684             }else if(aw !== undefined){
15685                 rz.setWidth(aw);
15686             }
15687             this.onResize(aw, ah, w, h);
15688             this.fireEvent('resize', this, aw, ah, w, h);
15689         }
15690         return this;
15691     },
15692
15693     /**
15694      * Gets the current size of the component's underlying element.
15695      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15696      */
15697     getSize : function(){
15698         return this.el.getSize();
15699     },
15700
15701     /**
15702      * Gets the current XY position of the component's underlying element.
15703      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15704      * @return {Array} The XY position of the element (e.g., [100, 200])
15705      */
15706     getPosition : function(local){
15707         if(local === true){
15708             return [this.el.getLeft(true), this.el.getTop(true)];
15709         }
15710         return this.xy || this.el.getXY();
15711     },
15712
15713     /**
15714      * Gets the current box measurements of the component's underlying element.
15715      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15716      * @returns {Object} box An object in the format {x, y, width, height}
15717      */
15718     getBox : function(local){
15719         var s = this.el.getSize();
15720         if(local){
15721             s.x = this.el.getLeft(true);
15722             s.y = this.el.getTop(true);
15723         }else{
15724             var xy = this.xy || this.el.getXY();
15725             s.x = xy[0];
15726             s.y = xy[1];
15727         }
15728         return s;
15729     },
15730
15731     /**
15732      * Sets the current box measurements of the component's underlying element.
15733      * @param {Object} box An object in the format {x, y, width, height}
15734      * @returns {Roo.BoxComponent} this
15735      */
15736     updateBox : function(box){
15737         this.setSize(box.width, box.height);
15738         this.setPagePosition(box.x, box.y);
15739         return this;
15740     },
15741
15742     // protected
15743     getResizeEl : function(){
15744         return this.resizeEl || this.el;
15745     },
15746
15747     // protected
15748     getPositionEl : function(){
15749         return this.positionEl || this.el;
15750     },
15751
15752     /**
15753      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15754      * This method fires the move event.
15755      * @param {Number} left The new left
15756      * @param {Number} top The new top
15757      * @returns {Roo.BoxComponent} this
15758      */
15759     setPosition : function(x, y){
15760         this.x = x;
15761         this.y = y;
15762         if(!this.boxReady){
15763             return this;
15764         }
15765         var adj = this.adjustPosition(x, y);
15766         var ax = adj.x, ay = adj.y;
15767
15768         var el = this.getPositionEl();
15769         if(ax !== undefined || ay !== undefined){
15770             if(ax !== undefined && ay !== undefined){
15771                 el.setLeftTop(ax, ay);
15772             }else if(ax !== undefined){
15773                 el.setLeft(ax);
15774             }else if(ay !== undefined){
15775                 el.setTop(ay);
15776             }
15777             this.onPosition(ax, ay);
15778             this.fireEvent('move', this, ax, ay);
15779         }
15780         return this;
15781     },
15782
15783     /**
15784      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15785      * This method fires the move event.
15786      * @param {Number} x The new x position
15787      * @param {Number} y The new y position
15788      * @returns {Roo.BoxComponent} this
15789      */
15790     setPagePosition : function(x, y){
15791         this.pageX = x;
15792         this.pageY = y;
15793         if(!this.boxReady){
15794             return;
15795         }
15796         if(x === undefined || y === undefined){ // cannot translate undefined points
15797             return;
15798         }
15799         var p = this.el.translatePoints(x, y);
15800         this.setPosition(p.left, p.top);
15801         return this;
15802     },
15803
15804     // private
15805     onRender : function(ct, position){
15806         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15807         if(this.resizeEl){
15808             this.resizeEl = Roo.get(this.resizeEl);
15809         }
15810         if(this.positionEl){
15811             this.positionEl = Roo.get(this.positionEl);
15812         }
15813     },
15814
15815     // private
15816     afterRender : function(){
15817         Roo.BoxComponent.superclass.afterRender.call(this);
15818         this.boxReady = true;
15819         this.setSize(this.width, this.height);
15820         if(this.x || this.y){
15821             this.setPosition(this.x, this.y);
15822         }
15823         if(this.pageX || this.pageY){
15824             this.setPagePosition(this.pageX, this.pageY);
15825         }
15826     },
15827
15828     /**
15829      * Force the component's size to recalculate based on the underlying element's current height and width.
15830      * @returns {Roo.BoxComponent} this
15831      */
15832     syncSize : function(){
15833         delete this.lastSize;
15834         this.setSize(this.el.getWidth(), this.el.getHeight());
15835         return this;
15836     },
15837
15838     /**
15839      * Called after the component is resized, this method is empty by default but can be implemented by any
15840      * subclass that needs to perform custom logic after a resize occurs.
15841      * @param {Number} adjWidth The box-adjusted width that was set
15842      * @param {Number} adjHeight The box-adjusted height that was set
15843      * @param {Number} rawWidth The width that was originally specified
15844      * @param {Number} rawHeight The height that was originally specified
15845      */
15846     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15847
15848     },
15849
15850     /**
15851      * Called after the component is moved, this method is empty by default but can be implemented by any
15852      * subclass that needs to perform custom logic after a move occurs.
15853      * @param {Number} x The new x position
15854      * @param {Number} y The new y position
15855      */
15856     onPosition : function(x, y){
15857
15858     },
15859
15860     // private
15861     adjustSize : function(w, h){
15862         if(this.autoWidth){
15863             w = 'auto';
15864         }
15865         if(this.autoHeight){
15866             h = 'auto';
15867         }
15868         return {width : w, height: h};
15869     },
15870
15871     // private
15872     adjustPosition : function(x, y){
15873         return {x : x, y: y};
15874     }
15875 });/*
15876  * Original code for Roojs - LGPL
15877  * <script type="text/javascript">
15878  */
15879  
15880 /**
15881  * @class Roo.XComponent
15882  * A delayed Element creator...
15883  * Or a way to group chunks of interface together.
15884  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15885  *  used in conjunction with XComponent.build() it will create an instance of each element,
15886  *  then call addxtype() to build the User interface.
15887  * 
15888  * Mypart.xyx = new Roo.XComponent({
15889
15890     parent : 'Mypart.xyz', // empty == document.element.!!
15891     order : '001',
15892     name : 'xxxx'
15893     region : 'xxxx'
15894     disabled : function() {} 
15895      
15896     tree : function() { // return an tree of xtype declared components
15897         var MODULE = this;
15898         return 
15899         {
15900             xtype : 'NestedLayoutPanel',
15901             // technicall
15902         }
15903      ]
15904  *})
15905  *
15906  *
15907  * It can be used to build a big heiracy, with parent etc.
15908  * or you can just use this to render a single compoent to a dom element
15909  * MYPART.render(Roo.Element | String(id) | dom_element )
15910  *
15911  *
15912  * Usage patterns.
15913  *
15914  * Classic Roo
15915  *
15916  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15917  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15918  *
15919  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15920  *
15921  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15922  * - if mulitple topModules exist, the last one is defined as the top module.
15923  *
15924  * Embeded Roo
15925  * 
15926  * When the top level or multiple modules are to embedded into a existing HTML page,
15927  * the parent element can container '#id' of the element where the module will be drawn.
15928  *
15929  * Bootstrap Roo
15930  *
15931  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15932  * it relies more on a include mechanism, where sub modules are included into an outer page.
15933  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15934  * 
15935  * Bootstrap Roo Included elements
15936  *
15937  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15938  * hence confusing the component builder as it thinks there are multiple top level elements. 
15939  *
15940  * 
15941  * 
15942  * @extends Roo.util.Observable
15943  * @constructor
15944  * @param cfg {Object} configuration of component
15945  * 
15946  */
15947 Roo.XComponent = function(cfg) {
15948     Roo.apply(this, cfg);
15949     this.addEvents({ 
15950         /**
15951              * @event built
15952              * Fires when this the componnt is built
15953              * @param {Roo.XComponent} c the component
15954              */
15955         'built' : true
15956         
15957     });
15958     this.region = this.region || 'center'; // default..
15959     Roo.XComponent.register(this);
15960     this.modules = false;
15961     this.el = false; // where the layout goes..
15962     
15963     
15964 }
15965 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15966     /**
15967      * @property el
15968      * The created element (with Roo.factory())
15969      * @type {Roo.Layout}
15970      */
15971     el  : false,
15972     
15973     /**
15974      * @property el
15975      * for BC  - use el in new code
15976      * @type {Roo.Layout}
15977      */
15978     panel : false,
15979     
15980     /**
15981      * @property layout
15982      * for BC  - use el in new code
15983      * @type {Roo.Layout}
15984      */
15985     layout : false,
15986     
15987      /**
15988      * @cfg {Function|boolean} disabled
15989      * If this module is disabled by some rule, return true from the funtion
15990      */
15991     disabled : false,
15992     
15993     /**
15994      * @cfg {String} parent 
15995      * Name of parent element which it get xtype added to..
15996      */
15997     parent: false,
15998     
15999     /**
16000      * @cfg {String} order
16001      * Used to set the order in which elements are created (usefull for multiple tabs)
16002      */
16003     
16004     order : false,
16005     /**
16006      * @cfg {String} name
16007      * String to display while loading.
16008      */
16009     name : false,
16010     /**
16011      * @cfg {String} region
16012      * Region to render component to (defaults to center)
16013      */
16014     region : 'center',
16015     
16016     /**
16017      * @cfg {Array} items
16018      * A single item array - the first element is the root of the tree..
16019      * It's done this way to stay compatible with the Xtype system...
16020      */
16021     items : false,
16022     
16023     /**
16024      * @property _tree
16025      * The method that retuns the tree of parts that make up this compoennt 
16026      * @type {function}
16027      */
16028     _tree  : false,
16029     
16030      /**
16031      * render
16032      * render element to dom or tree
16033      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16034      */
16035     
16036     render : function(el)
16037     {
16038         
16039         el = el || false;
16040         var hp = this.parent ? 1 : 0;
16041         Roo.debug &&  Roo.log(this);
16042         
16043         var tree = this._tree ? this._tree() : this.tree();
16044
16045         
16046         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16047             // if parent is a '#.....' string, then let's use that..
16048             var ename = this.parent.substr(1);
16049             this.parent = false;
16050             Roo.debug && Roo.log(ename);
16051             switch (ename) {
16052                 case 'bootstrap-body':
16053                     if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
16054                         // this is the BorderLayout standard?
16055                        this.parent = { el : true };
16056                        break;
16057                     }
16058                     if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
16059                         // need to insert stuff...
16060                         this.parent =  {
16061                              el : new Roo.bootstrap.layout.Border({
16062                                  el : document.body, 
16063                      
16064                                  center: {
16065                                     titlebar: false,
16066                                     autoScroll:false,
16067                                     closeOnTab: true,
16068                                     tabPosition: 'top',
16069                                       //resizeTabs: true,
16070                                     alwaysShowTabs: true,
16071                                     hideTabs: false
16072                                      //minTabWidth: 140
16073                                  }
16074                              })
16075                         
16076                          };
16077                          break;
16078                     }
16079                          
16080                     if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16081                         this.parent = { el :  new  Roo.bootstrap.Body() };
16082                         Roo.debug && Roo.log("setting el to doc body");
16083                          
16084                     } else {
16085                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16086                     }
16087                     break;
16088                 case 'bootstrap':
16089                     this.parent = { el : true};
16090                     // fall through
16091                 default:
16092                     el = Roo.get(ename);
16093                     if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16094                         this.parent = { el : true};
16095                     }
16096                     
16097                     break;
16098             }
16099                 
16100             
16101             if (!el && !this.parent) {
16102                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16103                 return;
16104             }
16105         }
16106         
16107         Roo.debug && Roo.log("EL:");
16108         Roo.debug && Roo.log(el);
16109         Roo.debug && Roo.log("this.parent.el:");
16110         Roo.debug && Roo.log(this.parent.el);
16111         
16112
16113         // altertive root elements ??? - we need a better way to indicate these.
16114         var is_alt = Roo.XComponent.is_alt ||
16115                     (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16116                     (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16117                     (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16118         
16119         
16120         
16121         if (!this.parent && is_alt) {
16122             //el = Roo.get(document.body);
16123             this.parent = { el : true };
16124         }
16125             
16126             
16127         
16128         if (!this.parent) {
16129             
16130             Roo.debug && Roo.log("no parent - creating one");
16131             
16132             el = el ? Roo.get(el) : false;      
16133             
16134             if (typeof(Roo.BorderLayout) == 'undefined' ) {
16135                 
16136                 this.parent =  {
16137                     el : new Roo.bootstrap.layout.Border({
16138                         el: el || document.body,
16139                     
16140                         center: {
16141                             titlebar: false,
16142                             autoScroll:false,
16143                             closeOnTab: true,
16144                             tabPosition: 'top',
16145                              //resizeTabs: true,
16146                             alwaysShowTabs: false,
16147                             hideTabs: true,
16148                             minTabWidth: 140,
16149                             overflow: 'visible'
16150                          }
16151                      })
16152                 };
16153             } else {
16154             
16155                 // it's a top level one..
16156                 this.parent =  {
16157                     el : new Roo.BorderLayout(el || document.body, {
16158                         center: {
16159                             titlebar: false,
16160                             autoScroll:false,
16161                             closeOnTab: true,
16162                             tabPosition: 'top',
16163                              //resizeTabs: true,
16164                             alwaysShowTabs: el && hp? false :  true,
16165                             hideTabs: el || !hp ? true :  false,
16166                             minTabWidth: 140
16167                          }
16168                     })
16169                 };
16170             }
16171         }
16172         
16173         if (!this.parent.el) {
16174                 // probably an old style ctor, which has been disabled.
16175                 return;
16176
16177         }
16178                 // The 'tree' method is  '_tree now' 
16179             
16180         tree.region = tree.region || this.region;
16181         var is_body = false;
16182         if (this.parent.el === true) {
16183             // bootstrap... - body..
16184             if (el) {
16185                 tree.el = el;
16186             }
16187             this.parent.el = Roo.factory(tree);
16188             is_body = true;
16189         }
16190         
16191         this.el = this.parent.el.addxtype(tree, undefined, is_body);
16192         this.fireEvent('built', this);
16193         
16194         this.panel = this.el;
16195         this.layout = this.panel.layout;
16196         this.parentLayout = this.parent.layout  || false;  
16197          
16198     }
16199     
16200 });
16201
16202 Roo.apply(Roo.XComponent, {
16203     /**
16204      * @property  hideProgress
16205      * true to disable the building progress bar.. usefull on single page renders.
16206      * @type Boolean
16207      */
16208     hideProgress : false,
16209     /**
16210      * @property  buildCompleted
16211      * True when the builder has completed building the interface.
16212      * @type Boolean
16213      */
16214     buildCompleted : false,
16215      
16216     /**
16217      * @property  topModule
16218      * the upper most module - uses document.element as it's constructor.
16219      * @type Object
16220      */
16221      
16222     topModule  : false,
16223       
16224     /**
16225      * @property  modules
16226      * array of modules to be created by registration system.
16227      * @type {Array} of Roo.XComponent
16228      */
16229     
16230     modules : [],
16231     /**
16232      * @property  elmodules
16233      * array of modules to be created by which use #ID 
16234      * @type {Array} of Roo.XComponent
16235      */
16236      
16237     elmodules : [],
16238
16239      /**
16240      * @property  is_alt
16241      * Is an alternative Root - normally used by bootstrap or other systems,
16242      *    where the top element in the tree can wrap 'body' 
16243      * @type {boolean}  (default false)
16244      */
16245      
16246     is_alt : false,
16247     /**
16248      * @property  build_from_html
16249      * Build elements from html - used by bootstrap HTML stuff 
16250      *    - this is cleared after build is completed
16251      * @type {boolean}    (default false)
16252      */
16253      
16254     build_from_html : false,
16255     /**
16256      * Register components to be built later.
16257      *
16258      * This solves the following issues
16259      * - Building is not done on page load, but after an authentication process has occured.
16260      * - Interface elements are registered on page load
16261      * - Parent Interface elements may not be loaded before child, so this handles that..
16262      * 
16263      *
16264      * example:
16265      * 
16266      * MyApp.register({
16267           order : '000001',
16268           module : 'Pman.Tab.projectMgr',
16269           region : 'center',
16270           parent : 'Pman.layout',
16271           disabled : false,  // or use a function..
16272         })
16273      
16274      * * @param {Object} details about module
16275      */
16276     register : function(obj) {
16277                 
16278         Roo.XComponent.event.fireEvent('register', obj);
16279         switch(typeof(obj.disabled) ) {
16280                 
16281             case 'undefined':
16282                 break;
16283             
16284             case 'function':
16285                 if ( obj.disabled() ) {
16286                         return;
16287                 }
16288                 break;
16289             
16290             default:
16291                 if (obj.disabled) {
16292                         return;
16293                 }
16294                 break;
16295         }
16296                 
16297         this.modules.push(obj);
16298          
16299     },
16300     /**
16301      * convert a string to an object..
16302      * eg. 'AAA.BBB' -> finds AAA.BBB
16303
16304      */
16305     
16306     toObject : function(str)
16307     {
16308         if (!str || typeof(str) == 'object') {
16309             return str;
16310         }
16311         if (str.substring(0,1) == '#') {
16312             return str;
16313         }
16314
16315         var ar = str.split('.');
16316         var rt, o;
16317         rt = ar.shift();
16318             /** eval:var:o */
16319         try {
16320             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16321         } catch (e) {
16322             throw "Module not found : " + str;
16323         }
16324         
16325         if (o === false) {
16326             throw "Module not found : " + str;
16327         }
16328         Roo.each(ar, function(e) {
16329             if (typeof(o[e]) == 'undefined') {
16330                 throw "Module not found : " + str;
16331             }
16332             o = o[e];
16333         });
16334         
16335         return o;
16336         
16337     },
16338     
16339     
16340     /**
16341      * move modules into their correct place in the tree..
16342      * 
16343      */
16344     preBuild : function ()
16345     {
16346         var _t = this;
16347         Roo.each(this.modules , function (obj)
16348         {
16349             Roo.XComponent.event.fireEvent('beforebuild', obj);
16350             
16351             var opar = obj.parent;
16352             try { 
16353                 obj.parent = this.toObject(opar);
16354             } catch(e) {
16355                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16356                 return;
16357             }
16358             
16359             if (!obj.parent) {
16360                 Roo.debug && Roo.log("GOT top level module");
16361                 Roo.debug && Roo.log(obj);
16362                 obj.modules = new Roo.util.MixedCollection(false, 
16363                     function(o) { return o.order + '' }
16364                 );
16365                 this.topModule = obj;
16366                 return;
16367             }
16368                         // parent is a string (usually a dom element name..)
16369             if (typeof(obj.parent) == 'string') {
16370                 this.elmodules.push(obj);
16371                 return;
16372             }
16373             if (obj.parent.constructor != Roo.XComponent) {
16374                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16375             }
16376             if (!obj.parent.modules) {
16377                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16378                     function(o) { return o.order + '' }
16379                 );
16380             }
16381             if (obj.parent.disabled) {
16382                 obj.disabled = true;
16383             }
16384             obj.parent.modules.add(obj);
16385         }, this);
16386     },
16387     
16388      /**
16389      * make a list of modules to build.
16390      * @return {Array} list of modules. 
16391      */ 
16392     
16393     buildOrder : function()
16394     {
16395         var _this = this;
16396         var cmp = function(a,b) {   
16397             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16398         };
16399         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16400             throw "No top level modules to build";
16401         }
16402         
16403         // make a flat list in order of modules to build.
16404         var mods = this.topModule ? [ this.topModule ] : [];
16405                 
16406         
16407         // elmodules (is a list of DOM based modules )
16408         Roo.each(this.elmodules, function(e) {
16409             mods.push(e);
16410             if (!this.topModule &&
16411                 typeof(e.parent) == 'string' &&
16412                 e.parent.substring(0,1) == '#' &&
16413                 Roo.get(e.parent.substr(1))
16414                ) {
16415                 
16416                 _this.topModule = e;
16417             }
16418             
16419         });
16420
16421         
16422         // add modules to their parents..
16423         var addMod = function(m) {
16424             Roo.debug && Roo.log("build Order: add: " + m.name);
16425                 
16426             mods.push(m);
16427             if (m.modules && !m.disabled) {
16428                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16429                 m.modules.keySort('ASC',  cmp );
16430                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16431     
16432                 m.modules.each(addMod);
16433             } else {
16434                 Roo.debug && Roo.log("build Order: no child modules");
16435             }
16436             // not sure if this is used any more..
16437             if (m.finalize) {
16438                 m.finalize.name = m.name + " (clean up) ";
16439                 mods.push(m.finalize);
16440             }
16441             
16442         }
16443         if (this.topModule && this.topModule.modules) { 
16444             this.topModule.modules.keySort('ASC',  cmp );
16445             this.topModule.modules.each(addMod);
16446         } 
16447         return mods;
16448     },
16449     
16450      /**
16451      * Build the registered modules.
16452      * @param {Object} parent element.
16453      * @param {Function} optional method to call after module has been added.
16454      * 
16455      */ 
16456    
16457     build : function(opts) 
16458     {
16459         
16460         if (typeof(opts) != 'undefined') {
16461             Roo.apply(this,opts);
16462         }
16463         
16464         this.preBuild();
16465         var mods = this.buildOrder();
16466       
16467         //this.allmods = mods;
16468         //Roo.debug && Roo.log(mods);
16469         //return;
16470         if (!mods.length) { // should not happen
16471             throw "NO modules!!!";
16472         }
16473         
16474         
16475         var msg = "Building Interface...";
16476         // flash it up as modal - so we store the mask!?
16477         if (!this.hideProgress && Roo.MessageBox) {
16478             Roo.MessageBox.show({ title: 'loading' });
16479             Roo.MessageBox.show({
16480                title: "Please wait...",
16481                msg: msg,
16482                width:450,
16483                progress:true,
16484                closable:false,
16485                modal: false
16486               
16487             });
16488         }
16489         var total = mods.length;
16490         
16491         var _this = this;
16492         var progressRun = function() {
16493             if (!mods.length) {
16494                 Roo.debug && Roo.log('hide?');
16495                 if (!this.hideProgress && Roo.MessageBox) {
16496                     Roo.MessageBox.hide();
16497                 }
16498                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16499                 
16500                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16501                 
16502                 // THE END...
16503                 return false;   
16504             }
16505             
16506             var m = mods.shift();
16507             
16508             
16509             Roo.debug && Roo.log(m);
16510             // not sure if this is supported any more.. - modules that are are just function
16511             if (typeof(m) == 'function') { 
16512                 m.call(this);
16513                 return progressRun.defer(10, _this);
16514             } 
16515             
16516             
16517             msg = "Building Interface " + (total  - mods.length) + 
16518                     " of " + total + 
16519                     (m.name ? (' - ' + m.name) : '');
16520                         Roo.debug && Roo.log(msg);
16521             if (!this.hideProgress &&  Roo.MessageBox) { 
16522                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16523             }
16524             
16525          
16526             // is the module disabled?
16527             var disabled = (typeof(m.disabled) == 'function') ?
16528                 m.disabled.call(m.module.disabled) : m.disabled;    
16529             
16530             
16531             if (disabled) {
16532                 return progressRun(); // we do not update the display!
16533             }
16534             
16535             // now build 
16536             
16537                         
16538                         
16539             m.render();
16540             // it's 10 on top level, and 1 on others??? why...
16541             return progressRun.defer(10, _this);
16542              
16543         }
16544         progressRun.defer(1, _this);
16545      
16546         
16547         
16548     },
16549         
16550         
16551         /**
16552          * Event Object.
16553          *
16554          *
16555          */
16556         event: false, 
16557     /**
16558          * wrapper for event.on - aliased later..  
16559          * Typically use to register a event handler for register:
16560          *
16561          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16562          *
16563          */
16564     on : false
16565    
16566     
16567     
16568 });
16569
16570 Roo.XComponent.event = new Roo.util.Observable({
16571                 events : { 
16572                         /**
16573                          * @event register
16574                          * Fires when an Component is registered,
16575                          * set the disable property on the Component to stop registration.
16576                          * @param {Roo.XComponent} c the component being registerd.
16577                          * 
16578                          */
16579                         'register' : true,
16580             /**
16581                          * @event beforebuild
16582                          * Fires before each Component is built
16583                          * can be used to apply permissions.
16584                          * @param {Roo.XComponent} c the component being registerd.
16585                          * 
16586                          */
16587                         'beforebuild' : true,
16588                         /**
16589                          * @event buildcomplete
16590                          * Fires on the top level element when all elements have been built
16591                          * @param {Roo.XComponent} the top level component.
16592                          */
16593                         'buildcomplete' : true
16594                         
16595                 }
16596 });
16597
16598 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16599  //
16600  /**
16601  * marked - a markdown parser
16602  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16603  * https://github.com/chjj/marked
16604  */
16605
16606
16607 /**
16608  *
16609  * Roo.Markdown - is a very crude wrapper around marked..
16610  *
16611  * usage:
16612  * 
16613  * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16614  * 
16615  * Note: move the sample code to the bottom of this
16616  * file before uncommenting it.
16617  *
16618  */
16619
16620 Roo.Markdown = {};
16621 Roo.Markdown.toHtml = function(text) {
16622     
16623     var c = new Roo.Markdown.marked.setOptions({
16624             renderer: new Roo.Markdown.marked.Renderer(),
16625             gfm: true,
16626             tables: true,
16627             breaks: false,
16628             pedantic: false,
16629             sanitize: false,
16630             smartLists: true,
16631             smartypants: false
16632           });
16633     // A FEW HACKS!!?
16634     
16635     text = text.replace(/\\\n/g,' ');
16636     return Roo.Markdown.marked(text);
16637 };
16638 //
16639 // converter
16640 //
16641 // Wraps all "globals" so that the only thing
16642 // exposed is makeHtml().
16643 //
16644 (function() {
16645     
16646     /**
16647      * Block-Level Grammar
16648      */
16649     
16650     var block = {
16651       newline: /^\n+/,
16652       code: /^( {4}[^\n]+\n*)+/,
16653       fences: noop,
16654       hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16655       heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16656       nptable: noop,
16657       lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16658       blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16659       list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16660       html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16661       def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16662       table: noop,
16663       paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16664       text: /^[^\n]+/
16665     };
16666     
16667     block.bullet = /(?:[*+-]|\d+\.)/;
16668     block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16669     block.item = replace(block.item, 'gm')
16670       (/bull/g, block.bullet)
16671       ();
16672     
16673     block.list = replace(block.list)
16674       (/bull/g, block.bullet)
16675       ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16676       ('def', '\\n+(?=' + block.def.source + ')')
16677       ();
16678     
16679     block.blockquote = replace(block.blockquote)
16680       ('def', block.def)
16681       ();
16682     
16683     block._tag = '(?!(?:'
16684       + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16685       + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16686       + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16687     
16688     block.html = replace(block.html)
16689       ('comment', /<!--[\s\S]*?-->/)
16690       ('closed', /<(tag)[\s\S]+?<\/\1>/)
16691       ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16692       (/tag/g, block._tag)
16693       ();
16694     
16695     block.paragraph = replace(block.paragraph)
16696       ('hr', block.hr)
16697       ('heading', block.heading)
16698       ('lheading', block.lheading)
16699       ('blockquote', block.blockquote)
16700       ('tag', '<' + block._tag)
16701       ('def', block.def)
16702       ();
16703     
16704     /**
16705      * Normal Block Grammar
16706      */
16707     
16708     block.normal = merge({}, block);
16709     
16710     /**
16711      * GFM Block Grammar
16712      */
16713     
16714     block.gfm = merge({}, block.normal, {
16715       fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16716       paragraph: /^/,
16717       heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16718     });
16719     
16720     block.gfm.paragraph = replace(block.paragraph)
16721       ('(?!', '(?!'
16722         + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16723         + block.list.source.replace('\\1', '\\3') + '|')
16724       ();
16725     
16726     /**
16727      * GFM + Tables Block Grammar
16728      */
16729     
16730     block.tables = merge({}, block.gfm, {
16731       nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16732       table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16733     });
16734     
16735     /**
16736      * Block Lexer
16737      */
16738     
16739     function Lexer(options) {
16740       this.tokens = [];
16741       this.tokens.links = {};
16742       this.options = options || marked.defaults;
16743       this.rules = block.normal;
16744     
16745       if (this.options.gfm) {
16746         if (this.options.tables) {
16747           this.rules = block.tables;
16748         } else {
16749           this.rules = block.gfm;
16750         }
16751       }
16752     }
16753     
16754     /**
16755      * Expose Block Rules
16756      */
16757     
16758     Lexer.rules = block;
16759     
16760     /**
16761      * Static Lex Method
16762      */
16763     
16764     Lexer.lex = function(src, options) {
16765       var lexer = new Lexer(options);
16766       return lexer.lex(src);
16767     };
16768     
16769     /**
16770      * Preprocessing
16771      */
16772     
16773     Lexer.prototype.lex = function(src) {
16774       src = src
16775         .replace(/\r\n|\r/g, '\n')
16776         .replace(/\t/g, '    ')
16777         .replace(/\u00a0/g, ' ')
16778         .replace(/\u2424/g, '\n');
16779     
16780       return this.token(src, true);
16781     };
16782     
16783     /**
16784      * Lexing
16785      */
16786     
16787     Lexer.prototype.token = function(src, top, bq) {
16788       var src = src.replace(/^ +$/gm, '')
16789         , next
16790         , loose
16791         , cap
16792         , bull
16793         , b
16794         , item
16795         , space
16796         , i
16797         , l;
16798     
16799       while (src) {
16800         // newline
16801         if (cap = this.rules.newline.exec(src)) {
16802           src = src.substring(cap[0].length);
16803           if (cap[0].length > 1) {
16804             this.tokens.push({
16805               type: 'space'
16806             });
16807           }
16808         }
16809     
16810         // code
16811         if (cap = this.rules.code.exec(src)) {
16812           src = src.substring(cap[0].length);
16813           cap = cap[0].replace(/^ {4}/gm, '');
16814           this.tokens.push({
16815             type: 'code',
16816             text: !this.options.pedantic
16817               ? cap.replace(/\n+$/, '')
16818               : cap
16819           });
16820           continue;
16821         }
16822     
16823         // fences (gfm)
16824         if (cap = this.rules.fences.exec(src)) {
16825           src = src.substring(cap[0].length);
16826           this.tokens.push({
16827             type: 'code',
16828             lang: cap[2],
16829             text: cap[3] || ''
16830           });
16831           continue;
16832         }
16833     
16834         // heading
16835         if (cap = this.rules.heading.exec(src)) {
16836           src = src.substring(cap[0].length);
16837           this.tokens.push({
16838             type: 'heading',
16839             depth: cap[1].length,
16840             text: cap[2]
16841           });
16842           continue;
16843         }
16844     
16845         // table no leading pipe (gfm)
16846         if (top && (cap = this.rules.nptable.exec(src))) {
16847           src = src.substring(cap[0].length);
16848     
16849           item = {
16850             type: 'table',
16851             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16852             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16853             cells: cap[3].replace(/\n$/, '').split('\n')
16854           };
16855     
16856           for (i = 0; i < item.align.length; i++) {
16857             if (/^ *-+: *$/.test(item.align[i])) {
16858               item.align[i] = 'right';
16859             } else if (/^ *:-+: *$/.test(item.align[i])) {
16860               item.align[i] = 'center';
16861             } else if (/^ *:-+ *$/.test(item.align[i])) {
16862               item.align[i] = 'left';
16863             } else {
16864               item.align[i] = null;
16865             }
16866           }
16867     
16868           for (i = 0; i < item.cells.length; i++) {
16869             item.cells[i] = item.cells[i].split(/ *\| */);
16870           }
16871     
16872           this.tokens.push(item);
16873     
16874           continue;
16875         }
16876     
16877         // lheading
16878         if (cap = this.rules.lheading.exec(src)) {
16879           src = src.substring(cap[0].length);
16880           this.tokens.push({
16881             type: 'heading',
16882             depth: cap[2] === '=' ? 1 : 2,
16883             text: cap[1]
16884           });
16885           continue;
16886         }
16887     
16888         // hr
16889         if (cap = this.rules.hr.exec(src)) {
16890           src = src.substring(cap[0].length);
16891           this.tokens.push({
16892             type: 'hr'
16893           });
16894           continue;
16895         }
16896     
16897         // blockquote
16898         if (cap = this.rules.blockquote.exec(src)) {
16899           src = src.substring(cap[0].length);
16900     
16901           this.tokens.push({
16902             type: 'blockquote_start'
16903           });
16904     
16905           cap = cap[0].replace(/^ *> ?/gm, '');
16906     
16907           // Pass `top` to keep the current
16908           // "toplevel" state. This is exactly
16909           // how markdown.pl works.
16910           this.token(cap, top, true);
16911     
16912           this.tokens.push({
16913             type: 'blockquote_end'
16914           });
16915     
16916           continue;
16917         }
16918     
16919         // list
16920         if (cap = this.rules.list.exec(src)) {
16921           src = src.substring(cap[0].length);
16922           bull = cap[2];
16923     
16924           this.tokens.push({
16925             type: 'list_start',
16926             ordered: bull.length > 1
16927           });
16928     
16929           // Get each top-level item.
16930           cap = cap[0].match(this.rules.item);
16931     
16932           next = false;
16933           l = cap.length;
16934           i = 0;
16935     
16936           for (; i < l; i++) {
16937             item = cap[i];
16938     
16939             // Remove the list item's bullet
16940             // so it is seen as the next token.
16941             space = item.length;
16942             item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16943     
16944             // Outdent whatever the
16945             // list item contains. Hacky.
16946             if (~item.indexOf('\n ')) {
16947               space -= item.length;
16948               item = !this.options.pedantic
16949                 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16950                 : item.replace(/^ {1,4}/gm, '');
16951             }
16952     
16953             // Determine whether the next list item belongs here.
16954             // Backpedal if it does not belong in this list.
16955             if (this.options.smartLists && i !== l - 1) {
16956               b = block.bullet.exec(cap[i + 1])[0];
16957               if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16958                 src = cap.slice(i + 1).join('\n') + src;
16959                 i = l - 1;
16960               }
16961             }
16962     
16963             // Determine whether item is loose or not.
16964             // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
16965             // for discount behavior.
16966             loose = next || /\n\n(?!\s*$)/.test(item);
16967             if (i !== l - 1) {
16968               next = item.charAt(item.length - 1) === '\n';
16969               if (!loose) { loose = next; }
16970             }
16971     
16972             this.tokens.push({
16973               type: loose
16974                 ? 'loose_item_start'
16975                 : 'list_item_start'
16976             });
16977     
16978             // Recurse.
16979             this.token(item, false, bq);
16980     
16981             this.tokens.push({
16982               type: 'list_item_end'
16983             });
16984           }
16985     
16986           this.tokens.push({
16987             type: 'list_end'
16988           });
16989     
16990           continue;
16991         }
16992     
16993         // html
16994         if (cap = this.rules.html.exec(src)) {
16995           src = src.substring(cap[0].length);
16996           this.tokens.push({
16997             type: this.options.sanitize
16998               ? 'paragraph'
16999               : 'html',
17000             pre: !this.options.sanitizer
17001               && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17002             text: cap[0]
17003           });
17004           continue;
17005         }
17006     
17007         // def
17008         if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17009           src = src.substring(cap[0].length);
17010           this.tokens.links[cap[1].toLowerCase()] = {
17011             href: cap[2],
17012             title: cap[3]
17013           };
17014           continue;
17015         }
17016     
17017         // table (gfm)
17018         if (top && (cap = this.rules.table.exec(src))) {
17019           src = src.substring(cap[0].length);
17020     
17021           item = {
17022             type: 'table',
17023             header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17024             align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17025             cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17026           };
17027     
17028           for (i = 0; i < item.align.length; i++) {
17029             if (/^ *-+: *$/.test(item.align[i])) {
17030               item.align[i] = 'right';
17031             } else if (/^ *:-+: *$/.test(item.align[i])) {
17032               item.align[i] = 'center';
17033             } else if (/^ *:-+ *$/.test(item.align[i])) {
17034               item.align[i] = 'left';
17035             } else {
17036               item.align[i] = null;
17037             }
17038           }
17039     
17040           for (i = 0; i < item.cells.length; i++) {
17041             item.cells[i] = item.cells[i]
17042               .replace(/^ *\| *| *\| *$/g, '')
17043               .split(/ *\| */);
17044           }
17045     
17046           this.tokens.push(item);
17047     
17048           continue;
17049         }
17050     
17051         // top-level paragraph
17052         if (top && (cap = this.rules.paragraph.exec(src))) {
17053           src = src.substring(cap[0].length);
17054           this.tokens.push({
17055             type: 'paragraph',
17056             text: cap[1].charAt(cap[1].length - 1) === '\n'
17057               ? cap[1].slice(0, -1)
17058               : cap[1]
17059           });
17060           continue;
17061         }
17062     
17063         // text
17064         if (cap = this.rules.text.exec(src)) {
17065           // Top-level should never reach here.
17066           src = src.substring(cap[0].length);
17067           this.tokens.push({
17068             type: 'text',
17069             text: cap[0]
17070           });
17071           continue;
17072         }
17073     
17074         if (src) {
17075           throw new
17076             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17077         }
17078       }
17079     
17080       return this.tokens;
17081     };
17082     
17083     /**
17084      * Inline-Level Grammar
17085      */
17086     
17087     var inline = {
17088       escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17089       autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17090       url: noop,
17091       tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17092       link: /^!?\[(inside)\]\(href\)/,
17093       reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17094       nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17095       strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17096       em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17097       code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17098       br: /^ {2,}\n(?!\s*$)/,
17099       del: noop,
17100       text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17101     };
17102     
17103     inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17104     inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17105     
17106     inline.link = replace(inline.link)
17107       ('inside', inline._inside)
17108       ('href', inline._href)
17109       ();
17110     
17111     inline.reflink = replace(inline.reflink)
17112       ('inside', inline._inside)
17113       ();
17114     
17115     /**
17116      * Normal Inline Grammar
17117      */
17118     
17119     inline.normal = merge({}, inline);
17120     
17121     /**
17122      * Pedantic Inline Grammar
17123      */
17124     
17125     inline.pedantic = merge({}, inline.normal, {
17126       strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17127       em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17128     });
17129     
17130     /**
17131      * GFM Inline Grammar
17132      */
17133     
17134     inline.gfm = merge({}, inline.normal, {
17135       escape: replace(inline.escape)('])', '~|])')(),
17136       url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17137       del: /^~~(?=\S)([\s\S]*?\S)~~/,
17138       text: replace(inline.text)
17139         (']|', '~]|')
17140         ('|', '|https?://|')
17141         ()
17142     });
17143     
17144     /**
17145      * GFM + Line Breaks Inline Grammar
17146      */
17147     
17148     inline.breaks = merge({}, inline.gfm, {
17149       br: replace(inline.br)('{2,}', '*')(),
17150       text: replace(inline.gfm.text)('{2,}', '*')()
17151     });
17152     
17153     /**
17154      * Inline Lexer & Compiler
17155      */
17156     
17157     function InlineLexer(links, options) {
17158       this.options = options || marked.defaults;
17159       this.links = links;
17160       this.rules = inline.normal;
17161       this.renderer = this.options.renderer || new Renderer;
17162       this.renderer.options = this.options;
17163     
17164       if (!this.links) {
17165         throw new
17166           Error('Tokens array requires a `links` property.');
17167       }
17168     
17169       if (this.options.gfm) {
17170         if (this.options.breaks) {
17171           this.rules = inline.breaks;
17172         } else {
17173           this.rules = inline.gfm;
17174         }
17175       } else if (this.options.pedantic) {
17176         this.rules = inline.pedantic;
17177       }
17178     }
17179     
17180     /**
17181      * Expose Inline Rules
17182      */
17183     
17184     InlineLexer.rules = inline;
17185     
17186     /**
17187      * Static Lexing/Compiling Method
17188      */
17189     
17190     InlineLexer.output = function(src, links, options) {
17191       var inline = new InlineLexer(links, options);
17192       return inline.output(src);
17193     };
17194     
17195     /**
17196      * Lexing/Compiling
17197      */
17198     
17199     InlineLexer.prototype.output = function(src) {
17200       var out = ''
17201         , link
17202         , text
17203         , href
17204         , cap;
17205     
17206       while (src) {
17207         // escape
17208         if (cap = this.rules.escape.exec(src)) {
17209           src = src.substring(cap[0].length);
17210           out += cap[1];
17211           continue;
17212         }
17213     
17214         // autolink
17215         if (cap = this.rules.autolink.exec(src)) {
17216           src = src.substring(cap[0].length);
17217           if (cap[2] === '@') {
17218             text = cap[1].charAt(6) === ':'
17219               ? this.mangle(cap[1].substring(7))
17220               : this.mangle(cap[1]);
17221             href = this.mangle('mailto:') + text;
17222           } else {
17223             text = escape(cap[1]);
17224             href = text;
17225           }
17226           out += this.renderer.link(href, null, text);
17227           continue;
17228         }
17229     
17230         // url (gfm)
17231         if (!this.inLink && (cap = this.rules.url.exec(src))) {
17232           src = src.substring(cap[0].length);
17233           text = escape(cap[1]);
17234           href = text;
17235           out += this.renderer.link(href, null, text);
17236           continue;
17237         }
17238     
17239         // tag
17240         if (cap = this.rules.tag.exec(src)) {
17241           if (!this.inLink && /^<a /i.test(cap[0])) {
17242             this.inLink = true;
17243           } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17244             this.inLink = false;
17245           }
17246           src = src.substring(cap[0].length);
17247           out += this.options.sanitize
17248             ? this.options.sanitizer
17249               ? this.options.sanitizer(cap[0])
17250               : escape(cap[0])
17251             : cap[0];
17252           continue;
17253         }
17254     
17255         // link
17256         if (cap = this.rules.link.exec(src)) {
17257           src = src.substring(cap[0].length);
17258           this.inLink = true;
17259           out += this.outputLink(cap, {
17260             href: cap[2],
17261             title: cap[3]
17262           });
17263           this.inLink = false;
17264           continue;
17265         }
17266     
17267         // reflink, nolink
17268         if ((cap = this.rules.reflink.exec(src))
17269             || (cap = this.rules.nolink.exec(src))) {
17270           src = src.substring(cap[0].length);
17271           link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17272           link = this.links[link.toLowerCase()];
17273           if (!link || !link.href) {
17274             out += cap[0].charAt(0);
17275             src = cap[0].substring(1) + src;
17276             continue;
17277           }
17278           this.inLink = true;
17279           out += this.outputLink(cap, link);
17280           this.inLink = false;
17281           continue;
17282         }
17283     
17284         // strong
17285         if (cap = this.rules.strong.exec(src)) {
17286           src = src.substring(cap[0].length);
17287           out += this.renderer.strong(this.output(cap[2] || cap[1]));
17288           continue;
17289         }
17290     
17291         // em
17292         if (cap = this.rules.em.exec(src)) {
17293           src = src.substring(cap[0].length);
17294           out += this.renderer.em(this.output(cap[2] || cap[1]));
17295           continue;
17296         }
17297     
17298         // code
17299         if (cap = this.rules.code.exec(src)) {
17300           src = src.substring(cap[0].length);
17301           out += this.renderer.codespan(escape(cap[2], true));
17302           continue;
17303         }
17304     
17305         // br
17306         if (cap = this.rules.br.exec(src)) {
17307           src = src.substring(cap[0].length);
17308           out += this.renderer.br();
17309           continue;
17310         }
17311     
17312         // del (gfm)
17313         if (cap = this.rules.del.exec(src)) {
17314           src = src.substring(cap[0].length);
17315           out += this.renderer.del(this.output(cap[1]));
17316           continue;
17317         }
17318     
17319         // text
17320         if (cap = this.rules.text.exec(src)) {
17321           src = src.substring(cap[0].length);
17322           out += this.renderer.text(escape(this.smartypants(cap[0])));
17323           continue;
17324         }
17325     
17326         if (src) {
17327           throw new
17328             Error('Infinite loop on byte: ' + src.charCodeAt(0));
17329         }
17330       }
17331     
17332       return out;
17333     };
17334     
17335     /**
17336      * Compile Link
17337      */
17338     
17339     InlineLexer.prototype.outputLink = function(cap, link) {
17340       var href = escape(link.href)
17341         , title = link.title ? escape(link.title) : null;
17342     
17343       return cap[0].charAt(0) !== '!'
17344         ? this.renderer.link(href, title, this.output(cap[1]))
17345         : this.renderer.image(href, title, escape(cap[1]));
17346     };
17347     
17348     /**
17349      * Smartypants Transformations
17350      */
17351     
17352     InlineLexer.prototype.smartypants = function(text) {
17353       if (!this.options.smartypants)  { return text; }
17354       return text
17355         // em-dashes
17356         .replace(/---/g, '\u2014')
17357         // en-dashes
17358         .replace(/--/g, '\u2013')
17359         // opening singles
17360         .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17361         // closing singles & apostrophes
17362         .replace(/'/g, '\u2019')
17363         // opening doubles
17364         .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17365         // closing doubles
17366         .replace(/"/g, '\u201d')
17367         // ellipses
17368         .replace(/\.{3}/g, '\u2026');
17369     };
17370     
17371     /**
17372      * Mangle Links
17373      */
17374     
17375     InlineLexer.prototype.mangle = function(text) {
17376       if (!this.options.mangle) { return text; }
17377       var out = ''
17378         , l = text.length
17379         , i = 0
17380         , ch;
17381     
17382       for (; i < l; i++) {
17383         ch = text.charCodeAt(i);
17384         if (Math.random() > 0.5) {
17385           ch = 'x' + ch.toString(16);
17386         }
17387         out += '&#' + ch + ';';
17388       }
17389     
17390       return out;
17391     };
17392     
17393     /**
17394      * Renderer
17395      */
17396     
17397     function Renderer(options) {
17398       this.options = options || {};
17399     }
17400     
17401     Renderer.prototype.code = function(code, lang, escaped) {
17402       if (this.options.highlight) {
17403         var out = this.options.highlight(code, lang);
17404         if (out != null && out !== code) {
17405           escaped = true;
17406           code = out;
17407         }
17408       } else {
17409             // hack!!! - it's already escapeD?
17410             escaped = true;
17411       }
17412     
17413       if (!lang) {
17414         return '<pre><code>'
17415           + (escaped ? code : escape(code, true))
17416           + '\n</code></pre>';
17417       }
17418     
17419       return '<pre><code class="'
17420         + this.options.langPrefix
17421         + escape(lang, true)
17422         + '">'
17423         + (escaped ? code : escape(code, true))
17424         + '\n</code></pre>\n';
17425     };
17426     
17427     Renderer.prototype.blockquote = function(quote) {
17428       return '<blockquote>\n' + quote + '</blockquote>\n';
17429     };
17430     
17431     Renderer.prototype.html = function(html) {
17432       return html;
17433     };
17434     
17435     Renderer.prototype.heading = function(text, level, raw) {
17436       return '<h'
17437         + level
17438         + ' id="'
17439         + this.options.headerPrefix
17440         + raw.toLowerCase().replace(/[^\w]+/g, '-')
17441         + '">'
17442         + text
17443         + '</h'
17444         + level
17445         + '>\n';
17446     };
17447     
17448     Renderer.prototype.hr = function() {
17449       return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17450     };
17451     
17452     Renderer.prototype.list = function(body, ordered) {
17453       var type = ordered ? 'ol' : 'ul';
17454       return '<' + type + '>\n' + body + '</' + type + '>\n';
17455     };
17456     
17457     Renderer.prototype.listitem = function(text) {
17458       return '<li>' + text + '</li>\n';
17459     };
17460     
17461     Renderer.prototype.paragraph = function(text) {
17462       return '<p>' + text + '</p>\n';
17463     };
17464     
17465     Renderer.prototype.table = function(header, body) {
17466       return '<table class="table table-striped">\n'
17467         + '<thead>\n'
17468         + header
17469         + '</thead>\n'
17470         + '<tbody>\n'
17471         + body
17472         + '</tbody>\n'
17473         + '</table>\n';
17474     };
17475     
17476     Renderer.prototype.tablerow = function(content) {
17477       return '<tr>\n' + content + '</tr>\n';
17478     };
17479     
17480     Renderer.prototype.tablecell = function(content, flags) {
17481       var type = flags.header ? 'th' : 'td';
17482       var tag = flags.align
17483         ? '<' + type + ' style="text-align:' + flags.align + '">'
17484         : '<' + type + '>';
17485       return tag + content + '</' + type + '>\n';
17486     };
17487     
17488     // span level renderer
17489     Renderer.prototype.strong = function(text) {
17490       return '<strong>' + text + '</strong>';
17491     };
17492     
17493     Renderer.prototype.em = function(text) {
17494       return '<em>' + text + '</em>';
17495     };
17496     
17497     Renderer.prototype.codespan = function(text) {
17498       return '<code>' + text + '</code>';
17499     };
17500     
17501     Renderer.prototype.br = function() {
17502       return this.options.xhtml ? '<br/>' : '<br>';
17503     };
17504     
17505     Renderer.prototype.del = function(text) {
17506       return '<del>' + text + '</del>';
17507     };
17508     
17509     Renderer.prototype.link = function(href, title, text) {
17510       if (this.options.sanitize) {
17511         try {
17512           var prot = decodeURIComponent(unescape(href))
17513             .replace(/[^\w:]/g, '')
17514             .toLowerCase();
17515         } catch (e) {
17516           return '';
17517         }
17518         if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17519           return '';
17520         }
17521       }
17522       var out = '<a href="' + href + '"';
17523       if (title) {
17524         out += ' title="' + title + '"';
17525       }
17526       out += '>' + text + '</a>';
17527       return out;
17528     };
17529     
17530     Renderer.prototype.image = function(href, title, text) {
17531       var out = '<img src="' + href + '" alt="' + text + '"';
17532       if (title) {
17533         out += ' title="' + title + '"';
17534       }
17535       out += this.options.xhtml ? '/>' : '>';
17536       return out;
17537     };
17538     
17539     Renderer.prototype.text = function(text) {
17540       return text;
17541     };
17542     
17543     /**
17544      * Parsing & Compiling
17545      */
17546     
17547     function Parser(options) {
17548       this.tokens = [];
17549       this.token = null;
17550       this.options = options || marked.defaults;
17551       this.options.renderer = this.options.renderer || new Renderer;
17552       this.renderer = this.options.renderer;
17553       this.renderer.options = this.options;
17554     }
17555     
17556     /**
17557      * Static Parse Method
17558      */
17559     
17560     Parser.parse = function(src, options, renderer) {
17561       var parser = new Parser(options, renderer);
17562       return parser.parse(src);
17563     };
17564     
17565     /**
17566      * Parse Loop
17567      */
17568     
17569     Parser.prototype.parse = function(src) {
17570       this.inline = new InlineLexer(src.links, this.options, this.renderer);
17571       this.tokens = src.reverse();
17572     
17573       var out = '';
17574       while (this.next()) {
17575         out += this.tok();
17576       }
17577     
17578       return out;
17579     };
17580     
17581     /**
17582      * Next Token
17583      */
17584     
17585     Parser.prototype.next = function() {
17586       return this.token = this.tokens.pop();
17587     };
17588     
17589     /**
17590      * Preview Next Token
17591      */
17592     
17593     Parser.prototype.peek = function() {
17594       return this.tokens[this.tokens.length - 1] || 0;
17595     };
17596     
17597     /**
17598      * Parse Text Tokens
17599      */
17600     
17601     Parser.prototype.parseText = function() {
17602       var body = this.token.text;
17603     
17604       while (this.peek().type === 'text') {
17605         body += '\n' + this.next().text;
17606       }
17607     
17608       return this.inline.output(body);
17609     };
17610     
17611     /**
17612      * Parse Current Token
17613      */
17614     
17615     Parser.prototype.tok = function() {
17616       switch (this.token.type) {
17617         case 'space': {
17618           return '';
17619         }
17620         case 'hr': {
17621           return this.renderer.hr();
17622         }
17623         case 'heading': {
17624           return this.renderer.heading(
17625             this.inline.output(this.token.text),
17626             this.token.depth,
17627             this.token.text);
17628         }
17629         case 'code': {
17630           return this.renderer.code(this.token.text,
17631             this.token.lang,
17632             this.token.escaped);
17633         }
17634         case 'table': {
17635           var header = ''
17636             , body = ''
17637             , i
17638             , row
17639             , cell
17640             , flags
17641             , j;
17642     
17643           // header
17644           cell = '';
17645           for (i = 0; i < this.token.header.length; i++) {
17646             flags = { header: true, align: this.token.align[i] };
17647             cell += this.renderer.tablecell(
17648               this.inline.output(this.token.header[i]),
17649               { header: true, align: this.token.align[i] }
17650             );
17651           }
17652           header += this.renderer.tablerow(cell);
17653     
17654           for (i = 0; i < this.token.cells.length; i++) {
17655             row = this.token.cells[i];
17656     
17657             cell = '';
17658             for (j = 0; j < row.length; j++) {
17659               cell += this.renderer.tablecell(
17660                 this.inline.output(row[j]),
17661                 { header: false, align: this.token.align[j] }
17662               );
17663             }
17664     
17665             body += this.renderer.tablerow(cell);
17666           }
17667           return this.renderer.table(header, body);
17668         }
17669         case 'blockquote_start': {
17670           var body = '';
17671     
17672           while (this.next().type !== 'blockquote_end') {
17673             body += this.tok();
17674           }
17675     
17676           return this.renderer.blockquote(body);
17677         }
17678         case 'list_start': {
17679           var body = ''
17680             , ordered = this.token.ordered;
17681     
17682           while (this.next().type !== 'list_end') {
17683             body += this.tok();
17684           }
17685     
17686           return this.renderer.list(body, ordered);
17687         }
17688         case 'list_item_start': {
17689           var body = '';
17690     
17691           while (this.next().type !== 'list_item_end') {
17692             body += this.token.type === 'text'
17693               ? this.parseText()
17694               : this.tok();
17695           }
17696     
17697           return this.renderer.listitem(body);
17698         }
17699         case 'loose_item_start': {
17700           var body = '';
17701     
17702           while (this.next().type !== 'list_item_end') {
17703             body += this.tok();
17704           }
17705     
17706           return this.renderer.listitem(body);
17707         }
17708         case 'html': {
17709           var html = !this.token.pre && !this.options.pedantic
17710             ? this.inline.output(this.token.text)
17711             : this.token.text;
17712           return this.renderer.html(html);
17713         }
17714         case 'paragraph': {
17715           return this.renderer.paragraph(this.inline.output(this.token.text));
17716         }
17717         case 'text': {
17718           return this.renderer.paragraph(this.parseText());
17719         }
17720       }
17721     };
17722     
17723     /**
17724      * Helpers
17725      */
17726     
17727     function escape(html, encode) {
17728       return html
17729         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
17730         .replace(/</g, '&lt;')
17731         .replace(/>/g, '&gt;')
17732         .replace(/"/g, '&quot;')
17733         .replace(/'/g, '&#39;');
17734     }
17735     
17736     function unescape(html) {
17737         // explicitly match decimal, hex, and named HTML entities 
17738       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17739         n = n.toLowerCase();
17740         if (n === 'colon') { return ':'; }
17741         if (n.charAt(0) === '#') {
17742           return n.charAt(1) === 'x'
17743             ? String.fromCharCode(parseInt(n.substring(2), 16))
17744             : String.fromCharCode(+n.substring(1));
17745         }
17746         return '';
17747       });
17748     }
17749     
17750     function replace(regex, opt) {
17751       regex = regex.source;
17752       opt = opt || '';
17753       return function self(name, val) {
17754         if (!name) { return new RegExp(regex, opt); }
17755         val = val.source || val;
17756         val = val.replace(/(^|[^\[])\^/g, '$1');
17757         regex = regex.replace(name, val);
17758         return self;
17759       };
17760     }
17761     
17762     function noop() {}
17763     noop.exec = noop;
17764     
17765     function merge(obj) {
17766       var i = 1
17767         , target
17768         , key;
17769     
17770       for (; i < arguments.length; i++) {
17771         target = arguments[i];
17772         for (key in target) {
17773           if (Object.prototype.hasOwnProperty.call(target, key)) {
17774             obj[key] = target[key];
17775           }
17776         }
17777       }
17778     
17779       return obj;
17780     }
17781     
17782     
17783     /**
17784      * Marked
17785      */
17786     
17787     function marked(src, opt, callback) {
17788       if (callback || typeof opt === 'function') {
17789         if (!callback) {
17790           callback = opt;
17791           opt = null;
17792         }
17793     
17794         opt = merge({}, marked.defaults, opt || {});
17795     
17796         var highlight = opt.highlight
17797           , tokens
17798           , pending
17799           , i = 0;
17800     
17801         try {
17802           tokens = Lexer.lex(src, opt)
17803         } catch (e) {
17804           return callback(e);
17805         }
17806     
17807         pending = tokens.length;
17808     
17809         var done = function(err) {
17810           if (err) {
17811             opt.highlight = highlight;
17812             return callback(err);
17813           }
17814     
17815           var out;
17816     
17817           try {
17818             out = Parser.parse(tokens, opt);
17819           } catch (e) {
17820             err = e;
17821           }
17822     
17823           opt.highlight = highlight;
17824     
17825           return err
17826             ? callback(err)
17827             : callback(null, out);
17828         };
17829     
17830         if (!highlight || highlight.length < 3) {
17831           return done();
17832         }
17833     
17834         delete opt.highlight;
17835     
17836         if (!pending) { return done(); }
17837     
17838         for (; i < tokens.length; i++) {
17839           (function(token) {
17840             if (token.type !== 'code') {
17841               return --pending || done();
17842             }
17843             return highlight(token.text, token.lang, function(err, code) {
17844               if (err) { return done(err); }
17845               if (code == null || code === token.text) {
17846                 return --pending || done();
17847               }
17848               token.text = code;
17849               token.escaped = true;
17850               --pending || done();
17851             });
17852           })(tokens[i]);
17853         }
17854     
17855         return;
17856       }
17857       try {
17858         if (opt) { opt = merge({}, marked.defaults, opt); }
17859         return Parser.parse(Lexer.lex(src, opt), opt);
17860       } catch (e) {
17861         e.message += '\nPlease report this to https://github.com/chjj/marked.';
17862         if ((opt || marked.defaults).silent) {
17863           return '<p>An error occured:</p><pre>'
17864             + escape(e.message + '', true)
17865             + '</pre>';
17866         }
17867         throw e;
17868       }
17869     }
17870     
17871     /**
17872      * Options
17873      */
17874     
17875     marked.options =
17876     marked.setOptions = function(opt) {
17877       merge(marked.defaults, opt);
17878       return marked;
17879     };
17880     
17881     marked.defaults = {
17882       gfm: true,
17883       tables: true,
17884       breaks: false,
17885       pedantic: false,
17886       sanitize: false,
17887       sanitizer: null,
17888       mangle: true,
17889       smartLists: false,
17890       silent: false,
17891       highlight: null,
17892       langPrefix: 'lang-',
17893       smartypants: false,
17894       headerPrefix: '',
17895       renderer: new Renderer,
17896       xhtml: false
17897     };
17898     
17899     /**
17900      * Expose
17901      */
17902     
17903     marked.Parser = Parser;
17904     marked.parser = Parser.parse;
17905     
17906     marked.Renderer = Renderer;
17907     
17908     marked.Lexer = Lexer;
17909     marked.lexer = Lexer.lex;
17910     
17911     marked.InlineLexer = InlineLexer;
17912     marked.inlineLexer = InlineLexer.output;
17913     
17914     marked.parse = marked;
17915     
17916     Roo.Markdown.marked = marked;
17917
17918 })();/*
17919  * Based on:
17920  * Ext JS Library 1.1.1
17921  * Copyright(c) 2006-2007, Ext JS, LLC.
17922  *
17923  * Originally Released Under LGPL - original licence link has changed is not relivant.
17924  *
17925  * Fork - LGPL
17926  * <script type="text/javascript">
17927  */
17928
17929
17930
17931 /*
17932  * These classes are derivatives of the similarly named classes in the YUI Library.
17933  * The original license:
17934  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17935  * Code licensed under the BSD License:
17936  * http://developer.yahoo.net/yui/license.txt
17937  */
17938
17939 (function() {
17940
17941 var Event=Roo.EventManager;
17942 var Dom=Roo.lib.Dom;
17943
17944 /**
17945  * @class Roo.dd.DragDrop
17946  * @extends Roo.util.Observable
17947  * Defines the interface and base operation of items that that can be
17948  * dragged or can be drop targets.  It was designed to be extended, overriding
17949  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17950  * Up to three html elements can be associated with a DragDrop instance:
17951  * <ul>
17952  * <li>linked element: the element that is passed into the constructor.
17953  * This is the element which defines the boundaries for interaction with
17954  * other DragDrop objects.</li>
17955  * <li>handle element(s): The drag operation only occurs if the element that
17956  * was clicked matches a handle element.  By default this is the linked
17957  * element, but there are times that you will want only a portion of the
17958  * linked element to initiate the drag operation, and the setHandleElId()
17959  * method provides a way to define this.</li>
17960  * <li>drag element: this represents the element that would be moved along
17961  * with the cursor during a drag operation.  By default, this is the linked
17962  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
17963  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
17964  * </li>
17965  * </ul>
17966  * This class should not be instantiated until the onload event to ensure that
17967  * the associated elements are available.
17968  * The following would define a DragDrop obj that would interact with any
17969  * other DragDrop obj in the "group1" group:
17970  * <pre>
17971  *  dd = new Roo.dd.DragDrop("div1", "group1");
17972  * </pre>
17973  * Since none of the event handlers have been implemented, nothing would
17974  * actually happen if you were to run the code above.  Normally you would
17975  * override this class or one of the default implementations, but you can
17976  * also override the methods you want on an instance of the class...
17977  * <pre>
17978  *  dd.onDragDrop = function(e, id) {
17979  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
17980  *  }
17981  * </pre>
17982  * @constructor
17983  * @param {String} id of the element that is linked to this instance
17984  * @param {String} sGroup the group of related DragDrop objects
17985  * @param {object} config an object containing configurable attributes
17986  *                Valid properties for DragDrop:
17987  *                    padding, isTarget, maintainOffset, primaryButtonOnly
17988  */
17989 Roo.dd.DragDrop = function(id, sGroup, config) {
17990     if (id) {
17991         this.init(id, sGroup, config);
17992     }
17993     
17994 };
17995
17996 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
17997
17998     /**
17999      * The id of the element associated with this object.  This is what we
18000      * refer to as the "linked element" because the size and position of
18001      * this element is used to determine when the drag and drop objects have
18002      * interacted.
18003      * @property id
18004      * @type String
18005      */
18006     id: null,
18007
18008     /**
18009      * Configuration attributes passed into the constructor
18010      * @property config
18011      * @type object
18012      */
18013     config: null,
18014
18015     /**
18016      * The id of the element that will be dragged.  By default this is same
18017      * as the linked element , but could be changed to another element. Ex:
18018      * Roo.dd.DDProxy
18019      * @property dragElId
18020      * @type String
18021      * @private
18022      */
18023     dragElId: null,
18024
18025     /**
18026      * the id of the element that initiates the drag operation.  By default
18027      * this is the linked element, but could be changed to be a child of this
18028      * element.  This lets us do things like only starting the drag when the
18029      * header element within the linked html element is clicked.
18030      * @property handleElId
18031      * @type String
18032      * @private
18033      */
18034     handleElId: null,
18035
18036     /**
18037      * An associative array of HTML tags that will be ignored if clicked.
18038      * @property invalidHandleTypes
18039      * @type {string: string}
18040      */
18041     invalidHandleTypes: null,
18042
18043     /**
18044      * An associative array of ids for elements that will be ignored if clicked
18045      * @property invalidHandleIds
18046      * @type {string: string}
18047      */
18048     invalidHandleIds: null,
18049
18050     /**
18051      * An indexted array of css class names for elements that will be ignored
18052      * if clicked.
18053      * @property invalidHandleClasses
18054      * @type string[]
18055      */
18056     invalidHandleClasses: null,
18057
18058     /**
18059      * The linked element's absolute X position at the time the drag was
18060      * started
18061      * @property startPageX
18062      * @type int
18063      * @private
18064      */
18065     startPageX: 0,
18066
18067     /**
18068      * The linked element's absolute X position at the time the drag was
18069      * started
18070      * @property startPageY
18071      * @type int
18072      * @private
18073      */
18074     startPageY: 0,
18075
18076     /**
18077      * The group defines a logical collection of DragDrop objects that are
18078      * related.  Instances only get events when interacting with other
18079      * DragDrop object in the same group.  This lets us define multiple
18080      * groups using a single DragDrop subclass if we want.
18081      * @property groups
18082      * @type {string: string}
18083      */
18084     groups: null,
18085
18086     /**
18087      * Individual drag/drop instances can be locked.  This will prevent
18088      * onmousedown start drag.
18089      * @property locked
18090      * @type boolean
18091      * @private
18092      */
18093     locked: false,
18094
18095     /**
18096      * Lock this instance
18097      * @method lock
18098      */
18099     lock: function() { this.locked = true; },
18100
18101     /**
18102      * Unlock this instace
18103      * @method unlock
18104      */
18105     unlock: function() { this.locked = false; },
18106
18107     /**
18108      * By default, all insances can be a drop target.  This can be disabled by
18109      * setting isTarget to false.
18110      * @method isTarget
18111      * @type boolean
18112      */
18113     isTarget: true,
18114
18115     /**
18116      * The padding configured for this drag and drop object for calculating
18117      * the drop zone intersection with this object.
18118      * @method padding
18119      * @type int[]
18120      */
18121     padding: null,
18122
18123     /**
18124      * Cached reference to the linked element
18125      * @property _domRef
18126      * @private
18127      */
18128     _domRef: null,
18129
18130     /**
18131      * Internal typeof flag
18132      * @property __ygDragDrop
18133      * @private
18134      */
18135     __ygDragDrop: true,
18136
18137     /**
18138      * Set to true when horizontal contraints are applied
18139      * @property constrainX
18140      * @type boolean
18141      * @private
18142      */
18143     constrainX: false,
18144
18145     /**
18146      * Set to true when vertical contraints are applied
18147      * @property constrainY
18148      * @type boolean
18149      * @private
18150      */
18151     constrainY: false,
18152
18153     /**
18154      * The left constraint
18155      * @property minX
18156      * @type int
18157      * @private
18158      */
18159     minX: 0,
18160
18161     /**
18162      * The right constraint
18163      * @property maxX
18164      * @type int
18165      * @private
18166      */
18167     maxX: 0,
18168
18169     /**
18170      * The up constraint
18171      * @property minY
18172      * @type int
18173      * @type int
18174      * @private
18175      */
18176     minY: 0,
18177
18178     /**
18179      * The down constraint
18180      * @property maxY
18181      * @type int
18182      * @private
18183      */
18184     maxY: 0,
18185
18186     /**
18187      * Maintain offsets when we resetconstraints.  Set to true when you want
18188      * the position of the element relative to its parent to stay the same
18189      * when the page changes
18190      *
18191      * @property maintainOffset
18192      * @type boolean
18193      */
18194     maintainOffset: false,
18195
18196     /**
18197      * Array of pixel locations the element will snap to if we specified a
18198      * horizontal graduation/interval.  This array is generated automatically
18199      * when you define a tick interval.
18200      * @property xTicks
18201      * @type int[]
18202      */
18203     xTicks: null,
18204
18205     /**
18206      * Array of pixel locations the element will snap to if we specified a
18207      * vertical graduation/interval.  This array is generated automatically
18208      * when you define a tick interval.
18209      * @property yTicks
18210      * @type int[]
18211      */
18212     yTicks: null,
18213
18214     /**
18215      * By default the drag and drop instance will only respond to the primary
18216      * button click (left button for a right-handed mouse).  Set to true to
18217      * allow drag and drop to start with any mouse click that is propogated
18218      * by the browser
18219      * @property primaryButtonOnly
18220      * @type boolean
18221      */
18222     primaryButtonOnly: true,
18223
18224     /**
18225      * The availabe property is false until the linked dom element is accessible.
18226      * @property available
18227      * @type boolean
18228      */
18229     available: false,
18230
18231     /**
18232      * By default, drags can only be initiated if the mousedown occurs in the
18233      * region the linked element is.  This is done in part to work around a
18234      * bug in some browsers that mis-report the mousedown if the previous
18235      * mouseup happened outside of the window.  This property is set to true
18236      * if outer handles are defined.
18237      *
18238      * @property hasOuterHandles
18239      * @type boolean
18240      * @default false
18241      */
18242     hasOuterHandles: false,
18243
18244     /**
18245      * Code that executes immediately before the startDrag event
18246      * @method b4StartDrag
18247      * @private
18248      */
18249     b4StartDrag: function(x, y) { },
18250
18251     /**
18252      * Abstract method called after a drag/drop object is clicked
18253      * and the drag or mousedown time thresholds have beeen met.
18254      * @method startDrag
18255      * @param {int} X click location
18256      * @param {int} Y click location
18257      */
18258     startDrag: function(x, y) { /* override this */ },
18259
18260     /**
18261      * Code that executes immediately before the onDrag event
18262      * @method b4Drag
18263      * @private
18264      */
18265     b4Drag: function(e) { },
18266
18267     /**
18268      * Abstract method called during the onMouseMove event while dragging an
18269      * object.
18270      * @method onDrag
18271      * @param {Event} e the mousemove event
18272      */
18273     onDrag: function(e) { /* override this */ },
18274
18275     /**
18276      * Abstract method called when this element fist begins hovering over
18277      * another DragDrop obj
18278      * @method onDragEnter
18279      * @param {Event} e the mousemove event
18280      * @param {String|DragDrop[]} id In POINT mode, the element
18281      * id this is hovering over.  In INTERSECT mode, an array of one or more
18282      * dragdrop items being hovered over.
18283      */
18284     onDragEnter: function(e, id) { /* override this */ },
18285
18286     /**
18287      * Code that executes immediately before the onDragOver event
18288      * @method b4DragOver
18289      * @private
18290      */
18291     b4DragOver: function(e) { },
18292
18293     /**
18294      * Abstract method called when this element is hovering over another
18295      * DragDrop obj
18296      * @method onDragOver
18297      * @param {Event} e the mousemove event
18298      * @param {String|DragDrop[]} id In POINT mode, the element
18299      * id this is hovering over.  In INTERSECT mode, an array of dd items
18300      * being hovered over.
18301      */
18302     onDragOver: function(e, id) { /* override this */ },
18303
18304     /**
18305      * Code that executes immediately before the onDragOut event
18306      * @method b4DragOut
18307      * @private
18308      */
18309     b4DragOut: function(e) { },
18310
18311     /**
18312      * Abstract method called when we are no longer hovering over an element
18313      * @method onDragOut
18314      * @param {Event} e the mousemove event
18315      * @param {String|DragDrop[]} id In POINT mode, the element
18316      * id this was hovering over.  In INTERSECT mode, an array of dd items
18317      * that the mouse is no longer over.
18318      */
18319     onDragOut: function(e, id) { /* override this */ },
18320
18321     /**
18322      * Code that executes immediately before the onDragDrop event
18323      * @method b4DragDrop
18324      * @private
18325      */
18326     b4DragDrop: function(e) { },
18327
18328     /**
18329      * Abstract method called when this item is dropped on another DragDrop
18330      * obj
18331      * @method onDragDrop
18332      * @param {Event} e the mouseup event
18333      * @param {String|DragDrop[]} id In POINT mode, the element
18334      * id this was dropped on.  In INTERSECT mode, an array of dd items this
18335      * was dropped on.
18336      */
18337     onDragDrop: function(e, id) { /* override this */ },
18338
18339     /**
18340      * Abstract method called when this item is dropped on an area with no
18341      * drop target
18342      * @method onInvalidDrop
18343      * @param {Event} e the mouseup event
18344      */
18345     onInvalidDrop: function(e) { /* override this */ },
18346
18347     /**
18348      * Code that executes immediately before the endDrag event
18349      * @method b4EndDrag
18350      * @private
18351      */
18352     b4EndDrag: function(e) { },
18353
18354     /**
18355      * Fired when we are done dragging the object
18356      * @method endDrag
18357      * @param {Event} e the mouseup event
18358      */
18359     endDrag: function(e) { /* override this */ },
18360
18361     /**
18362      * Code executed immediately before the onMouseDown event
18363      * @method b4MouseDown
18364      * @param {Event} e the mousedown event
18365      * @private
18366      */
18367     b4MouseDown: function(e) {  },
18368
18369     /**
18370      * Event handler that fires when a drag/drop obj gets a mousedown
18371      * @method onMouseDown
18372      * @param {Event} e the mousedown event
18373      */
18374     onMouseDown: function(e) { /* override this */ },
18375
18376     /**
18377      * Event handler that fires when a drag/drop obj gets a mouseup
18378      * @method onMouseUp
18379      * @param {Event} e the mouseup event
18380      */
18381     onMouseUp: function(e) { /* override this */ },
18382
18383     /**
18384      * Override the onAvailable method to do what is needed after the initial
18385      * position was determined.
18386      * @method onAvailable
18387      */
18388     onAvailable: function () {
18389     },
18390
18391     /*
18392      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18393      * @type Object
18394      */
18395     defaultPadding : {left:0, right:0, top:0, bottom:0},
18396
18397     /*
18398      * Initializes the drag drop object's constraints to restrict movement to a certain element.
18399  *
18400  * Usage:
18401  <pre><code>
18402  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18403                 { dragElId: "existingProxyDiv" });
18404  dd.startDrag = function(){
18405      this.constrainTo("parent-id");
18406  };
18407  </code></pre>
18408  * Or you can initalize it using the {@link Roo.Element} object:
18409  <pre><code>
18410  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18411      startDrag : function(){
18412          this.constrainTo("parent-id");
18413      }
18414  });
18415  </code></pre>
18416      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18417      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18418      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18419      * an object containing the sides to pad. For example: {right:10, bottom:10}
18420      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18421      */
18422     constrainTo : function(constrainTo, pad, inContent){
18423         if(typeof pad == "number"){
18424             pad = {left: pad, right:pad, top:pad, bottom:pad};
18425         }
18426         pad = pad || this.defaultPadding;
18427         var b = Roo.get(this.getEl()).getBox();
18428         var ce = Roo.get(constrainTo);
18429         var s = ce.getScroll();
18430         var c, cd = ce.dom;
18431         if(cd == document.body){
18432             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18433         }else{
18434             xy = ce.getXY();
18435             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18436         }
18437
18438
18439         var topSpace = b.y - c.y;
18440         var leftSpace = b.x - c.x;
18441
18442         this.resetConstraints();
18443         this.setXConstraint(leftSpace - (pad.left||0), // left
18444                 c.width - leftSpace - b.width - (pad.right||0) //right
18445         );
18446         this.setYConstraint(topSpace - (pad.top||0), //top
18447                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18448         );
18449     },
18450
18451     /**
18452      * Returns a reference to the linked element
18453      * @method getEl
18454      * @return {HTMLElement} the html element
18455      */
18456     getEl: function() {
18457         if (!this._domRef) {
18458             this._domRef = Roo.getDom(this.id);
18459         }
18460
18461         return this._domRef;
18462     },
18463
18464     /**
18465      * Returns a reference to the actual element to drag.  By default this is
18466      * the same as the html element, but it can be assigned to another
18467      * element. An example of this can be found in Roo.dd.DDProxy
18468      * @method getDragEl
18469      * @return {HTMLElement} the html element
18470      */
18471     getDragEl: function() {
18472         return Roo.getDom(this.dragElId);
18473     },
18474
18475     /**
18476      * Sets up the DragDrop object.  Must be called in the constructor of any
18477      * Roo.dd.DragDrop subclass
18478      * @method init
18479      * @param id the id of the linked element
18480      * @param {String} sGroup the group of related items
18481      * @param {object} config configuration attributes
18482      */
18483     init: function(id, sGroup, config) {
18484         this.initTarget(id, sGroup, config);
18485         if (!Roo.isTouch) {
18486             Event.on(this.id, "mousedown", this.handleMouseDown, this);
18487         }
18488         Event.on(this.id, "touchstart", this.handleMouseDown, this);
18489         // Event.on(this.id, "selectstart", Event.preventDefault);
18490     },
18491
18492     /**
18493      * Initializes Targeting functionality only... the object does not
18494      * get a mousedown handler.
18495      * @method initTarget
18496      * @param id the id of the linked element
18497      * @param {String} sGroup the group of related items
18498      * @param {object} config configuration attributes
18499      */
18500     initTarget: function(id, sGroup, config) {
18501
18502         // configuration attributes
18503         this.config = config || {};
18504
18505         // create a local reference to the drag and drop manager
18506         this.DDM = Roo.dd.DDM;
18507         // initialize the groups array
18508         this.groups = {};
18509
18510         // assume that we have an element reference instead of an id if the
18511         // parameter is not a string
18512         if (typeof id !== "string") {
18513             id = Roo.id(id);
18514         }
18515
18516         // set the id
18517         this.id = id;
18518
18519         // add to an interaction group
18520         this.addToGroup((sGroup) ? sGroup : "default");
18521
18522         // We don't want to register this as the handle with the manager
18523         // so we just set the id rather than calling the setter.
18524         this.handleElId = id;
18525
18526         // the linked element is the element that gets dragged by default
18527         this.setDragElId(id);
18528
18529         // by default, clicked anchors will not start drag operations.
18530         this.invalidHandleTypes = { A: "A" };
18531         this.invalidHandleIds = {};
18532         this.invalidHandleClasses = [];
18533
18534         this.applyConfig();
18535
18536         this.handleOnAvailable();
18537     },
18538
18539     /**
18540      * Applies the configuration parameters that were passed into the constructor.
18541      * This is supposed to happen at each level through the inheritance chain.  So
18542      * a DDProxy implentation will execute apply config on DDProxy, DD, and
18543      * DragDrop in order to get all of the parameters that are available in
18544      * each object.
18545      * @method applyConfig
18546      */
18547     applyConfig: function() {
18548
18549         // configurable properties:
18550         //    padding, isTarget, maintainOffset, primaryButtonOnly
18551         this.padding           = this.config.padding || [0, 0, 0, 0];
18552         this.isTarget          = (this.config.isTarget !== false);
18553         this.maintainOffset    = (this.config.maintainOffset);
18554         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18555
18556     },
18557
18558     /**
18559      * Executed when the linked element is available
18560      * @method handleOnAvailable
18561      * @private
18562      */
18563     handleOnAvailable: function() {
18564         this.available = true;
18565         this.resetConstraints();
18566         this.onAvailable();
18567     },
18568
18569      /**
18570      * Configures the padding for the target zone in px.  Effectively expands
18571      * (or reduces) the virtual object size for targeting calculations.
18572      * Supports css-style shorthand; if only one parameter is passed, all sides
18573      * will have that padding, and if only two are passed, the top and bottom
18574      * will have the first param, the left and right the second.
18575      * @method setPadding
18576      * @param {int} iTop    Top pad
18577      * @param {int} iRight  Right pad
18578      * @param {int} iBot    Bot pad
18579      * @param {int} iLeft   Left pad
18580      */
18581     setPadding: function(iTop, iRight, iBot, iLeft) {
18582         // this.padding = [iLeft, iRight, iTop, iBot];
18583         if (!iRight && 0 !== iRight) {
18584             this.padding = [iTop, iTop, iTop, iTop];
18585         } else if (!iBot && 0 !== iBot) {
18586             this.padding = [iTop, iRight, iTop, iRight];
18587         } else {
18588             this.padding = [iTop, iRight, iBot, iLeft];
18589         }
18590     },
18591
18592     /**
18593      * Stores the initial placement of the linked element.
18594      * @method setInitialPosition
18595      * @param {int} diffX   the X offset, default 0
18596      * @param {int} diffY   the Y offset, default 0
18597      */
18598     setInitPosition: function(diffX, diffY) {
18599         var el = this.getEl();
18600
18601         if (!this.DDM.verifyEl(el)) {
18602             return;
18603         }
18604
18605         var dx = diffX || 0;
18606         var dy = diffY || 0;
18607
18608         var p = Dom.getXY( el );
18609
18610         this.initPageX = p[0] - dx;
18611         this.initPageY = p[1] - dy;
18612
18613         this.lastPageX = p[0];
18614         this.lastPageY = p[1];
18615
18616
18617         this.setStartPosition(p);
18618     },
18619
18620     /**
18621      * Sets the start position of the element.  This is set when the obj
18622      * is initialized, the reset when a drag is started.
18623      * @method setStartPosition
18624      * @param pos current position (from previous lookup)
18625      * @private
18626      */
18627     setStartPosition: function(pos) {
18628         var p = pos || Dom.getXY( this.getEl() );
18629         this.deltaSetXY = null;
18630
18631         this.startPageX = p[0];
18632         this.startPageY = p[1];
18633     },
18634
18635     /**
18636      * Add this instance to a group of related drag/drop objects.  All
18637      * instances belong to at least one group, and can belong to as many
18638      * groups as needed.
18639      * @method addToGroup
18640      * @param sGroup {string} the name of the group
18641      */
18642     addToGroup: function(sGroup) {
18643         this.groups[sGroup] = true;
18644         this.DDM.regDragDrop(this, sGroup);
18645     },
18646
18647     /**
18648      * Remove's this instance from the supplied interaction group
18649      * @method removeFromGroup
18650      * @param {string}  sGroup  The group to drop
18651      */
18652     removeFromGroup: function(sGroup) {
18653         if (this.groups[sGroup]) {
18654             delete this.groups[sGroup];
18655         }
18656
18657         this.DDM.removeDDFromGroup(this, sGroup);
18658     },
18659
18660     /**
18661      * Allows you to specify that an element other than the linked element
18662      * will be moved with the cursor during a drag
18663      * @method setDragElId
18664      * @param id {string} the id of the element that will be used to initiate the drag
18665      */
18666     setDragElId: function(id) {
18667         this.dragElId = id;
18668     },
18669
18670     /**
18671      * Allows you to specify a child of the linked element that should be
18672      * used to initiate the drag operation.  An example of this would be if
18673      * you have a content div with text and links.  Clicking anywhere in the
18674      * content area would normally start the drag operation.  Use this method
18675      * to specify that an element inside of the content div is the element
18676      * that starts the drag operation.
18677      * @method setHandleElId
18678      * @param id {string} the id of the element that will be used to
18679      * initiate the drag.
18680      */
18681     setHandleElId: function(id) {
18682         if (typeof id !== "string") {
18683             id = Roo.id(id);
18684         }
18685         this.handleElId = id;
18686         this.DDM.regHandle(this.id, id);
18687     },
18688
18689     /**
18690      * Allows you to set an element outside of the linked element as a drag
18691      * handle
18692      * @method setOuterHandleElId
18693      * @param id the id of the element that will be used to initiate the drag
18694      */
18695     setOuterHandleElId: function(id) {
18696         if (typeof id !== "string") {
18697             id = Roo.id(id);
18698         }
18699         Event.on(id, "mousedown",
18700                 this.handleMouseDown, this);
18701         this.setHandleElId(id);
18702
18703         this.hasOuterHandles = true;
18704     },
18705
18706     /**
18707      * Remove all drag and drop hooks for this element
18708      * @method unreg
18709      */
18710     unreg: function() {
18711         Event.un(this.id, "mousedown",
18712                 this.handleMouseDown);
18713         Event.un(this.id, "touchstart",
18714                 this.handleMouseDown);
18715         this._domRef = null;
18716         this.DDM._remove(this);
18717     },
18718
18719     destroy : function(){
18720         this.unreg();
18721     },
18722
18723     /**
18724      * Returns true if this instance is locked, or the drag drop mgr is locked
18725      * (meaning that all drag/drop is disabled on the page.)
18726      * @method isLocked
18727      * @return {boolean} true if this obj or all drag/drop is locked, else
18728      * false
18729      */
18730     isLocked: function() {
18731         return (this.DDM.isLocked() || this.locked);
18732     },
18733
18734     /**
18735      * Fired when this object is clicked
18736      * @method handleMouseDown
18737      * @param {Event} e
18738      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18739      * @private
18740      */
18741     handleMouseDown: function(e, oDD){
18742      
18743         if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18744             //Roo.log('not touch/ button !=0');
18745             return;
18746         }
18747         if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18748             return; // double touch..
18749         }
18750         
18751
18752         if (this.isLocked()) {
18753             //Roo.log('locked');
18754             return;
18755         }
18756
18757         this.DDM.refreshCache(this.groups);
18758 //        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18759         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18760         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
18761             //Roo.log('no outer handes or not over target');
18762                 // do nothing.
18763         } else {
18764 //            Roo.log('check validator');
18765             if (this.clickValidator(e)) {
18766 //                Roo.log('validate success');
18767                 // set the initial element position
18768                 this.setStartPosition();
18769
18770
18771                 this.b4MouseDown(e);
18772                 this.onMouseDown(e);
18773
18774                 this.DDM.handleMouseDown(e, this);
18775
18776                 this.DDM.stopEvent(e);
18777             } else {
18778
18779
18780             }
18781         }
18782     },
18783
18784     clickValidator: function(e) {
18785         var target = e.getTarget();
18786         return ( this.isValidHandleChild(target) &&
18787                     (this.id == this.handleElId ||
18788                         this.DDM.handleWasClicked(target, this.id)) );
18789     },
18790
18791     /**
18792      * Allows you to specify a tag name that should not start a drag operation
18793      * when clicked.  This is designed to facilitate embedding links within a
18794      * drag handle that do something other than start the drag.
18795      * @method addInvalidHandleType
18796      * @param {string} tagName the type of element to exclude
18797      */
18798     addInvalidHandleType: function(tagName) {
18799         var type = tagName.toUpperCase();
18800         this.invalidHandleTypes[type] = type;
18801     },
18802
18803     /**
18804      * Lets you to specify an element id for a child of a drag handle
18805      * that should not initiate a drag
18806      * @method addInvalidHandleId
18807      * @param {string} id the element id of the element you wish to ignore
18808      */
18809     addInvalidHandleId: function(id) {
18810         if (typeof id !== "string") {
18811             id = Roo.id(id);
18812         }
18813         this.invalidHandleIds[id] = id;
18814     },
18815
18816     /**
18817      * Lets you specify a css class of elements that will not initiate a drag
18818      * @method addInvalidHandleClass
18819      * @param {string} cssClass the class of the elements you wish to ignore
18820      */
18821     addInvalidHandleClass: function(cssClass) {
18822         this.invalidHandleClasses.push(cssClass);
18823     },
18824
18825     /**
18826      * Unsets an excluded tag name set by addInvalidHandleType
18827      * @method removeInvalidHandleType
18828      * @param {string} tagName the type of element to unexclude
18829      */
18830     removeInvalidHandleType: function(tagName) {
18831         var type = tagName.toUpperCase();
18832         // this.invalidHandleTypes[type] = null;
18833         delete this.invalidHandleTypes[type];
18834     },
18835
18836     /**
18837      * Unsets an invalid handle id
18838      * @method removeInvalidHandleId
18839      * @param {string} id the id of the element to re-enable
18840      */
18841     removeInvalidHandleId: function(id) {
18842         if (typeof id !== "string") {
18843             id = Roo.id(id);
18844         }
18845         delete this.invalidHandleIds[id];
18846     },
18847
18848     /**
18849      * Unsets an invalid css class
18850      * @method removeInvalidHandleClass
18851      * @param {string} cssClass the class of the element(s) you wish to
18852      * re-enable
18853      */
18854     removeInvalidHandleClass: function(cssClass) {
18855         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18856             if (this.invalidHandleClasses[i] == cssClass) {
18857                 delete this.invalidHandleClasses[i];
18858             }
18859         }
18860     },
18861
18862     /**
18863      * Checks the tag exclusion list to see if this click should be ignored
18864      * @method isValidHandleChild
18865      * @param {HTMLElement} node the HTMLElement to evaluate
18866      * @return {boolean} true if this is a valid tag type, false if not
18867      */
18868     isValidHandleChild: function(node) {
18869
18870         var valid = true;
18871         // var n = (node.nodeName == "#text") ? node.parentNode : node;
18872         var nodeName;
18873         try {
18874             nodeName = node.nodeName.toUpperCase();
18875         } catch(e) {
18876             nodeName = node.nodeName;
18877         }
18878         valid = valid && !this.invalidHandleTypes[nodeName];
18879         valid = valid && !this.invalidHandleIds[node.id];
18880
18881         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18882             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18883         }
18884
18885
18886         return valid;
18887
18888     },
18889
18890     /**
18891      * Create the array of horizontal tick marks if an interval was specified
18892      * in setXConstraint().
18893      * @method setXTicks
18894      * @private
18895      */
18896     setXTicks: function(iStartX, iTickSize) {
18897         this.xTicks = [];
18898         this.xTickSize = iTickSize;
18899
18900         var tickMap = {};
18901
18902         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18903             if (!tickMap[i]) {
18904                 this.xTicks[this.xTicks.length] = i;
18905                 tickMap[i] = true;
18906             }
18907         }
18908
18909         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18910             if (!tickMap[i]) {
18911                 this.xTicks[this.xTicks.length] = i;
18912                 tickMap[i] = true;
18913             }
18914         }
18915
18916         this.xTicks.sort(this.DDM.numericSort) ;
18917     },
18918
18919     /**
18920      * Create the array of vertical tick marks if an interval was specified in
18921      * setYConstraint().
18922      * @method setYTicks
18923      * @private
18924      */
18925     setYTicks: function(iStartY, iTickSize) {
18926         this.yTicks = [];
18927         this.yTickSize = iTickSize;
18928
18929         var tickMap = {};
18930
18931         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18932             if (!tickMap[i]) {
18933                 this.yTicks[this.yTicks.length] = i;
18934                 tickMap[i] = true;
18935             }
18936         }
18937
18938         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18939             if (!tickMap[i]) {
18940                 this.yTicks[this.yTicks.length] = i;
18941                 tickMap[i] = true;
18942             }
18943         }
18944
18945         this.yTicks.sort(this.DDM.numericSort) ;
18946     },
18947
18948     /**
18949      * By default, the element can be dragged any place on the screen.  Use
18950      * this method to limit the horizontal travel of the element.  Pass in
18951      * 0,0 for the parameters if you want to lock the drag to the y axis.
18952      * @method setXConstraint
18953      * @param {int} iLeft the number of pixels the element can move to the left
18954      * @param {int} iRight the number of pixels the element can move to the
18955      * right
18956      * @param {int} iTickSize optional parameter for specifying that the
18957      * element
18958      * should move iTickSize pixels at a time.
18959      */
18960     setXConstraint: function(iLeft, iRight, iTickSize) {
18961         this.leftConstraint = iLeft;
18962         this.rightConstraint = iRight;
18963
18964         this.minX = this.initPageX - iLeft;
18965         this.maxX = this.initPageX + iRight;
18966         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
18967
18968         this.constrainX = true;
18969     },
18970
18971     /**
18972      * Clears any constraints applied to this instance.  Also clears ticks
18973      * since they can't exist independent of a constraint at this time.
18974      * @method clearConstraints
18975      */
18976     clearConstraints: function() {
18977         this.constrainX = false;
18978         this.constrainY = false;
18979         this.clearTicks();
18980     },
18981
18982     /**
18983      * Clears any tick interval defined for this instance
18984      * @method clearTicks
18985      */
18986     clearTicks: function() {
18987         this.xTicks = null;
18988         this.yTicks = null;
18989         this.xTickSize = 0;
18990         this.yTickSize = 0;
18991     },
18992
18993     /**
18994      * By default, the element can be dragged any place on the screen.  Set
18995      * this to limit the vertical travel of the element.  Pass in 0,0 for the
18996      * parameters if you want to lock the drag to the x axis.
18997      * @method setYConstraint
18998      * @param {int} iUp the number of pixels the element can move up
18999      * @param {int} iDown the number of pixels the element can move down
19000      * @param {int} iTickSize optional parameter for specifying that the
19001      * element should move iTickSize pixels at a time.
19002      */
19003     setYConstraint: function(iUp, iDown, iTickSize) {
19004         this.topConstraint = iUp;
19005         this.bottomConstraint = iDown;
19006
19007         this.minY = this.initPageY - iUp;
19008         this.maxY = this.initPageY + iDown;
19009         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19010
19011         this.constrainY = true;
19012
19013     },
19014
19015     /**
19016      * resetConstraints must be called if you manually reposition a dd element.
19017      * @method resetConstraints
19018      * @param {boolean} maintainOffset
19019      */
19020     resetConstraints: function() {
19021
19022
19023         // Maintain offsets if necessary
19024         if (this.initPageX || this.initPageX === 0) {
19025             // figure out how much this thing has moved
19026             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19027             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19028
19029             this.setInitPosition(dx, dy);
19030
19031         // This is the first time we have detected the element's position
19032         } else {
19033             this.setInitPosition();
19034         }
19035
19036         if (this.constrainX) {
19037             this.setXConstraint( this.leftConstraint,
19038                                  this.rightConstraint,
19039                                  this.xTickSize        );
19040         }
19041
19042         if (this.constrainY) {
19043             this.setYConstraint( this.topConstraint,
19044                                  this.bottomConstraint,
19045                                  this.yTickSize         );
19046         }
19047     },
19048
19049     /**
19050      * Normally the drag element is moved pixel by pixel, but we can specify
19051      * that it move a number of pixels at a time.  This method resolves the
19052      * location when we have it set up like this.
19053      * @method getTick
19054      * @param {int} val where we want to place the object
19055      * @param {int[]} tickArray sorted array of valid points
19056      * @return {int} the closest tick
19057      * @private
19058      */
19059     getTick: function(val, tickArray) {
19060
19061         if (!tickArray) {
19062             // If tick interval is not defined, it is effectively 1 pixel,
19063             // so we return the value passed to us.
19064             return val;
19065         } else if (tickArray[0] >= val) {
19066             // The value is lower than the first tick, so we return the first
19067             // tick.
19068             return tickArray[0];
19069         } else {
19070             for (var i=0, len=tickArray.length; i<len; ++i) {
19071                 var next = i + 1;
19072                 if (tickArray[next] && tickArray[next] >= val) {
19073                     var diff1 = val - tickArray[i];
19074                     var diff2 = tickArray[next] - val;
19075                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19076                 }
19077             }
19078
19079             // The value is larger than the last tick, so we return the last
19080             // tick.
19081             return tickArray[tickArray.length - 1];
19082         }
19083     },
19084
19085     /**
19086      * toString method
19087      * @method toString
19088      * @return {string} string representation of the dd obj
19089      */
19090     toString: function() {
19091         return ("DragDrop " + this.id);
19092     }
19093
19094 });
19095
19096 })();
19097 /*
19098  * Based on:
19099  * Ext JS Library 1.1.1
19100  * Copyright(c) 2006-2007, Ext JS, LLC.
19101  *
19102  * Originally Released Under LGPL - original licence link has changed is not relivant.
19103  *
19104  * Fork - LGPL
19105  * <script type="text/javascript">
19106  */
19107
19108
19109 /**
19110  * The drag and drop utility provides a framework for building drag and drop
19111  * applications.  In addition to enabling drag and drop for specific elements,
19112  * the drag and drop elements are tracked by the manager class, and the
19113  * interactions between the various elements are tracked during the drag and
19114  * the implementing code is notified about these important moments.
19115  */
19116
19117 // Only load the library once.  Rewriting the manager class would orphan
19118 // existing drag and drop instances.
19119 if (!Roo.dd.DragDropMgr) {
19120
19121 /**
19122  * @class Roo.dd.DragDropMgr
19123  * DragDropMgr is a singleton that tracks the element interaction for
19124  * all DragDrop items in the window.  Generally, you will not call
19125  * this class directly, but it does have helper methods that could
19126  * be useful in your DragDrop implementations.
19127  * @singleton
19128  */
19129 Roo.dd.DragDropMgr = function() {
19130
19131     var Event = Roo.EventManager;
19132
19133     return {
19134
19135         /**
19136          * Two dimensional Array of registered DragDrop objects.  The first
19137          * dimension is the DragDrop item group, the second the DragDrop
19138          * object.
19139          * @property ids
19140          * @type {string: string}
19141          * @private
19142          * @static
19143          */
19144         ids: {},
19145
19146         /**
19147          * Array of element ids defined as drag handles.  Used to determine
19148          * if the element that generated the mousedown event is actually the
19149          * handle and not the html element itself.
19150          * @property handleIds
19151          * @type {string: string}
19152          * @private
19153          * @static
19154          */
19155         handleIds: {},
19156
19157         /**
19158          * the DragDrop object that is currently being dragged
19159          * @property dragCurrent
19160          * @type DragDrop
19161          * @private
19162          * @static
19163          **/
19164         dragCurrent: null,
19165
19166         /**
19167          * the DragDrop object(s) that are being hovered over
19168          * @property dragOvers
19169          * @type Array
19170          * @private
19171          * @static
19172          */
19173         dragOvers: {},
19174
19175         /**
19176          * the X distance between the cursor and the object being dragged
19177          * @property deltaX
19178          * @type int
19179          * @private
19180          * @static
19181          */
19182         deltaX: 0,
19183
19184         /**
19185          * the Y distance between the cursor and the object being dragged
19186          * @property deltaY
19187          * @type int
19188          * @private
19189          * @static
19190          */
19191         deltaY: 0,
19192
19193         /**
19194          * Flag to determine if we should prevent the default behavior of the
19195          * events we define. By default this is true, but this can be set to
19196          * false if you need the default behavior (not recommended)
19197          * @property preventDefault
19198          * @type boolean
19199          * @static
19200          */
19201         preventDefault: true,
19202
19203         /**
19204          * Flag to determine if we should stop the propagation of the events
19205          * we generate. This is true by default but you may want to set it to
19206          * false if the html element contains other features that require the
19207          * mouse click.
19208          * @property stopPropagation
19209          * @type boolean
19210          * @static
19211          */
19212         stopPropagation: true,
19213
19214         /**
19215          * Internal flag that is set to true when drag and drop has been
19216          * intialized
19217          * @property initialized
19218          * @private
19219          * @static
19220          */
19221         initalized: false,
19222
19223         /**
19224          * All drag and drop can be disabled.
19225          * @property locked
19226          * @private
19227          * @static
19228          */
19229         locked: false,
19230
19231         /**
19232          * Called the first time an element is registered.
19233          * @method init
19234          * @private
19235          * @static
19236          */
19237         init: function() {
19238             this.initialized = true;
19239         },
19240
19241         /**
19242          * In point mode, drag and drop interaction is defined by the
19243          * location of the cursor during the drag/drop
19244          * @property POINT
19245          * @type int
19246          * @static
19247          */
19248         POINT: 0,
19249
19250         /**
19251          * In intersect mode, drag and drop interactio nis defined by the
19252          * overlap of two or more drag and drop objects.
19253          * @property INTERSECT
19254          * @type int
19255          * @static
19256          */
19257         INTERSECT: 1,
19258
19259         /**
19260          * The current drag and drop mode.  Default: POINT
19261          * @property mode
19262          * @type int
19263          * @static
19264          */
19265         mode: 0,
19266
19267         /**
19268          * Runs method on all drag and drop objects
19269          * @method _execOnAll
19270          * @private
19271          * @static
19272          */
19273         _execOnAll: function(sMethod, args) {
19274             for (var i in this.ids) {
19275                 for (var j in this.ids[i]) {
19276                     var oDD = this.ids[i][j];
19277                     if (! this.isTypeOfDD(oDD)) {
19278                         continue;
19279                     }
19280                     oDD[sMethod].apply(oDD, args);
19281                 }
19282             }
19283         },
19284
19285         /**
19286          * Drag and drop initialization.  Sets up the global event handlers
19287          * @method _onLoad
19288          * @private
19289          * @static
19290          */
19291         _onLoad: function() {
19292
19293             this.init();
19294
19295             if (!Roo.isTouch) {
19296                 Event.on(document, "mouseup",   this.handleMouseUp, this, true);
19297                 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19298             }
19299             Event.on(document, "touchend",   this.handleMouseUp, this, true);
19300             Event.on(document, "touchmove", this.handleMouseMove, this, true);
19301             
19302             Event.on(window,   "unload",    this._onUnload, this, true);
19303             Event.on(window,   "resize",    this._onResize, this, true);
19304             // Event.on(window,   "mouseout",    this._test);
19305
19306         },
19307
19308         /**
19309          * Reset constraints on all drag and drop objs
19310          * @method _onResize
19311          * @private
19312          * @static
19313          */
19314         _onResize: function(e) {
19315             this._execOnAll("resetConstraints", []);
19316         },
19317
19318         /**
19319          * Lock all drag and drop functionality
19320          * @method lock
19321          * @static
19322          */
19323         lock: function() { this.locked = true; },
19324
19325         /**
19326          * Unlock all drag and drop functionality
19327          * @method unlock
19328          * @static
19329          */
19330         unlock: function() { this.locked = false; },
19331
19332         /**
19333          * Is drag and drop locked?
19334          * @method isLocked
19335          * @return {boolean} True if drag and drop is locked, false otherwise.
19336          * @static
19337          */
19338         isLocked: function() { return this.locked; },
19339
19340         /**
19341          * Location cache that is set for all drag drop objects when a drag is
19342          * initiated, cleared when the drag is finished.
19343          * @property locationCache
19344          * @private
19345          * @static
19346          */
19347         locationCache: {},
19348
19349         /**
19350          * Set useCache to false if you want to force object the lookup of each
19351          * drag and drop linked element constantly during a drag.
19352          * @property useCache
19353          * @type boolean
19354          * @static
19355          */
19356         useCache: true,
19357
19358         /**
19359          * The number of pixels that the mouse needs to move after the
19360          * mousedown before the drag is initiated.  Default=3;
19361          * @property clickPixelThresh
19362          * @type int
19363          * @static
19364          */
19365         clickPixelThresh: 3,
19366
19367         /**
19368          * The number of milliseconds after the mousedown event to initiate the
19369          * drag if we don't get a mouseup event. Default=1000
19370          * @property clickTimeThresh
19371          * @type int
19372          * @static
19373          */
19374         clickTimeThresh: 350,
19375
19376         /**
19377          * Flag that indicates that either the drag pixel threshold or the
19378          * mousdown time threshold has been met
19379          * @property dragThreshMet
19380          * @type boolean
19381          * @private
19382          * @static
19383          */
19384         dragThreshMet: false,
19385
19386         /**
19387          * Timeout used for the click time threshold
19388          * @property clickTimeout
19389          * @type Object
19390          * @private
19391          * @static
19392          */
19393         clickTimeout: null,
19394
19395         /**
19396          * The X position of the mousedown event stored for later use when a
19397          * drag threshold is met.
19398          * @property startX
19399          * @type int
19400          * @private
19401          * @static
19402          */
19403         startX: 0,
19404
19405         /**
19406          * The Y position of the mousedown event stored for later use when a
19407          * drag threshold is met.
19408          * @property startY
19409          * @type int
19410          * @private
19411          * @static
19412          */
19413         startY: 0,
19414
19415         /**
19416          * Each DragDrop instance must be registered with the DragDropMgr.
19417          * This is executed in DragDrop.init()
19418          * @method regDragDrop
19419          * @param {DragDrop} oDD the DragDrop object to register
19420          * @param {String} sGroup the name of the group this element belongs to
19421          * @static
19422          */
19423         regDragDrop: function(oDD, sGroup) {
19424             if (!this.initialized) { this.init(); }
19425
19426             if (!this.ids[sGroup]) {
19427                 this.ids[sGroup] = {};
19428             }
19429             this.ids[sGroup][oDD.id] = oDD;
19430         },
19431
19432         /**
19433          * Removes the supplied dd instance from the supplied group. Executed
19434          * by DragDrop.removeFromGroup, so don't call this function directly.
19435          * @method removeDDFromGroup
19436          * @private
19437          * @static
19438          */
19439         removeDDFromGroup: function(oDD, sGroup) {
19440             if (!this.ids[sGroup]) {
19441                 this.ids[sGroup] = {};
19442             }
19443
19444             var obj = this.ids[sGroup];
19445             if (obj && obj[oDD.id]) {
19446                 delete obj[oDD.id];
19447             }
19448         },
19449
19450         /**
19451          * Unregisters a drag and drop item.  This is executed in
19452          * DragDrop.unreg, use that method instead of calling this directly.
19453          * @method _remove
19454          * @private
19455          * @static
19456          */
19457         _remove: function(oDD) {
19458             for (var g in oDD.groups) {
19459                 if (g && this.ids[g][oDD.id]) {
19460                     delete this.ids[g][oDD.id];
19461                 }
19462             }
19463             delete this.handleIds[oDD.id];
19464         },
19465
19466         /**
19467          * Each DragDrop handle element must be registered.  This is done
19468          * automatically when executing DragDrop.setHandleElId()
19469          * @method regHandle
19470          * @param {String} sDDId the DragDrop id this element is a handle for
19471          * @param {String} sHandleId the id of the element that is the drag
19472          * handle
19473          * @static
19474          */
19475         regHandle: function(sDDId, sHandleId) {
19476             if (!this.handleIds[sDDId]) {
19477                 this.handleIds[sDDId] = {};
19478             }
19479             this.handleIds[sDDId][sHandleId] = sHandleId;
19480         },
19481
19482         /**
19483          * Utility function to determine if a given element has been
19484          * registered as a drag drop item.
19485          * @method isDragDrop
19486          * @param {String} id the element id to check
19487          * @return {boolean} true if this element is a DragDrop item,
19488          * false otherwise
19489          * @static
19490          */
19491         isDragDrop: function(id) {
19492             return ( this.getDDById(id) ) ? true : false;
19493         },
19494
19495         /**
19496          * Returns the drag and drop instances that are in all groups the
19497          * passed in instance belongs to.
19498          * @method getRelated
19499          * @param {DragDrop} p_oDD the obj to get related data for
19500          * @param {boolean} bTargetsOnly if true, only return targetable objs
19501          * @return {DragDrop[]} the related instances
19502          * @static
19503          */
19504         getRelated: function(p_oDD, bTargetsOnly) {
19505             var oDDs = [];
19506             for (var i in p_oDD.groups) {
19507                 for (j in this.ids[i]) {
19508                     var dd = this.ids[i][j];
19509                     if (! this.isTypeOfDD(dd)) {
19510                         continue;
19511                     }
19512                     if (!bTargetsOnly || dd.isTarget) {
19513                         oDDs[oDDs.length] = dd;
19514                     }
19515                 }
19516             }
19517
19518             return oDDs;
19519         },
19520
19521         /**
19522          * Returns true if the specified dd target is a legal target for
19523          * the specifice drag obj
19524          * @method isLegalTarget
19525          * @param {DragDrop} the drag obj
19526          * @param {DragDrop} the target
19527          * @return {boolean} true if the target is a legal target for the
19528          * dd obj
19529          * @static
19530          */
19531         isLegalTarget: function (oDD, oTargetDD) {
19532             var targets = this.getRelated(oDD, true);
19533             for (var i=0, len=targets.length;i<len;++i) {
19534                 if (targets[i].id == oTargetDD.id) {
19535                     return true;
19536                 }
19537             }
19538
19539             return false;
19540         },
19541
19542         /**
19543          * My goal is to be able to transparently determine if an object is
19544          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
19545          * returns "object", oDD.constructor.toString() always returns
19546          * "DragDrop" and not the name of the subclass.  So for now it just
19547          * evaluates a well-known variable in DragDrop.
19548          * @method isTypeOfDD
19549          * @param {Object} the object to evaluate
19550          * @return {boolean} true if typeof oDD = DragDrop
19551          * @static
19552          */
19553         isTypeOfDD: function (oDD) {
19554             return (oDD && oDD.__ygDragDrop);
19555         },
19556
19557         /**
19558          * Utility function to determine if a given element has been
19559          * registered as a drag drop handle for the given Drag Drop object.
19560          * @method isHandle
19561          * @param {String} id the element id to check
19562          * @return {boolean} true if this element is a DragDrop handle, false
19563          * otherwise
19564          * @static
19565          */
19566         isHandle: function(sDDId, sHandleId) {
19567             return ( this.handleIds[sDDId] &&
19568                             this.handleIds[sDDId][sHandleId] );
19569         },
19570
19571         /**
19572          * Returns the DragDrop instance for a given id
19573          * @method getDDById
19574          * @param {String} id the id of the DragDrop object
19575          * @return {DragDrop} the drag drop object, null if it is not found
19576          * @static
19577          */
19578         getDDById: function(id) {
19579             for (var i in this.ids) {
19580                 if (this.ids[i][id]) {
19581                     return this.ids[i][id];
19582                 }
19583             }
19584             return null;
19585         },
19586
19587         /**
19588          * Fired after a registered DragDrop object gets the mousedown event.
19589          * Sets up the events required to track the object being dragged
19590          * @method handleMouseDown
19591          * @param {Event} e the event
19592          * @param oDD the DragDrop object being dragged
19593          * @private
19594          * @static
19595          */
19596         handleMouseDown: function(e, oDD) {
19597             if(Roo.QuickTips){
19598                 Roo.QuickTips.disable();
19599             }
19600             this.currentTarget = e.getTarget();
19601
19602             this.dragCurrent = oDD;
19603
19604             var el = oDD.getEl();
19605
19606             // track start position
19607             this.startX = e.getPageX();
19608             this.startY = e.getPageY();
19609
19610             this.deltaX = this.startX - el.offsetLeft;
19611             this.deltaY = this.startY - el.offsetTop;
19612
19613             this.dragThreshMet = false;
19614
19615             this.clickTimeout = setTimeout(
19616                     function() {
19617                         var DDM = Roo.dd.DDM;
19618                         DDM.startDrag(DDM.startX, DDM.startY);
19619                     },
19620                     this.clickTimeThresh );
19621         },
19622
19623         /**
19624          * Fired when either the drag pixel threshol or the mousedown hold
19625          * time threshold has been met.
19626          * @method startDrag
19627          * @param x {int} the X position of the original mousedown
19628          * @param y {int} the Y position of the original mousedown
19629          * @static
19630          */
19631         startDrag: function(x, y) {
19632             clearTimeout(this.clickTimeout);
19633             if (this.dragCurrent) {
19634                 this.dragCurrent.b4StartDrag(x, y);
19635                 this.dragCurrent.startDrag(x, y);
19636             }
19637             this.dragThreshMet = true;
19638         },
19639
19640         /**
19641          * Internal function to handle the mouseup event.  Will be invoked
19642          * from the context of the document.
19643          * @method handleMouseUp
19644          * @param {Event} e the event
19645          * @private
19646          * @static
19647          */
19648         handleMouseUp: function(e) {
19649
19650             if(Roo.QuickTips){
19651                 Roo.QuickTips.enable();
19652             }
19653             if (! this.dragCurrent) {
19654                 return;
19655             }
19656
19657             clearTimeout(this.clickTimeout);
19658
19659             if (this.dragThreshMet) {
19660                 this.fireEvents(e, true);
19661             } else {
19662             }
19663
19664             this.stopDrag(e);
19665
19666             this.stopEvent(e);
19667         },
19668
19669         /**
19670          * Utility to stop event propagation and event default, if these
19671          * features are turned on.
19672          * @method stopEvent
19673          * @param {Event} e the event as returned by this.getEvent()
19674          * @static
19675          */
19676         stopEvent: function(e){
19677             if(this.stopPropagation) {
19678                 e.stopPropagation();
19679             }
19680
19681             if (this.preventDefault) {
19682                 e.preventDefault();
19683             }
19684         },
19685
19686         /**
19687          * Internal function to clean up event handlers after the drag
19688          * operation is complete
19689          * @method stopDrag
19690          * @param {Event} e the event
19691          * @private
19692          * @static
19693          */
19694         stopDrag: function(e) {
19695             // Fire the drag end event for the item that was dragged
19696             if (this.dragCurrent) {
19697                 if (this.dragThreshMet) {
19698                     this.dragCurrent.b4EndDrag(e);
19699                     this.dragCurrent.endDrag(e);
19700                 }
19701
19702                 this.dragCurrent.onMouseUp(e);
19703             }
19704
19705             this.dragCurrent = null;
19706             this.dragOvers = {};
19707         },
19708
19709         /**
19710          * Internal function to handle the mousemove event.  Will be invoked
19711          * from the context of the html element.
19712          *
19713          * @TODO figure out what we can do about mouse events lost when the
19714          * user drags objects beyond the window boundary.  Currently we can
19715          * detect this in internet explorer by verifying that the mouse is
19716          * down during the mousemove event.  Firefox doesn't give us the
19717          * button state on the mousemove event.
19718          * @method handleMouseMove
19719          * @param {Event} e the event
19720          * @private
19721          * @static
19722          */
19723         handleMouseMove: function(e) {
19724             if (! this.dragCurrent) {
19725                 return true;
19726             }
19727
19728             // var button = e.which || e.button;
19729
19730             // check for IE mouseup outside of page boundary
19731             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19732                 this.stopEvent(e);
19733                 return this.handleMouseUp(e);
19734             }
19735
19736             if (!this.dragThreshMet) {
19737                 var diffX = Math.abs(this.startX - e.getPageX());
19738                 var diffY = Math.abs(this.startY - e.getPageY());
19739                 if (diffX > this.clickPixelThresh ||
19740                             diffY > this.clickPixelThresh) {
19741                     this.startDrag(this.startX, this.startY);
19742                 }
19743             }
19744
19745             if (this.dragThreshMet) {
19746                 this.dragCurrent.b4Drag(e);
19747                 this.dragCurrent.onDrag(e);
19748                 if(!this.dragCurrent.moveOnly){
19749                     this.fireEvents(e, false);
19750                 }
19751             }
19752
19753             this.stopEvent(e);
19754
19755             return true;
19756         },
19757
19758         /**
19759          * Iterates over all of the DragDrop elements to find ones we are
19760          * hovering over or dropping on
19761          * @method fireEvents
19762          * @param {Event} e the event
19763          * @param {boolean} isDrop is this a drop op or a mouseover op?
19764          * @private
19765          * @static
19766          */
19767         fireEvents: function(e, isDrop) {
19768             var dc = this.dragCurrent;
19769
19770             // If the user did the mouse up outside of the window, we could
19771             // get here even though we have ended the drag.
19772             if (!dc || dc.isLocked()) {
19773                 return;
19774             }
19775
19776             var pt = e.getPoint();
19777
19778             // cache the previous dragOver array
19779             var oldOvers = [];
19780
19781             var outEvts   = [];
19782             var overEvts  = [];
19783             var dropEvts  = [];
19784             var enterEvts = [];
19785
19786             // Check to see if the object(s) we were hovering over is no longer
19787             // being hovered over so we can fire the onDragOut event
19788             for (var i in this.dragOvers) {
19789
19790                 var ddo = this.dragOvers[i];
19791
19792                 if (! this.isTypeOfDD(ddo)) {
19793                     continue;
19794                 }
19795
19796                 if (! this.isOverTarget(pt, ddo, this.mode)) {
19797                     outEvts.push( ddo );
19798                 }
19799
19800                 oldOvers[i] = true;
19801                 delete this.dragOvers[i];
19802             }
19803
19804             for (var sGroup in dc.groups) {
19805
19806                 if ("string" != typeof sGroup) {
19807                     continue;
19808                 }
19809
19810                 for (i in this.ids[sGroup]) {
19811                     var oDD = this.ids[sGroup][i];
19812                     if (! this.isTypeOfDD(oDD)) {
19813                         continue;
19814                     }
19815
19816                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19817                         if (this.isOverTarget(pt, oDD, this.mode)) {
19818                             // look for drop interactions
19819                             if (isDrop) {
19820                                 dropEvts.push( oDD );
19821                             // look for drag enter and drag over interactions
19822                             } else {
19823
19824                                 // initial drag over: dragEnter fires
19825                                 if (!oldOvers[oDD.id]) {
19826                                     enterEvts.push( oDD );
19827                                 // subsequent drag overs: dragOver fires
19828                                 } else {
19829                                     overEvts.push( oDD );
19830                                 }
19831
19832                                 this.dragOvers[oDD.id] = oDD;
19833                             }
19834                         }
19835                     }
19836                 }
19837             }
19838
19839             if (this.mode) {
19840                 if (outEvts.length) {
19841                     dc.b4DragOut(e, outEvts);
19842                     dc.onDragOut(e, outEvts);
19843                 }
19844
19845                 if (enterEvts.length) {
19846                     dc.onDragEnter(e, enterEvts);
19847                 }
19848
19849                 if (overEvts.length) {
19850                     dc.b4DragOver(e, overEvts);
19851                     dc.onDragOver(e, overEvts);
19852                 }
19853
19854                 if (dropEvts.length) {
19855                     dc.b4DragDrop(e, dropEvts);
19856                     dc.onDragDrop(e, dropEvts);
19857                 }
19858
19859             } else {
19860                 // fire dragout events
19861                 var len = 0;
19862                 for (i=0, len=outEvts.length; i<len; ++i) {
19863                     dc.b4DragOut(e, outEvts[i].id);
19864                     dc.onDragOut(e, outEvts[i].id);
19865                 }
19866
19867                 // fire enter events
19868                 for (i=0,len=enterEvts.length; i<len; ++i) {
19869                     // dc.b4DragEnter(e, oDD.id);
19870                     dc.onDragEnter(e, enterEvts[i].id);
19871                 }
19872
19873                 // fire over events
19874                 for (i=0,len=overEvts.length; i<len; ++i) {
19875                     dc.b4DragOver(e, overEvts[i].id);
19876                     dc.onDragOver(e, overEvts[i].id);
19877                 }
19878
19879                 // fire drop events
19880                 for (i=0, len=dropEvts.length; i<len; ++i) {
19881                     dc.b4DragDrop(e, dropEvts[i].id);
19882                     dc.onDragDrop(e, dropEvts[i].id);
19883                 }
19884
19885             }
19886
19887             // notify about a drop that did not find a target
19888             if (isDrop && !dropEvts.length) {
19889                 dc.onInvalidDrop(e);
19890             }
19891
19892         },
19893
19894         /**
19895          * Helper function for getting the best match from the list of drag
19896          * and drop objects returned by the drag and drop events when we are
19897          * in INTERSECT mode.  It returns either the first object that the
19898          * cursor is over, or the object that has the greatest overlap with
19899          * the dragged element.
19900          * @method getBestMatch
19901          * @param  {DragDrop[]} dds The array of drag and drop objects
19902          * targeted
19903          * @return {DragDrop}       The best single match
19904          * @static
19905          */
19906         getBestMatch: function(dds) {
19907             var winner = null;
19908             // Return null if the input is not what we expect
19909             //if (!dds || !dds.length || dds.length == 0) {
19910                // winner = null;
19911             // If there is only one item, it wins
19912             //} else if (dds.length == 1) {
19913
19914             var len = dds.length;
19915
19916             if (len == 1) {
19917                 winner = dds[0];
19918             } else {
19919                 // Loop through the targeted items
19920                 for (var i=0; i<len; ++i) {
19921                     var dd = dds[i];
19922                     // If the cursor is over the object, it wins.  If the
19923                     // cursor is over multiple matches, the first one we come
19924                     // to wins.
19925                     if (dd.cursorIsOver) {
19926                         winner = dd;
19927                         break;
19928                     // Otherwise the object with the most overlap wins
19929                     } else {
19930                         if (!winner ||
19931                             winner.overlap.getArea() < dd.overlap.getArea()) {
19932                             winner = dd;
19933                         }
19934                     }
19935                 }
19936             }
19937
19938             return winner;
19939         },
19940
19941         /**
19942          * Refreshes the cache of the top-left and bottom-right points of the
19943          * drag and drop objects in the specified group(s).  This is in the
19944          * format that is stored in the drag and drop instance, so typical
19945          * usage is:
19946          * <code>
19947          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19948          * </code>
19949          * Alternatively:
19950          * <code>
19951          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19952          * </code>
19953          * @TODO this really should be an indexed array.  Alternatively this
19954          * method could accept both.
19955          * @method refreshCache
19956          * @param {Object} groups an associative array of groups to refresh
19957          * @static
19958          */
19959         refreshCache: function(groups) {
19960             for (var sGroup in groups) {
19961                 if ("string" != typeof sGroup) {
19962                     continue;
19963                 }
19964                 for (var i in this.ids[sGroup]) {
19965                     var oDD = this.ids[sGroup][i];
19966
19967                     if (this.isTypeOfDD(oDD)) {
19968                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
19969                         var loc = this.getLocation(oDD);
19970                         if (loc) {
19971                             this.locationCache[oDD.id] = loc;
19972                         } else {
19973                             delete this.locationCache[oDD.id];
19974                             // this will unregister the drag and drop object if
19975                             // the element is not in a usable state
19976                             // oDD.unreg();
19977                         }
19978                     }
19979                 }
19980             }
19981         },
19982
19983         /**
19984          * This checks to make sure an element exists and is in the DOM.  The
19985          * main purpose is to handle cases where innerHTML is used to remove
19986          * drag and drop objects from the DOM.  IE provides an 'unspecified
19987          * error' when trying to access the offsetParent of such an element
19988          * @method verifyEl
19989          * @param {HTMLElement} el the element to check
19990          * @return {boolean} true if the element looks usable
19991          * @static
19992          */
19993         verifyEl: function(el) {
19994             if (el) {
19995                 var parent;
19996                 if(Roo.isIE){
19997                     try{
19998                         parent = el.offsetParent;
19999                     }catch(e){}
20000                 }else{
20001                     parent = el.offsetParent;
20002                 }
20003                 if (parent) {
20004                     return true;
20005                 }
20006             }
20007
20008             return false;
20009         },
20010
20011         /**
20012          * Returns a Region object containing the drag and drop element's position
20013          * and size, including the padding configured for it
20014          * @method getLocation
20015          * @param {DragDrop} oDD the drag and drop object to get the
20016          *                       location for
20017          * @return {Roo.lib.Region} a Region object representing the total area
20018          *                             the element occupies, including any padding
20019          *                             the instance is configured for.
20020          * @static
20021          */
20022         getLocation: function(oDD) {
20023             if (! this.isTypeOfDD(oDD)) {
20024                 return null;
20025             }
20026
20027             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20028
20029             try {
20030                 pos= Roo.lib.Dom.getXY(el);
20031             } catch (e) { }
20032
20033             if (!pos) {
20034                 return null;
20035             }
20036
20037             x1 = pos[0];
20038             x2 = x1 + el.offsetWidth;
20039             y1 = pos[1];
20040             y2 = y1 + el.offsetHeight;
20041
20042             t = y1 - oDD.padding[0];
20043             r = x2 + oDD.padding[1];
20044             b = y2 + oDD.padding[2];
20045             l = x1 - oDD.padding[3];
20046
20047             return new Roo.lib.Region( t, r, b, l );
20048         },
20049
20050         /**
20051          * Checks the cursor location to see if it over the target
20052          * @method isOverTarget
20053          * @param {Roo.lib.Point} pt The point to evaluate
20054          * @param {DragDrop} oTarget the DragDrop object we are inspecting
20055          * @return {boolean} true if the mouse is over the target
20056          * @private
20057          * @static
20058          */
20059         isOverTarget: function(pt, oTarget, intersect) {
20060             // use cache if available
20061             var loc = this.locationCache[oTarget.id];
20062             if (!loc || !this.useCache) {
20063                 loc = this.getLocation(oTarget);
20064                 this.locationCache[oTarget.id] = loc;
20065
20066             }
20067
20068             if (!loc) {
20069                 return false;
20070             }
20071
20072             oTarget.cursorIsOver = loc.contains( pt );
20073
20074             // DragDrop is using this as a sanity check for the initial mousedown
20075             // in this case we are done.  In POINT mode, if the drag obj has no
20076             // contraints, we are also done. Otherwise we need to evaluate the
20077             // location of the target as related to the actual location of the
20078             // dragged element.
20079             var dc = this.dragCurrent;
20080             if (!dc || !dc.getTargetCoord ||
20081                     (!intersect && !dc.constrainX && !dc.constrainY)) {
20082                 return oTarget.cursorIsOver;
20083             }
20084
20085             oTarget.overlap = null;
20086
20087             // Get the current location of the drag element, this is the
20088             // location of the mouse event less the delta that represents
20089             // where the original mousedown happened on the element.  We
20090             // need to consider constraints and ticks as well.
20091             var pos = dc.getTargetCoord(pt.x, pt.y);
20092
20093             var el = dc.getDragEl();
20094             var curRegion = new Roo.lib.Region( pos.y,
20095                                                    pos.x + el.offsetWidth,
20096                                                    pos.y + el.offsetHeight,
20097                                                    pos.x );
20098
20099             var overlap = curRegion.intersect(loc);
20100
20101             if (overlap) {
20102                 oTarget.overlap = overlap;
20103                 return (intersect) ? true : oTarget.cursorIsOver;
20104             } else {
20105                 return false;
20106             }
20107         },
20108
20109         /**
20110          * unload event handler
20111          * @method _onUnload
20112          * @private
20113          * @static
20114          */
20115         _onUnload: function(e, me) {
20116             Roo.dd.DragDropMgr.unregAll();
20117         },
20118
20119         /**
20120          * Cleans up the drag and drop events and objects.
20121          * @method unregAll
20122          * @private
20123          * @static
20124          */
20125         unregAll: function() {
20126
20127             if (this.dragCurrent) {
20128                 this.stopDrag();
20129                 this.dragCurrent = null;
20130             }
20131
20132             this._execOnAll("unreg", []);
20133
20134             for (i in this.elementCache) {
20135                 delete this.elementCache[i];
20136             }
20137
20138             this.elementCache = {};
20139             this.ids = {};
20140         },
20141
20142         /**
20143          * A cache of DOM elements
20144          * @property elementCache
20145          * @private
20146          * @static
20147          */
20148         elementCache: {},
20149
20150         /**
20151          * Get the wrapper for the DOM element specified
20152          * @method getElWrapper
20153          * @param {String} id the id of the element to get
20154          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20155          * @private
20156          * @deprecated This wrapper isn't that useful
20157          * @static
20158          */
20159         getElWrapper: function(id) {
20160             var oWrapper = this.elementCache[id];
20161             if (!oWrapper || !oWrapper.el) {
20162                 oWrapper = this.elementCache[id] =
20163                     new this.ElementWrapper(Roo.getDom(id));
20164             }
20165             return oWrapper;
20166         },
20167
20168         /**
20169          * Returns the actual DOM element
20170          * @method getElement
20171          * @param {String} id the id of the elment to get
20172          * @return {Object} The element
20173          * @deprecated use Roo.getDom instead
20174          * @static
20175          */
20176         getElement: function(id) {
20177             return Roo.getDom(id);
20178         },
20179
20180         /**
20181          * Returns the style property for the DOM element (i.e.,
20182          * document.getElById(id).style)
20183          * @method getCss
20184          * @param {String} id the id of the elment to get
20185          * @return {Object} The style property of the element
20186          * @deprecated use Roo.getDom instead
20187          * @static
20188          */
20189         getCss: function(id) {
20190             var el = Roo.getDom(id);
20191             return (el) ? el.style : null;
20192         },
20193
20194         /**
20195          * Inner class for cached elements
20196          * @class DragDropMgr.ElementWrapper
20197          * @for DragDropMgr
20198          * @private
20199          * @deprecated
20200          */
20201         ElementWrapper: function(el) {
20202                 /**
20203                  * The element
20204                  * @property el
20205                  */
20206                 this.el = el || null;
20207                 /**
20208                  * The element id
20209                  * @property id
20210                  */
20211                 this.id = this.el && el.id;
20212                 /**
20213                  * A reference to the style property
20214                  * @property css
20215                  */
20216                 this.css = this.el && el.style;
20217             },
20218
20219         /**
20220          * Returns the X position of an html element
20221          * @method getPosX
20222          * @param el the element for which to get the position
20223          * @return {int} the X coordinate
20224          * @for DragDropMgr
20225          * @deprecated use Roo.lib.Dom.getX instead
20226          * @static
20227          */
20228         getPosX: function(el) {
20229             return Roo.lib.Dom.getX(el);
20230         },
20231
20232         /**
20233          * Returns the Y position of an html element
20234          * @method getPosY
20235          * @param el the element for which to get the position
20236          * @return {int} the Y coordinate
20237          * @deprecated use Roo.lib.Dom.getY instead
20238          * @static
20239          */
20240         getPosY: function(el) {
20241             return Roo.lib.Dom.getY(el);
20242         },
20243
20244         /**
20245          * Swap two nodes.  In IE, we use the native method, for others we
20246          * emulate the IE behavior
20247          * @method swapNode
20248          * @param n1 the first node to swap
20249          * @param n2 the other node to swap
20250          * @static
20251          */
20252         swapNode: function(n1, n2) {
20253             if (n1.swapNode) {
20254                 n1.swapNode(n2);
20255             } else {
20256                 var p = n2.parentNode;
20257                 var s = n2.nextSibling;
20258
20259                 if (s == n1) {
20260                     p.insertBefore(n1, n2);
20261                 } else if (n2 == n1.nextSibling) {
20262                     p.insertBefore(n2, n1);
20263                 } else {
20264                     n1.parentNode.replaceChild(n2, n1);
20265                     p.insertBefore(n1, s);
20266                 }
20267             }
20268         },
20269
20270         /**
20271          * Returns the current scroll position
20272          * @method getScroll
20273          * @private
20274          * @static
20275          */
20276         getScroll: function () {
20277             var t, l, dde=document.documentElement, db=document.body;
20278             if (dde && (dde.scrollTop || dde.scrollLeft)) {
20279                 t = dde.scrollTop;
20280                 l = dde.scrollLeft;
20281             } else if (db) {
20282                 t = db.scrollTop;
20283                 l = db.scrollLeft;
20284             } else {
20285
20286             }
20287             return { top: t, left: l };
20288         },
20289
20290         /**
20291          * Returns the specified element style property
20292          * @method getStyle
20293          * @param {HTMLElement} el          the element
20294          * @param {string}      styleProp   the style property
20295          * @return {string} The value of the style property
20296          * @deprecated use Roo.lib.Dom.getStyle
20297          * @static
20298          */
20299         getStyle: function(el, styleProp) {
20300             return Roo.fly(el).getStyle(styleProp);
20301         },
20302
20303         /**
20304          * Gets the scrollTop
20305          * @method getScrollTop
20306          * @return {int} the document's scrollTop
20307          * @static
20308          */
20309         getScrollTop: function () { return this.getScroll().top; },
20310
20311         /**
20312          * Gets the scrollLeft
20313          * @method getScrollLeft
20314          * @return {int} the document's scrollTop
20315          * @static
20316          */
20317         getScrollLeft: function () { return this.getScroll().left; },
20318
20319         /**
20320          * Sets the x/y position of an element to the location of the
20321          * target element.
20322          * @method moveToEl
20323          * @param {HTMLElement} moveEl      The element to move
20324          * @param {HTMLElement} targetEl    The position reference element
20325          * @static
20326          */
20327         moveToEl: function (moveEl, targetEl) {
20328             var aCoord = Roo.lib.Dom.getXY(targetEl);
20329             Roo.lib.Dom.setXY(moveEl, aCoord);
20330         },
20331
20332         /**
20333          * Numeric array sort function
20334          * @method numericSort
20335          * @static
20336          */
20337         numericSort: function(a, b) { return (a - b); },
20338
20339         /**
20340          * Internal counter
20341          * @property _timeoutCount
20342          * @private
20343          * @static
20344          */
20345         _timeoutCount: 0,
20346
20347         /**
20348          * Trying to make the load order less important.  Without this we get
20349          * an error if this file is loaded before the Event Utility.
20350          * @method _addListeners
20351          * @private
20352          * @static
20353          */
20354         _addListeners: function() {
20355             var DDM = Roo.dd.DDM;
20356             if ( Roo.lib.Event && document ) {
20357                 DDM._onLoad();
20358             } else {
20359                 if (DDM._timeoutCount > 2000) {
20360                 } else {
20361                     setTimeout(DDM._addListeners, 10);
20362                     if (document && document.body) {
20363                         DDM._timeoutCount += 1;
20364                     }
20365                 }
20366             }
20367         },
20368
20369         /**
20370          * Recursively searches the immediate parent and all child nodes for
20371          * the handle element in order to determine wheter or not it was
20372          * clicked.
20373          * @method handleWasClicked
20374          * @param node the html element to inspect
20375          * @static
20376          */
20377         handleWasClicked: function(node, id) {
20378             if (this.isHandle(id, node.id)) {
20379                 return true;
20380             } else {
20381                 // check to see if this is a text node child of the one we want
20382                 var p = node.parentNode;
20383
20384                 while (p) {
20385                     if (this.isHandle(id, p.id)) {
20386                         return true;
20387                     } else {
20388                         p = p.parentNode;
20389                     }
20390                 }
20391             }
20392
20393             return false;
20394         }
20395
20396     };
20397
20398 }();
20399
20400 // shorter alias, save a few bytes
20401 Roo.dd.DDM = Roo.dd.DragDropMgr;
20402 Roo.dd.DDM._addListeners();
20403
20404 }/*
20405  * Based on:
20406  * Ext JS Library 1.1.1
20407  * Copyright(c) 2006-2007, Ext JS, LLC.
20408  *
20409  * Originally Released Under LGPL - original licence link has changed is not relivant.
20410  *
20411  * Fork - LGPL
20412  * <script type="text/javascript">
20413  */
20414
20415 /**
20416  * @class Roo.dd.DD
20417  * A DragDrop implementation where the linked element follows the
20418  * mouse cursor during a drag.
20419  * @extends Roo.dd.DragDrop
20420  * @constructor
20421  * @param {String} id the id of the linked element
20422  * @param {String} sGroup the group of related DragDrop items
20423  * @param {object} config an object containing configurable attributes
20424  *                Valid properties for DD:
20425  *                    scroll
20426  */
20427 Roo.dd.DD = function(id, sGroup, config) {
20428     if (id) {
20429         this.init(id, sGroup, config);
20430     }
20431 };
20432
20433 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20434
20435     /**
20436      * When set to true, the utility automatically tries to scroll the browser
20437      * window wehn a drag and drop element is dragged near the viewport boundary.
20438      * Defaults to true.
20439      * @property scroll
20440      * @type boolean
20441      */
20442     scroll: true,
20443
20444     /**
20445      * Sets the pointer offset to the distance between the linked element's top
20446      * left corner and the location the element was clicked
20447      * @method autoOffset
20448      * @param {int} iPageX the X coordinate of the click
20449      * @param {int} iPageY the Y coordinate of the click
20450      */
20451     autoOffset: function(iPageX, iPageY) {
20452         var x = iPageX - this.startPageX;
20453         var y = iPageY - this.startPageY;
20454         this.setDelta(x, y);
20455     },
20456
20457     /**
20458      * Sets the pointer offset.  You can call this directly to force the
20459      * offset to be in a particular location (e.g., pass in 0,0 to set it
20460      * to the center of the object)
20461      * @method setDelta
20462      * @param {int} iDeltaX the distance from the left
20463      * @param {int} iDeltaY the distance from the top
20464      */
20465     setDelta: function(iDeltaX, iDeltaY) {
20466         this.deltaX = iDeltaX;
20467         this.deltaY = iDeltaY;
20468     },
20469
20470     /**
20471      * Sets the drag element to the location of the mousedown or click event,
20472      * maintaining the cursor location relative to the location on the element
20473      * that was clicked.  Override this if you want to place the element in a
20474      * location other than where the cursor is.
20475      * @method setDragElPos
20476      * @param {int} iPageX the X coordinate of the mousedown or drag event
20477      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20478      */
20479     setDragElPos: function(iPageX, iPageY) {
20480         // the first time we do this, we are going to check to make sure
20481         // the element has css positioning
20482
20483         var el = this.getDragEl();
20484         this.alignElWithMouse(el, iPageX, iPageY);
20485     },
20486
20487     /**
20488      * Sets the element to the location of the mousedown or click event,
20489      * maintaining the cursor location relative to the location on the element
20490      * that was clicked.  Override this if you want to place the element in a
20491      * location other than where the cursor is.
20492      * @method alignElWithMouse
20493      * @param {HTMLElement} el the element to move
20494      * @param {int} iPageX the X coordinate of the mousedown or drag event
20495      * @param {int} iPageY the Y coordinate of the mousedown or drag event
20496      */
20497     alignElWithMouse: function(el, iPageX, iPageY) {
20498         var oCoord = this.getTargetCoord(iPageX, iPageY);
20499         var fly = el.dom ? el : Roo.fly(el);
20500         if (!this.deltaSetXY) {
20501             var aCoord = [oCoord.x, oCoord.y];
20502             fly.setXY(aCoord);
20503             var newLeft = fly.getLeft(true);
20504             var newTop  = fly.getTop(true);
20505             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20506         } else {
20507             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20508         }
20509
20510         this.cachePosition(oCoord.x, oCoord.y);
20511         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20512         return oCoord;
20513     },
20514
20515     /**
20516      * Saves the most recent position so that we can reset the constraints and
20517      * tick marks on-demand.  We need to know this so that we can calculate the
20518      * number of pixels the element is offset from its original position.
20519      * @method cachePosition
20520      * @param iPageX the current x position (optional, this just makes it so we
20521      * don't have to look it up again)
20522      * @param iPageY the current y position (optional, this just makes it so we
20523      * don't have to look it up again)
20524      */
20525     cachePosition: function(iPageX, iPageY) {
20526         if (iPageX) {
20527             this.lastPageX = iPageX;
20528             this.lastPageY = iPageY;
20529         } else {
20530             var aCoord = Roo.lib.Dom.getXY(this.getEl());
20531             this.lastPageX = aCoord[0];
20532             this.lastPageY = aCoord[1];
20533         }
20534     },
20535
20536     /**
20537      * Auto-scroll the window if the dragged object has been moved beyond the
20538      * visible window boundary.
20539      * @method autoScroll
20540      * @param {int} x the drag element's x position
20541      * @param {int} y the drag element's y position
20542      * @param {int} h the height of the drag element
20543      * @param {int} w the width of the drag element
20544      * @private
20545      */
20546     autoScroll: function(x, y, h, w) {
20547
20548         if (this.scroll) {
20549             // The client height
20550             var clientH = Roo.lib.Dom.getViewWidth();
20551
20552             // The client width
20553             var clientW = Roo.lib.Dom.getViewHeight();
20554
20555             // The amt scrolled down
20556             var st = this.DDM.getScrollTop();
20557
20558             // The amt scrolled right
20559             var sl = this.DDM.getScrollLeft();
20560
20561             // Location of the bottom of the element
20562             var bot = h + y;
20563
20564             // Location of the right of the element
20565             var right = w + x;
20566
20567             // The distance from the cursor to the bottom of the visible area,
20568             // adjusted so that we don't scroll if the cursor is beyond the
20569             // element drag constraints
20570             var toBot = (clientH + st - y - this.deltaY);
20571
20572             // The distance from the cursor to the right of the visible area
20573             var toRight = (clientW + sl - x - this.deltaX);
20574
20575
20576             // How close to the edge the cursor must be before we scroll
20577             // var thresh = (document.all) ? 100 : 40;
20578             var thresh = 40;
20579
20580             // How many pixels to scroll per autoscroll op.  This helps to reduce
20581             // clunky scrolling. IE is more sensitive about this ... it needs this
20582             // value to be higher.
20583             var scrAmt = (document.all) ? 80 : 30;
20584
20585             // Scroll down if we are near the bottom of the visible page and the
20586             // obj extends below the crease
20587             if ( bot > clientH && toBot < thresh ) {
20588                 window.scrollTo(sl, st + scrAmt);
20589             }
20590
20591             // Scroll up if the window is scrolled down and the top of the object
20592             // goes above the top border
20593             if ( y < st && st > 0 && y - st < thresh ) {
20594                 window.scrollTo(sl, st - scrAmt);
20595             }
20596
20597             // Scroll right if the obj is beyond the right border and the cursor is
20598             // near the border.
20599             if ( right > clientW && toRight < thresh ) {
20600                 window.scrollTo(sl + scrAmt, st);
20601             }
20602
20603             // Scroll left if the window has been scrolled to the right and the obj
20604             // extends past the left border
20605             if ( x < sl && sl > 0 && x - sl < thresh ) {
20606                 window.scrollTo(sl - scrAmt, st);
20607             }
20608         }
20609     },
20610
20611     /**
20612      * Finds the location the element should be placed if we want to move
20613      * it to where the mouse location less the click offset would place us.
20614      * @method getTargetCoord
20615      * @param {int} iPageX the X coordinate of the click
20616      * @param {int} iPageY the Y coordinate of the click
20617      * @return an object that contains the coordinates (Object.x and Object.y)
20618      * @private
20619      */
20620     getTargetCoord: function(iPageX, iPageY) {
20621
20622
20623         var x = iPageX - this.deltaX;
20624         var y = iPageY - this.deltaY;
20625
20626         if (this.constrainX) {
20627             if (x < this.minX) { x = this.minX; }
20628             if (x > this.maxX) { x = this.maxX; }
20629         }
20630
20631         if (this.constrainY) {
20632             if (y < this.minY) { y = this.minY; }
20633             if (y > this.maxY) { y = this.maxY; }
20634         }
20635
20636         x = this.getTick(x, this.xTicks);
20637         y = this.getTick(y, this.yTicks);
20638
20639
20640         return {x:x, y:y};
20641     },
20642
20643     /*
20644      * Sets up config options specific to this class. Overrides
20645      * Roo.dd.DragDrop, but all versions of this method through the
20646      * inheritance chain are called
20647      */
20648     applyConfig: function() {
20649         Roo.dd.DD.superclass.applyConfig.call(this);
20650         this.scroll = (this.config.scroll !== false);
20651     },
20652
20653     /*
20654      * Event that fires prior to the onMouseDown event.  Overrides
20655      * Roo.dd.DragDrop.
20656      */
20657     b4MouseDown: function(e) {
20658         // this.resetConstraints();
20659         this.autoOffset(e.getPageX(),
20660                             e.getPageY());
20661     },
20662
20663     /*
20664      * Event that fires prior to the onDrag event.  Overrides
20665      * Roo.dd.DragDrop.
20666      */
20667     b4Drag: function(e) {
20668         this.setDragElPos(e.getPageX(),
20669                             e.getPageY());
20670     },
20671
20672     toString: function() {
20673         return ("DD " + this.id);
20674     }
20675
20676     //////////////////////////////////////////////////////////////////////////
20677     // Debugging ygDragDrop events that can be overridden
20678     //////////////////////////////////////////////////////////////////////////
20679     /*
20680     startDrag: function(x, y) {
20681     },
20682
20683     onDrag: function(e) {
20684     },
20685
20686     onDragEnter: function(e, id) {
20687     },
20688
20689     onDragOver: function(e, id) {
20690     },
20691
20692     onDragOut: function(e, id) {
20693     },
20694
20695     onDragDrop: function(e, id) {
20696     },
20697
20698     endDrag: function(e) {
20699     }
20700
20701     */
20702
20703 });/*
20704  * Based on:
20705  * Ext JS Library 1.1.1
20706  * Copyright(c) 2006-2007, Ext JS, LLC.
20707  *
20708  * Originally Released Under LGPL - original licence link has changed is not relivant.
20709  *
20710  * Fork - LGPL
20711  * <script type="text/javascript">
20712  */
20713
20714 /**
20715  * @class Roo.dd.DDProxy
20716  * A DragDrop implementation that inserts an empty, bordered div into
20717  * the document that follows the cursor during drag operations.  At the time of
20718  * the click, the frame div is resized to the dimensions of the linked html
20719  * element, and moved to the exact location of the linked element.
20720  *
20721  * References to the "frame" element refer to the single proxy element that
20722  * was created to be dragged in place of all DDProxy elements on the
20723  * page.
20724  *
20725  * @extends Roo.dd.DD
20726  * @constructor
20727  * @param {String} id the id of the linked html element
20728  * @param {String} sGroup the group of related DragDrop objects
20729  * @param {object} config an object containing configurable attributes
20730  *                Valid properties for DDProxy in addition to those in DragDrop:
20731  *                   resizeFrame, centerFrame, dragElId
20732  */
20733 Roo.dd.DDProxy = function(id, sGroup, config) {
20734     if (id) {
20735         this.init(id, sGroup, config);
20736         this.initFrame();
20737     }
20738 };
20739
20740 /**
20741  * The default drag frame div id
20742  * @property Roo.dd.DDProxy.dragElId
20743  * @type String
20744  * @static
20745  */
20746 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20747
20748 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20749
20750     /**
20751      * By default we resize the drag frame to be the same size as the element
20752      * we want to drag (this is to get the frame effect).  We can turn it off
20753      * if we want a different behavior.
20754      * @property resizeFrame
20755      * @type boolean
20756      */
20757     resizeFrame: true,
20758
20759     /**
20760      * By default the frame is positioned exactly where the drag element is, so
20761      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
20762      * you do not have constraints on the obj is to have the drag frame centered
20763      * around the cursor.  Set centerFrame to true for this effect.
20764      * @property centerFrame
20765      * @type boolean
20766      */
20767     centerFrame: false,
20768
20769     /**
20770      * Creates the proxy element if it does not yet exist
20771      * @method createFrame
20772      */
20773     createFrame: function() {
20774         var self = this;
20775         var body = document.body;
20776
20777         if (!body || !body.firstChild) {
20778             setTimeout( function() { self.createFrame(); }, 50 );
20779             return;
20780         }
20781
20782         var div = this.getDragEl();
20783
20784         if (!div) {
20785             div    = document.createElement("div");
20786             div.id = this.dragElId;
20787             var s  = div.style;
20788
20789             s.position   = "absolute";
20790             s.visibility = "hidden";
20791             s.cursor     = "move";
20792             s.border     = "2px solid #aaa";
20793             s.zIndex     = 999;
20794
20795             // appendChild can blow up IE if invoked prior to the window load event
20796             // while rendering a table.  It is possible there are other scenarios
20797             // that would cause this to happen as well.
20798             body.insertBefore(div, body.firstChild);
20799         }
20800     },
20801
20802     /**
20803      * Initialization for the drag frame element.  Must be called in the
20804      * constructor of all subclasses
20805      * @method initFrame
20806      */
20807     initFrame: function() {
20808         this.createFrame();
20809     },
20810
20811     applyConfig: function() {
20812         Roo.dd.DDProxy.superclass.applyConfig.call(this);
20813
20814         this.resizeFrame = (this.config.resizeFrame !== false);
20815         this.centerFrame = (this.config.centerFrame);
20816         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20817     },
20818
20819     /**
20820      * Resizes the drag frame to the dimensions of the clicked object, positions
20821      * it over the object, and finally displays it
20822      * @method showFrame
20823      * @param {int} iPageX X click position
20824      * @param {int} iPageY Y click position
20825      * @private
20826      */
20827     showFrame: function(iPageX, iPageY) {
20828         var el = this.getEl();
20829         var dragEl = this.getDragEl();
20830         var s = dragEl.style;
20831
20832         this._resizeProxy();
20833
20834         if (this.centerFrame) {
20835             this.setDelta( Math.round(parseInt(s.width,  10)/2),
20836                            Math.round(parseInt(s.height, 10)/2) );
20837         }
20838
20839         this.setDragElPos(iPageX, iPageY);
20840
20841         Roo.fly(dragEl).show();
20842     },
20843
20844     /**
20845      * The proxy is automatically resized to the dimensions of the linked
20846      * element when a drag is initiated, unless resizeFrame is set to false
20847      * @method _resizeProxy
20848      * @private
20849      */
20850     _resizeProxy: function() {
20851         if (this.resizeFrame) {
20852             var el = this.getEl();
20853             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20854         }
20855     },
20856
20857     // overrides Roo.dd.DragDrop
20858     b4MouseDown: function(e) {
20859         var x = e.getPageX();
20860         var y = e.getPageY();
20861         this.autoOffset(x, y);
20862         this.setDragElPos(x, y);
20863     },
20864
20865     // overrides Roo.dd.DragDrop
20866     b4StartDrag: function(x, y) {
20867         // show the drag frame
20868         this.showFrame(x, y);
20869     },
20870
20871     // overrides Roo.dd.DragDrop
20872     b4EndDrag: function(e) {
20873         Roo.fly(this.getDragEl()).hide();
20874     },
20875
20876     // overrides Roo.dd.DragDrop
20877     // By default we try to move the element to the last location of the frame.
20878     // This is so that the default behavior mirrors that of Roo.dd.DD.
20879     endDrag: function(e) {
20880
20881         var lel = this.getEl();
20882         var del = this.getDragEl();
20883
20884         // Show the drag frame briefly so we can get its position
20885         del.style.visibility = "";
20886
20887         this.beforeMove();
20888         // Hide the linked element before the move to get around a Safari
20889         // rendering bug.
20890         lel.style.visibility = "hidden";
20891         Roo.dd.DDM.moveToEl(lel, del);
20892         del.style.visibility = "hidden";
20893         lel.style.visibility = "";
20894
20895         this.afterDrag();
20896     },
20897
20898     beforeMove : function(){
20899
20900     },
20901
20902     afterDrag : function(){
20903
20904     },
20905
20906     toString: function() {
20907         return ("DDProxy " + this.id);
20908     }
20909
20910 });
20911 /*
20912  * Based on:
20913  * Ext JS Library 1.1.1
20914  * Copyright(c) 2006-2007, Ext JS, LLC.
20915  *
20916  * Originally Released Under LGPL - original licence link has changed is not relivant.
20917  *
20918  * Fork - LGPL
20919  * <script type="text/javascript">
20920  */
20921
20922  /**
20923  * @class Roo.dd.DDTarget
20924  * A DragDrop implementation that does not move, but can be a drop
20925  * target.  You would get the same result by simply omitting implementation
20926  * for the event callbacks, but this way we reduce the processing cost of the
20927  * event listener and the callbacks.
20928  * @extends Roo.dd.DragDrop
20929  * @constructor
20930  * @param {String} id the id of the element that is a drop target
20931  * @param {String} sGroup the group of related DragDrop objects
20932  * @param {object} config an object containing configurable attributes
20933  *                 Valid properties for DDTarget in addition to those in
20934  *                 DragDrop:
20935  *                    none
20936  */
20937 Roo.dd.DDTarget = function(id, sGroup, config) {
20938     if (id) {
20939         this.initTarget(id, sGroup, config);
20940     }
20941     if (config.listeners || config.events) { 
20942        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
20943             listeners : config.listeners || {}, 
20944             events : config.events || {} 
20945         });    
20946     }
20947 };
20948
20949 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20950 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20951     toString: function() {
20952         return ("DDTarget " + this.id);
20953     }
20954 });
20955 /*
20956  * Based on:
20957  * Ext JS Library 1.1.1
20958  * Copyright(c) 2006-2007, Ext JS, LLC.
20959  *
20960  * Originally Released Under LGPL - original licence link has changed is not relivant.
20961  *
20962  * Fork - LGPL
20963  * <script type="text/javascript">
20964  */
20965  
20966
20967 /**
20968  * @class Roo.dd.ScrollManager
20969  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
20970  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
20971  * @singleton
20972  */
20973 Roo.dd.ScrollManager = function(){
20974     var ddm = Roo.dd.DragDropMgr;
20975     var els = {};
20976     var dragEl = null;
20977     var proc = {};
20978     
20979     
20980     
20981     var onStop = function(e){
20982         dragEl = null;
20983         clearProc();
20984     };
20985     
20986     var triggerRefresh = function(){
20987         if(ddm.dragCurrent){
20988              ddm.refreshCache(ddm.dragCurrent.groups);
20989         }
20990     };
20991     
20992     var doScroll = function(){
20993         if(ddm.dragCurrent){
20994             var dds = Roo.dd.ScrollManager;
20995             if(!dds.animate){
20996                 if(proc.el.scroll(proc.dir, dds.increment)){
20997                     triggerRefresh();
20998                 }
20999             }else{
21000                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21001             }
21002         }
21003     };
21004     
21005     var clearProc = function(){
21006         if(proc.id){
21007             clearInterval(proc.id);
21008         }
21009         proc.id = 0;
21010         proc.el = null;
21011         proc.dir = "";
21012     };
21013     
21014     var startProc = function(el, dir){
21015          Roo.log('scroll startproc');
21016         clearProc();
21017         proc.el = el;
21018         proc.dir = dir;
21019         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21020     };
21021     
21022     var onFire = function(e, isDrop){
21023        
21024         if(isDrop || !ddm.dragCurrent){ return; }
21025         var dds = Roo.dd.ScrollManager;
21026         if(!dragEl || dragEl != ddm.dragCurrent){
21027             dragEl = ddm.dragCurrent;
21028             // refresh regions on drag start
21029             dds.refreshCache();
21030         }
21031         
21032         var xy = Roo.lib.Event.getXY(e);
21033         var pt = new Roo.lib.Point(xy[0], xy[1]);
21034         for(var id in els){
21035             var el = els[id], r = el._region;
21036             if(r && r.contains(pt) && el.isScrollable()){
21037                 if(r.bottom - pt.y <= dds.thresh){
21038                     if(proc.el != el){
21039                         startProc(el, "down");
21040                     }
21041                     return;
21042                 }else if(r.right - pt.x <= dds.thresh){
21043                     if(proc.el != el){
21044                         startProc(el, "left");
21045                     }
21046                     return;
21047                 }else if(pt.y - r.top <= dds.thresh){
21048                     if(proc.el != el){
21049                         startProc(el, "up");
21050                     }
21051                     return;
21052                 }else if(pt.x - r.left <= dds.thresh){
21053                     if(proc.el != el){
21054                         startProc(el, "right");
21055                     }
21056                     return;
21057                 }
21058             }
21059         }
21060         clearProc();
21061     };
21062     
21063     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21064     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21065     
21066     return {
21067         /**
21068          * Registers new overflow element(s) to auto scroll
21069          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21070          */
21071         register : function(el){
21072             if(el instanceof Array){
21073                 for(var i = 0, len = el.length; i < len; i++) {
21074                         this.register(el[i]);
21075                 }
21076             }else{
21077                 el = Roo.get(el);
21078                 els[el.id] = el;
21079             }
21080             Roo.dd.ScrollManager.els = els;
21081         },
21082         
21083         /**
21084          * Unregisters overflow element(s) so they are no longer scrolled
21085          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21086          */
21087         unregister : function(el){
21088             if(el instanceof Array){
21089                 for(var i = 0, len = el.length; i < len; i++) {
21090                         this.unregister(el[i]);
21091                 }
21092             }else{
21093                 el = Roo.get(el);
21094                 delete els[el.id];
21095             }
21096         },
21097         
21098         /**
21099          * The number of pixels from the edge of a container the pointer needs to be to 
21100          * trigger scrolling (defaults to 25)
21101          * @type Number
21102          */
21103         thresh : 25,
21104         
21105         /**
21106          * The number of pixels to scroll in each scroll increment (defaults to 50)
21107          * @type Number
21108          */
21109         increment : 100,
21110         
21111         /**
21112          * The frequency of scrolls in milliseconds (defaults to 500)
21113          * @type Number
21114          */
21115         frequency : 500,
21116         
21117         /**
21118          * True to animate the scroll (defaults to true)
21119          * @type Boolean
21120          */
21121         animate: true,
21122         
21123         /**
21124          * The animation duration in seconds - 
21125          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21126          * @type Number
21127          */
21128         animDuration: .4,
21129         
21130         /**
21131          * Manually trigger a cache refresh.
21132          */
21133         refreshCache : function(){
21134             for(var id in els){
21135                 if(typeof els[id] == 'object'){ // for people extending the object prototype
21136                     els[id]._region = els[id].getRegion();
21137                 }
21138             }
21139         }
21140     };
21141 }();/*
21142  * Based on:
21143  * Ext JS Library 1.1.1
21144  * Copyright(c) 2006-2007, Ext JS, LLC.
21145  *
21146  * Originally Released Under LGPL - original licence link has changed is not relivant.
21147  *
21148  * Fork - LGPL
21149  * <script type="text/javascript">
21150  */
21151  
21152
21153 /**
21154  * @class Roo.dd.Registry
21155  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
21156  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21157  * @singleton
21158  */
21159 Roo.dd.Registry = function(){
21160     var elements = {}; 
21161     var handles = {}; 
21162     var autoIdSeed = 0;
21163
21164     var getId = function(el, autogen){
21165         if(typeof el == "string"){
21166             return el;
21167         }
21168         var id = el.id;
21169         if(!id && autogen !== false){
21170             id = "roodd-" + (++autoIdSeed);
21171             el.id = id;
21172         }
21173         return id;
21174     };
21175     
21176     return {
21177     /**
21178      * Register a drag drop element
21179      * @param {String|HTMLElement} element The id or DOM node to register
21180      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21181      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
21182      * knows how to interpret, plus there are some specific properties known to the Registry that should be
21183      * populated in the data object (if applicable):
21184      * <pre>
21185 Value      Description<br />
21186 ---------  ------------------------------------------<br />
21187 handles    Array of DOM nodes that trigger dragging<br />
21188            for the element being registered<br />
21189 isHandle   True if the element passed in triggers<br />
21190            dragging itself, else false
21191 </pre>
21192      */
21193         register : function(el, data){
21194             data = data || {};
21195             if(typeof el == "string"){
21196                 el = document.getElementById(el);
21197             }
21198             data.ddel = el;
21199             elements[getId(el)] = data;
21200             if(data.isHandle !== false){
21201                 handles[data.ddel.id] = data;
21202             }
21203             if(data.handles){
21204                 var hs = data.handles;
21205                 for(var i = 0, len = hs.length; i < len; i++){
21206                         handles[getId(hs[i])] = data;
21207                 }
21208             }
21209         },
21210
21211     /**
21212      * Unregister a drag drop element
21213      * @param {String|HTMLElement}  element The id or DOM node to unregister
21214      */
21215         unregister : function(el){
21216             var id = getId(el, false);
21217             var data = elements[id];
21218             if(data){
21219                 delete elements[id];
21220                 if(data.handles){
21221                     var hs = data.handles;
21222                     for(var i = 0, len = hs.length; i < len; i++){
21223                         delete handles[getId(hs[i], false)];
21224                     }
21225                 }
21226             }
21227         },
21228
21229     /**
21230      * Returns the handle registered for a DOM Node by id
21231      * @param {String|HTMLElement} id The DOM node or id to look up
21232      * @return {Object} handle The custom handle data
21233      */
21234         getHandle : function(id){
21235             if(typeof id != "string"){ // must be element?
21236                 id = id.id;
21237             }
21238             return handles[id];
21239         },
21240
21241     /**
21242      * Returns the handle that is registered for the DOM node that is the target of the event
21243      * @param {Event} e The event
21244      * @return {Object} handle The custom handle data
21245      */
21246         getHandleFromEvent : function(e){
21247             var t = Roo.lib.Event.getTarget(e);
21248             return t ? handles[t.id] : null;
21249         },
21250
21251     /**
21252      * Returns a custom data object that is registered for a DOM node by id
21253      * @param {String|HTMLElement} id The DOM node or id to look up
21254      * @return {Object} data The custom data
21255      */
21256         getTarget : function(id){
21257             if(typeof id != "string"){ // must be element?
21258                 id = id.id;
21259             }
21260             return elements[id];
21261         },
21262
21263     /**
21264      * Returns a custom data object that is registered for the DOM node that is the target of the event
21265      * @param {Event} e The event
21266      * @return {Object} data The custom data
21267      */
21268         getTargetFromEvent : function(e){
21269             var t = Roo.lib.Event.getTarget(e);
21270             return t ? elements[t.id] || handles[t.id] : null;
21271         }
21272     };
21273 }();/*
21274  * Based on:
21275  * Ext JS Library 1.1.1
21276  * Copyright(c) 2006-2007, Ext JS, LLC.
21277  *
21278  * Originally Released Under LGPL - original licence link has changed is not relivant.
21279  *
21280  * Fork - LGPL
21281  * <script type="text/javascript">
21282  */
21283  
21284
21285 /**
21286  * @class Roo.dd.StatusProxy
21287  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
21288  * default drag proxy used by all Roo.dd components.
21289  * @constructor
21290  * @param {Object} config
21291  */
21292 Roo.dd.StatusProxy = function(config){
21293     Roo.apply(this, config);
21294     this.id = this.id || Roo.id();
21295     this.el = new Roo.Layer({
21296         dh: {
21297             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21298                 {tag: "div", cls: "x-dd-drop-icon"},
21299                 {tag: "div", cls: "x-dd-drag-ghost"}
21300             ]
21301         }, 
21302         shadow: !config || config.shadow !== false
21303     });
21304     this.ghost = Roo.get(this.el.dom.childNodes[1]);
21305     this.dropStatus = this.dropNotAllowed;
21306 };
21307
21308 Roo.dd.StatusProxy.prototype = {
21309     /**
21310      * @cfg {String} dropAllowed
21311      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21312      */
21313     dropAllowed : "x-dd-drop-ok",
21314     /**
21315      * @cfg {String} dropNotAllowed
21316      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21317      */
21318     dropNotAllowed : "x-dd-drop-nodrop",
21319
21320     /**
21321      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21322      * over the current target element.
21323      * @param {String} cssClass The css class for the new drop status indicator image
21324      */
21325     setStatus : function(cssClass){
21326         cssClass = cssClass || this.dropNotAllowed;
21327         if(this.dropStatus != cssClass){
21328             this.el.replaceClass(this.dropStatus, cssClass);
21329             this.dropStatus = cssClass;
21330         }
21331     },
21332
21333     /**
21334      * Resets the status indicator to the default dropNotAllowed value
21335      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21336      */
21337     reset : function(clearGhost){
21338         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21339         this.dropStatus = this.dropNotAllowed;
21340         if(clearGhost){
21341             this.ghost.update("");
21342         }
21343     },
21344
21345     /**
21346      * Updates the contents of the ghost element
21347      * @param {String} html The html that will replace the current innerHTML of the ghost element
21348      */
21349     update : function(html){
21350         if(typeof html == "string"){
21351             this.ghost.update(html);
21352         }else{
21353             this.ghost.update("");
21354             html.style.margin = "0";
21355             this.ghost.dom.appendChild(html);
21356         }
21357         // ensure float = none set?? cant remember why though.
21358         var el = this.ghost.dom.firstChild;
21359                 if(el){
21360                         Roo.fly(el).setStyle('float', 'none');
21361                 }
21362     },
21363     
21364     /**
21365      * Returns the underlying proxy {@link Roo.Layer}
21366      * @return {Roo.Layer} el
21367     */
21368     getEl : function(){
21369         return this.el;
21370     },
21371
21372     /**
21373      * Returns the ghost element
21374      * @return {Roo.Element} el
21375      */
21376     getGhost : function(){
21377         return this.ghost;
21378     },
21379
21380     /**
21381      * Hides the proxy
21382      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21383      */
21384     hide : function(clear){
21385         this.el.hide();
21386         if(clear){
21387             this.reset(true);
21388         }
21389     },
21390
21391     /**
21392      * Stops the repair animation if it's currently running
21393      */
21394     stop : function(){
21395         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21396             this.anim.stop();
21397         }
21398     },
21399
21400     /**
21401      * Displays this proxy
21402      */
21403     show : function(){
21404         this.el.show();
21405     },
21406
21407     /**
21408      * Force the Layer to sync its shadow and shim positions to the element
21409      */
21410     sync : function(){
21411         this.el.sync();
21412     },
21413
21414     /**
21415      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
21416      * invalid drop operation by the item being dragged.
21417      * @param {Array} xy The XY position of the element ([x, y])
21418      * @param {Function} callback The function to call after the repair is complete
21419      * @param {Object} scope The scope in which to execute the callback
21420      */
21421     repair : function(xy, callback, scope){
21422         this.callback = callback;
21423         this.scope = scope;
21424         if(xy && this.animRepair !== false){
21425             this.el.addClass("x-dd-drag-repair");
21426             this.el.hideUnders(true);
21427             this.anim = this.el.shift({
21428                 duration: this.repairDuration || .5,
21429                 easing: 'easeOut',
21430                 xy: xy,
21431                 stopFx: true,
21432                 callback: this.afterRepair,
21433                 scope: this
21434             });
21435         }else{
21436             this.afterRepair();
21437         }
21438     },
21439
21440     // private
21441     afterRepair : function(){
21442         this.hide(true);
21443         if(typeof this.callback == "function"){
21444             this.callback.call(this.scope || this);
21445         }
21446         this.callback = null;
21447         this.scope = null;
21448     }
21449 };/*
21450  * Based on:
21451  * Ext JS Library 1.1.1
21452  * Copyright(c) 2006-2007, Ext JS, LLC.
21453  *
21454  * Originally Released Under LGPL - original licence link has changed is not relivant.
21455  *
21456  * Fork - LGPL
21457  * <script type="text/javascript">
21458  */
21459
21460 /**
21461  * @class Roo.dd.DragSource
21462  * @extends Roo.dd.DDProxy
21463  * A simple class that provides the basic implementation needed to make any element draggable.
21464  * @constructor
21465  * @param {String/HTMLElement/Element} el The container element
21466  * @param {Object} config
21467  */
21468 Roo.dd.DragSource = function(el, config){
21469     this.el = Roo.get(el);
21470     this.dragData = {};
21471     
21472     Roo.apply(this, config);
21473     
21474     if(!this.proxy){
21475         this.proxy = new Roo.dd.StatusProxy();
21476     }
21477
21478     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21479           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21480     
21481     this.dragging = false;
21482 };
21483
21484 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21485     /**
21486      * @cfg {String} dropAllowed
21487      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21488      */
21489     dropAllowed : "x-dd-drop-ok",
21490     /**
21491      * @cfg {String} dropNotAllowed
21492      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21493      */
21494     dropNotAllowed : "x-dd-drop-nodrop",
21495
21496     /**
21497      * Returns the data object associated with this drag source
21498      * @return {Object} data An object containing arbitrary data
21499      */
21500     getDragData : function(e){
21501         return this.dragData;
21502     },
21503
21504     // private
21505     onDragEnter : function(e, id){
21506         var target = Roo.dd.DragDropMgr.getDDById(id);
21507         this.cachedTarget = target;
21508         if(this.beforeDragEnter(target, e, id) !== false){
21509             if(target.isNotifyTarget){
21510                 var status = target.notifyEnter(this, e, this.dragData);
21511                 this.proxy.setStatus(status);
21512             }else{
21513                 this.proxy.setStatus(this.dropAllowed);
21514             }
21515             
21516             if(this.afterDragEnter){
21517                 /**
21518                  * An empty function by default, but provided so that you can perform a custom action
21519                  * when the dragged item enters the drop target by providing an implementation.
21520                  * @param {Roo.dd.DragDrop} target The drop target
21521                  * @param {Event} e The event object
21522                  * @param {String} id The id of the dragged element
21523                  * @method afterDragEnter
21524                  */
21525                 this.afterDragEnter(target, e, id);
21526             }
21527         }
21528     },
21529
21530     /**
21531      * An empty function by default, but provided so that you can perform a custom action
21532      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21533      * @param {Roo.dd.DragDrop} target The drop target
21534      * @param {Event} e The event object
21535      * @param {String} id The id of the dragged element
21536      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21537      */
21538     beforeDragEnter : function(target, e, id){
21539         return true;
21540     },
21541
21542     // private
21543     alignElWithMouse: function() {
21544         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21545         this.proxy.sync();
21546     },
21547
21548     // private
21549     onDragOver : function(e, id){
21550         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21551         if(this.beforeDragOver(target, e, id) !== false){
21552             if(target.isNotifyTarget){
21553                 var status = target.notifyOver(this, e, this.dragData);
21554                 this.proxy.setStatus(status);
21555             }
21556
21557             if(this.afterDragOver){
21558                 /**
21559                  * An empty function by default, but provided so that you can perform a custom action
21560                  * while the dragged item is over the drop target by providing an implementation.
21561                  * @param {Roo.dd.DragDrop} target The drop target
21562                  * @param {Event} e The event object
21563                  * @param {String} id The id of the dragged element
21564                  * @method afterDragOver
21565                  */
21566                 this.afterDragOver(target, e, id);
21567             }
21568         }
21569     },
21570
21571     /**
21572      * An empty function by default, but provided so that you can perform a custom action
21573      * while the dragged item is over the drop target and optionally cancel the onDragOver.
21574      * @param {Roo.dd.DragDrop} target The drop target
21575      * @param {Event} e The event object
21576      * @param {String} id The id of the dragged element
21577      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21578      */
21579     beforeDragOver : function(target, e, id){
21580         return true;
21581     },
21582
21583     // private
21584     onDragOut : function(e, id){
21585         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21586         if(this.beforeDragOut(target, e, id) !== false){
21587             if(target.isNotifyTarget){
21588                 target.notifyOut(this, e, this.dragData);
21589             }
21590             this.proxy.reset();
21591             if(this.afterDragOut){
21592                 /**
21593                  * An empty function by default, but provided so that you can perform a custom action
21594                  * after the dragged item is dragged out of the target without dropping.
21595                  * @param {Roo.dd.DragDrop} target The drop target
21596                  * @param {Event} e The event object
21597                  * @param {String} id The id of the dragged element
21598                  * @method afterDragOut
21599                  */
21600                 this.afterDragOut(target, e, id);
21601             }
21602         }
21603         this.cachedTarget = null;
21604     },
21605
21606     /**
21607      * An empty function by default, but provided so that you can perform a custom action before the dragged
21608      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21609      * @param {Roo.dd.DragDrop} target The drop target
21610      * @param {Event} e The event object
21611      * @param {String} id The id of the dragged element
21612      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21613      */
21614     beforeDragOut : function(target, e, id){
21615         return true;
21616     },
21617     
21618     // private
21619     onDragDrop : function(e, id){
21620         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21621         if(this.beforeDragDrop(target, e, id) !== false){
21622             if(target.isNotifyTarget){
21623                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21624                     this.onValidDrop(target, e, id);
21625                 }else{
21626                     this.onInvalidDrop(target, e, id);
21627                 }
21628             }else{
21629                 this.onValidDrop(target, e, id);
21630             }
21631             
21632             if(this.afterDragDrop){
21633                 /**
21634                  * An empty function by default, but provided so that you can perform a custom action
21635                  * after a valid drag drop has occurred by providing an implementation.
21636                  * @param {Roo.dd.DragDrop} target The drop target
21637                  * @param {Event} e The event object
21638                  * @param {String} id The id of the dropped element
21639                  * @method afterDragDrop
21640                  */
21641                 this.afterDragDrop(target, e, id);
21642             }
21643         }
21644         delete this.cachedTarget;
21645     },
21646
21647     /**
21648      * An empty function by default, but provided so that you can perform a custom action before the dragged
21649      * item is dropped onto the target and optionally cancel the onDragDrop.
21650      * @param {Roo.dd.DragDrop} target The drop target
21651      * @param {Event} e The event object
21652      * @param {String} id The id of the dragged element
21653      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21654      */
21655     beforeDragDrop : function(target, e, id){
21656         return true;
21657     },
21658
21659     // private
21660     onValidDrop : function(target, e, id){
21661         this.hideProxy();
21662         if(this.afterValidDrop){
21663             /**
21664              * An empty function by default, but provided so that you can perform a custom action
21665              * after a valid drop has occurred by providing an implementation.
21666              * @param {Object} target The target DD 
21667              * @param {Event} e The event object
21668              * @param {String} id The id of the dropped element
21669              * @method afterInvalidDrop
21670              */
21671             this.afterValidDrop(target, e, id);
21672         }
21673     },
21674
21675     // private
21676     getRepairXY : function(e, data){
21677         return this.el.getXY();  
21678     },
21679
21680     // private
21681     onInvalidDrop : function(target, e, id){
21682         this.beforeInvalidDrop(target, e, id);
21683         if(this.cachedTarget){
21684             if(this.cachedTarget.isNotifyTarget){
21685                 this.cachedTarget.notifyOut(this, e, this.dragData);
21686             }
21687             this.cacheTarget = null;
21688         }
21689         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21690
21691         if(this.afterInvalidDrop){
21692             /**
21693              * An empty function by default, but provided so that you can perform a custom action
21694              * after an invalid drop has occurred by providing an implementation.
21695              * @param {Event} e The event object
21696              * @param {String} id The id of the dropped element
21697              * @method afterInvalidDrop
21698              */
21699             this.afterInvalidDrop(e, id);
21700         }
21701     },
21702
21703     // private
21704     afterRepair : function(){
21705         if(Roo.enableFx){
21706             this.el.highlight(this.hlColor || "c3daf9");
21707         }
21708         this.dragging = false;
21709     },
21710
21711     /**
21712      * An empty function by default, but provided so that you can perform a custom action after an invalid
21713      * drop has occurred.
21714      * @param {Roo.dd.DragDrop} target The drop target
21715      * @param {Event} e The event object
21716      * @param {String} id The id of the dragged element
21717      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21718      */
21719     beforeInvalidDrop : function(target, e, id){
21720         return true;
21721     },
21722
21723     // private
21724     handleMouseDown : function(e){
21725         if(this.dragging) {
21726             return;
21727         }
21728         var data = this.getDragData(e);
21729         if(data && this.onBeforeDrag(data, e) !== false){
21730             this.dragData = data;
21731             this.proxy.stop();
21732             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21733         } 
21734     },
21735
21736     /**
21737      * An empty function by default, but provided so that you can perform a custom action before the initial
21738      * drag event begins and optionally cancel it.
21739      * @param {Object} data An object containing arbitrary data to be shared with drop targets
21740      * @param {Event} e The event object
21741      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21742      */
21743     onBeforeDrag : function(data, e){
21744         return true;
21745     },
21746
21747     /**
21748      * An empty function by default, but provided so that you can perform a custom action once the initial
21749      * drag event has begun.  The drag cannot be canceled from this function.
21750      * @param {Number} x The x position of the click on the dragged object
21751      * @param {Number} y The y position of the click on the dragged object
21752      */
21753     onStartDrag : Roo.emptyFn,
21754
21755     // private - YUI override
21756     startDrag : function(x, y){
21757         this.proxy.reset();
21758         this.dragging = true;
21759         this.proxy.update("");
21760         this.onInitDrag(x, y);
21761         this.proxy.show();
21762     },
21763
21764     // private
21765     onInitDrag : function(x, y){
21766         var clone = this.el.dom.cloneNode(true);
21767         clone.id = Roo.id(); // prevent duplicate ids
21768         this.proxy.update(clone);
21769         this.onStartDrag(x, y);
21770         return true;
21771     },
21772
21773     /**
21774      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21775      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21776      */
21777     getProxy : function(){
21778         return this.proxy;  
21779     },
21780
21781     /**
21782      * Hides the drag source's {@link Roo.dd.StatusProxy}
21783      */
21784     hideProxy : function(){
21785         this.proxy.hide();  
21786         this.proxy.reset(true);
21787         this.dragging = false;
21788     },
21789
21790     // private
21791     triggerCacheRefresh : function(){
21792         Roo.dd.DDM.refreshCache(this.groups);
21793     },
21794
21795     // private - override to prevent hiding
21796     b4EndDrag: function(e) {
21797     },
21798
21799     // private - override to prevent moving
21800     endDrag : function(e){
21801         this.onEndDrag(this.dragData, e);
21802     },
21803
21804     // private
21805     onEndDrag : function(data, e){
21806     },
21807     
21808     // private - pin to cursor
21809     autoOffset : function(x, y) {
21810         this.setDelta(-12, -20);
21811     }    
21812 });/*
21813  * Based on:
21814  * Ext JS Library 1.1.1
21815  * Copyright(c) 2006-2007, Ext JS, LLC.
21816  *
21817  * Originally Released Under LGPL - original licence link has changed is not relivant.
21818  *
21819  * Fork - LGPL
21820  * <script type="text/javascript">
21821  */
21822
21823
21824 /**
21825  * @class Roo.dd.DropTarget
21826  * @extends Roo.dd.DDTarget
21827  * A simple class that provides the basic implementation needed to make any element a drop target that can have
21828  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
21829  * @constructor
21830  * @param {String/HTMLElement/Element} el The container element
21831  * @param {Object} config
21832  */
21833 Roo.dd.DropTarget = function(el, config){
21834     this.el = Roo.get(el);
21835     
21836     var listeners = false; ;
21837     if (config && config.listeners) {
21838         listeners= config.listeners;
21839         delete config.listeners;
21840     }
21841     Roo.apply(this, config);
21842     
21843     if(this.containerScroll){
21844         Roo.dd.ScrollManager.register(this.el);
21845     }
21846     this.addEvents( {
21847          /**
21848          * @scope Roo.dd.DropTarget
21849          */
21850          
21851          /**
21852          * @event enter
21853          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21854          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
21855          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
21856          * 
21857          * IMPORTANT : it should set this.overClass and this.dropAllowed
21858          * 
21859          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21860          * @param {Event} e The event
21861          * @param {Object} data An object containing arbitrary data supplied by the drag source
21862          */
21863         "enter" : true,
21864         
21865          /**
21866          * @event over
21867          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21868          * This method will be called on every mouse movement while the drag source is over the drop target.
21869          * This default implementation simply returns the dropAllowed config value.
21870          * 
21871          * IMPORTANT : it should set this.dropAllowed
21872          * 
21873          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21874          * @param {Event} e The event
21875          * @param {Object} data An object containing arbitrary data supplied by the drag source
21876          
21877          */
21878         "over" : true,
21879         /**
21880          * @event out
21881          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21882          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
21883          * overClass (if any) from the drop element.
21884          * 
21885          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21886          * @param {Event} e The event
21887          * @param {Object} data An object containing arbitrary data supplied by the drag source
21888          */
21889          "out" : true,
21890          
21891         /**
21892          * @event drop
21893          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21894          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
21895          * implementation that does something to process the drop event and returns true so that the drag source's
21896          * repair action does not run.
21897          * 
21898          * IMPORTANT : it should set this.success
21899          * 
21900          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21901          * @param {Event} e The event
21902          * @param {Object} data An object containing arbitrary data supplied by the drag source
21903         */
21904          "drop" : true
21905     });
21906             
21907      
21908     Roo.dd.DropTarget.superclass.constructor.call(  this, 
21909         this.el.dom, 
21910         this.ddGroup || this.group,
21911         {
21912             isTarget: true,
21913             listeners : listeners || {} 
21914            
21915         
21916         }
21917     );
21918
21919 };
21920
21921 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21922     /**
21923      * @cfg {String} overClass
21924      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21925      */
21926      /**
21927      * @cfg {String} ddGroup
21928      * The drag drop group to handle drop events for
21929      */
21930      
21931     /**
21932      * @cfg {String} dropAllowed
21933      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21934      */
21935     dropAllowed : "x-dd-drop-ok",
21936     /**
21937      * @cfg {String} dropNotAllowed
21938      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21939      */
21940     dropNotAllowed : "x-dd-drop-nodrop",
21941     /**
21942      * @cfg {boolean} success
21943      * set this after drop listener.. 
21944      */
21945     success : false,
21946     /**
21947      * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21948      * if the drop point is valid for over/enter..
21949      */
21950     valid : false,
21951     // private
21952     isTarget : true,
21953
21954     // private
21955     isNotifyTarget : true,
21956     
21957     /**
21958      * @hide
21959      */
21960     notifyEnter : function(dd, e, data)
21961     {
21962         this.valid = true;
21963         this.fireEvent('enter', dd, e, data);
21964         if(this.overClass){
21965             this.el.addClass(this.overClass);
21966         }
21967         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21968             this.valid ? this.dropAllowed : this.dropNotAllowed
21969         );
21970     },
21971
21972     /**
21973      * @hide
21974      */
21975     notifyOver : function(dd, e, data)
21976     {
21977         this.valid = true;
21978         this.fireEvent('over', dd, e, data);
21979         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
21980             this.valid ? this.dropAllowed : this.dropNotAllowed
21981         );
21982     },
21983
21984     /**
21985      * @hide
21986      */
21987     notifyOut : function(dd, e, data)
21988     {
21989         this.fireEvent('out', dd, e, data);
21990         if(this.overClass){
21991             this.el.removeClass(this.overClass);
21992         }
21993     },
21994
21995     /**
21996      * @hide
21997      */
21998     notifyDrop : function(dd, e, data)
21999     {
22000         this.success = false;
22001         this.fireEvent('drop', dd, e, data);
22002         return this.success;
22003     }
22004 });/*
22005  * Based on:
22006  * Ext JS Library 1.1.1
22007  * Copyright(c) 2006-2007, Ext JS, LLC.
22008  *
22009  * Originally Released Under LGPL - original licence link has changed is not relivant.
22010  *
22011  * Fork - LGPL
22012  * <script type="text/javascript">
22013  */
22014
22015
22016 /**
22017  * @class Roo.dd.DragZone
22018  * @extends Roo.dd.DragSource
22019  * This class provides a container DD instance that proxies for multiple child node sources.<br />
22020  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22021  * @constructor
22022  * @param {String/HTMLElement/Element} el The container element
22023  * @param {Object} config
22024  */
22025 Roo.dd.DragZone = function(el, config){
22026     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22027     if(this.containerScroll){
22028         Roo.dd.ScrollManager.register(this.el);
22029     }
22030 };
22031
22032 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22033     /**
22034      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22035      * for auto scrolling during drag operations.
22036      */
22037     /**
22038      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22039      * method after a failed drop (defaults to "c3daf9" - light blue)
22040      */
22041
22042     /**
22043      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22044      * for a valid target to drag based on the mouse down. Override this method
22045      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22046      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22047      * @param {EventObject} e The mouse down event
22048      * @return {Object} The dragData
22049      */
22050     getDragData : function(e){
22051         return Roo.dd.Registry.getHandleFromEvent(e);
22052     },
22053     
22054     /**
22055      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22056      * this.dragData.ddel
22057      * @param {Number} x The x position of the click on the dragged object
22058      * @param {Number} y The y position of the click on the dragged object
22059      * @return {Boolean} true to continue the drag, false to cancel
22060      */
22061     onInitDrag : function(x, y){
22062         this.proxy.update(this.dragData.ddel.cloneNode(true));
22063         this.onStartDrag(x, y);
22064         return true;
22065     },
22066     
22067     /**
22068      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
22069      */
22070     afterRepair : function(){
22071         if(Roo.enableFx){
22072             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22073         }
22074         this.dragging = false;
22075     },
22076
22077     /**
22078      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22079      * the XY of this.dragData.ddel
22080      * @param {EventObject} e The mouse up event
22081      * @return {Array} The xy location (e.g. [100, 200])
22082      */
22083     getRepairXY : function(e){
22084         return Roo.Element.fly(this.dragData.ddel).getXY();  
22085     }
22086 });/*
22087  * Based on:
22088  * Ext JS Library 1.1.1
22089  * Copyright(c) 2006-2007, Ext JS, LLC.
22090  *
22091  * Originally Released Under LGPL - original licence link has changed is not relivant.
22092  *
22093  * Fork - LGPL
22094  * <script type="text/javascript">
22095  */
22096 /**
22097  * @class Roo.dd.DropZone
22098  * @extends Roo.dd.DropTarget
22099  * This class provides a container DD instance that proxies for multiple child node targets.<br />
22100  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22101  * @constructor
22102  * @param {String/HTMLElement/Element} el The container element
22103  * @param {Object} config
22104  */
22105 Roo.dd.DropZone = function(el, config){
22106     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22107 };
22108
22109 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22110     /**
22111      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
22112      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22113      * provide your own custom lookup.
22114      * @param {Event} e The event
22115      * @return {Object} data The custom data
22116      */
22117     getTargetFromEvent : function(e){
22118         return Roo.dd.Registry.getTargetFromEvent(e);
22119     },
22120
22121     /**
22122      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22123      * that it has registered.  This method has no default implementation and should be overridden to provide
22124      * node-specific processing if necessary.
22125      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
22126      * {@link #getTargetFromEvent} for this node)
22127      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22128      * @param {Event} e The event
22129      * @param {Object} data An object containing arbitrary data supplied by the drag source
22130      */
22131     onNodeEnter : function(n, dd, e, data){
22132         
22133     },
22134
22135     /**
22136      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22137      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
22138      * overridden to provide the proper feedback.
22139      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22140      * {@link #getTargetFromEvent} for this node)
22141      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22142      * @param {Event} e The event
22143      * @param {Object} data An object containing arbitrary data supplied by the drag source
22144      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22145      * underlying {@link Roo.dd.StatusProxy} can be updated
22146      */
22147     onNodeOver : function(n, dd, e, data){
22148         return this.dropAllowed;
22149     },
22150
22151     /**
22152      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22153      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
22154      * node-specific processing if necessary.
22155      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22156      * {@link #getTargetFromEvent} for this node)
22157      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22158      * @param {Event} e The event
22159      * @param {Object} data An object containing arbitrary data supplied by the drag source
22160      */
22161     onNodeOut : function(n, dd, e, data){
22162         
22163     },
22164
22165     /**
22166      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22167      * the drop node.  The default implementation returns false, so it should be overridden to provide the
22168      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22169      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22170      * {@link #getTargetFromEvent} for this node)
22171      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22172      * @param {Event} e The event
22173      * @param {Object} data An object containing arbitrary data supplied by the drag source
22174      * @return {Boolean} True if the drop was valid, else false
22175      */
22176     onNodeDrop : function(n, dd, e, data){
22177         return false;
22178     },
22179
22180     /**
22181      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22182      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
22183      * it should be overridden to provide the proper feedback if necessary.
22184      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22185      * @param {Event} e The event
22186      * @param {Object} data An object containing arbitrary data supplied by the drag source
22187      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22188      * underlying {@link Roo.dd.StatusProxy} can be updated
22189      */
22190     onContainerOver : function(dd, e, data){
22191         return this.dropNotAllowed;
22192     },
22193
22194     /**
22195      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22196      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
22197      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22198      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
22199      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22200      * @param {Event} e The event
22201      * @param {Object} data An object containing arbitrary data supplied by the drag source
22202      * @return {Boolean} True if the drop was valid, else false
22203      */
22204     onContainerDrop : function(dd, e, data){
22205         return false;
22206     },
22207
22208     /**
22209      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22210      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
22211      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22212      * you should override this method and provide a custom implementation.
22213      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22214      * @param {Event} e The event
22215      * @param {Object} data An object containing arbitrary data supplied by the drag source
22216      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22217      * underlying {@link Roo.dd.StatusProxy} can be updated
22218      */
22219     notifyEnter : function(dd, e, data){
22220         return this.dropNotAllowed;
22221     },
22222
22223     /**
22224      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22225      * This method will be called on every mouse movement while the drag source is over the drop zone.
22226      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22227      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22228      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22229      * registered node, it will call {@link #onContainerOver}.
22230      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22231      * @param {Event} e The event
22232      * @param {Object} data An object containing arbitrary data supplied by the drag source
22233      * @return {String} status The CSS class that communicates the drop status back to the source so that the
22234      * underlying {@link Roo.dd.StatusProxy} can be updated
22235      */
22236     notifyOver : function(dd, e, data){
22237         var n = this.getTargetFromEvent(e);
22238         if(!n){ // not over valid drop target
22239             if(this.lastOverNode){
22240                 this.onNodeOut(this.lastOverNode, dd, e, data);
22241                 this.lastOverNode = null;
22242             }
22243             return this.onContainerOver(dd, e, data);
22244         }
22245         if(this.lastOverNode != n){
22246             if(this.lastOverNode){
22247                 this.onNodeOut(this.lastOverNode, dd, e, data);
22248             }
22249             this.onNodeEnter(n, dd, e, data);
22250             this.lastOverNode = n;
22251         }
22252         return this.onNodeOver(n, dd, e, data);
22253     },
22254
22255     /**
22256      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22257      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
22258      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22259      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22260      * @param {Event} e The event
22261      * @param {Object} data An object containing arbitrary data supplied by the drag zone
22262      */
22263     notifyOut : function(dd, e, data){
22264         if(this.lastOverNode){
22265             this.onNodeOut(this.lastOverNode, dd, e, data);
22266             this.lastOverNode = null;
22267         }
22268     },
22269
22270     /**
22271      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22272      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
22273      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22274      * otherwise it will call {@link #onContainerDrop}.
22275      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22276      * @param {Event} e The event
22277      * @param {Object} data An object containing arbitrary data supplied by the drag source
22278      * @return {Boolean} True if the drop was valid, else false
22279      */
22280     notifyDrop : function(dd, e, data){
22281         if(this.lastOverNode){
22282             this.onNodeOut(this.lastOverNode, dd, e, data);
22283             this.lastOverNode = null;
22284         }
22285         var n = this.getTargetFromEvent(e);
22286         return n ?
22287             this.onNodeDrop(n, dd, e, data) :
22288             this.onContainerDrop(dd, e, data);
22289     },
22290
22291     // private
22292     triggerCacheRefresh : function(){
22293         Roo.dd.DDM.refreshCache(this.groups);
22294     }  
22295 });